From e1e1331e445046dc628d052564e955477daf32be Mon Sep 17 00:00:00 2001 From: MeowOS Date: Tue, 1 Sep 2026 10:32:15 +0800 Subject: [PATCH] =?UTF-8?q?fix(audiod):=20=E9=95=BF=E6=B5=81=E5=8D=A1?= =?UTF-8?q?=E6=AD=BB=E6=A0=B9=E6=B2=BB=20=E2=80=94=20=E9=98=B2=E5=8D=A1?= =?UTF-8?q?=E6=AD=BB=E6=8A=A4=E6=A0=8F=E5=85=A8=E9=87=8F=E8=90=BD=E5=9C=B0?= =?UTF-8?q?(AUDIOD=5FDESIGN=20=C2=A712)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 根因(级联死锁): 内核驱动 wedge(hbc3000/cs43198 时钟域族, write/PREPARE/amixer ioctl 卡死在内核) → 播放线程永不返回 → ring 填满 → IO 线程在 ring_write 无超时 cond_wait 永久睡眠 → accept 停摆(backlog 满后 CLI ECONNREFUSED) → ncm 堵 socket 写 → 全链冻结。 同效路径: popen_read_tmo 无界 waitpid 随挂死的 amixer 子进程拖死持锁线程。 修法: - ring 写有界等待(MEOW_AUDIO_RING_WAIT_MS 缺省 5s)超时丢弃+计数(dropped=), IO 永生; 等待期 sid 代际守卫(抢占中等待的旧流 PCM 不再注入新流 ring) - 全部 cond 等待 timedwait 化(播放 1s 周期自愈, g_cond 改 CLOCK_MONOTONIC); 信号处理器只置 g_stop(不再调非 async-signal-safe 的 cond_signal) - popen 收割有界: WNOHANG 300ms → SIGKILL 300ms → D 态放弃收割(泄漏换永生); 路由线程 amixer 调用不持 g_mu; QUERY 改报 g_route_cur 缓存(IO 热路径不再 popen) - ALSA 改 O_NONBLOCK + poll(POLLOUT,1s): 连续 3 次停摆判 wedge → PREPARE 自救无效即 关卡进丢弃模式(stall=), 下一路 OPEN 重开重试 - server→client 下行帧单发 write 写不全即整帧丢弃(txdrop=), 杜绝半帧错位/慢客户端堵 IO - 主线程 watchdog: IO/播放心跳 10s 静默告警; io 线程 poll 出错不退出(listener 不丢); backlog 4→8; RESUME/PAUSE 补 cond 唤醒 - SDK meow_ui_audio.c + CLI: connect 非阻塞+poll 2s, SO_SNDTIMEO/RCVTIMEO 2s (audiod 真死时 App 报错重开, 不再永久阻塞) 验证: 宿主 38/38 PASS(旧 19 回归 + 新增 T5 长流 3min 等效 31.7MB 持续灌 played==written underrun/dropped=0 喂流中 listener 探活 15/15; T6 wedge 故障注入生存 — 旧代码同款注入 挂死(90s timeout 强制 kill), 新代码 IO/accept/preempt/SIGTERM 全活; T7 慢客户端 tx 丢弃); qemu-mipsel 静态二进制 status/tone 全通(written=played=13230 underrun=0); -Wall -Wextra 0 warning(host+mipsel+SDK 双端编译)。 meow_audiod md5 86a8b6793d516c90bbd12c2997b30d8f / meow_audio c23b96490842f54324b855fd9c2467a5 (fw_content.conf 已更)。暂不部署真机(主会话统一); meow_ui.a/App 重链留主会话。 --- patch_v2/meow_audiod/meow_audio | Bin 78016 -> 79840 bytes patch_v2/meow_audiod/meow_audio.c | 24 +- patch_v2/meow_audiod/meow_audio_host | Bin 72032 -> 72168 bytes patch_v2/meow_audiod/meow_audiod | Bin 144508 -> 149468 bytes patch_v2/meow_audiod/meow_audiod.c | 307 +++++++++++++++++++----- patch_v2/meow_audiod/meow_audiod_host | Bin 75744 -> 76656 bytes patch_v2/meow_audiod/test_audiod_host | Bin 72224 -> 72520 bytes patch_v2/meow_audiod/test_audiod_host.c | 182 +++++++++++++- patch_v2/sdk/meow_ui_audio.c | 27 ++- scripts/build/fw_content.conf | 4 +- 10 files changed, 477 insertions(+), 67 deletions(-) diff --git a/patch_v2/meow_audiod/meow_audio b/patch_v2/meow_audiod/meow_audio index e809d35395049d863dcd0ab79b11596b4864e3f6..790948f713525b697e78336116cb9dec6d0a1a3e 100755 GIT binary patch delta 14302 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 CSJ-#} diff --git a/patch_v2/meow_audiod/meow_audio.c b/patch_v2/meow_audiod/meow_audio.c index 1029153..53f509d 100644 --- a/patch_v2/meow_audiod/meow_audio.c +++ b/patch_v2/meow_audiod/meow_audio.c @@ -22,6 +22,8 @@ #include #include #include +#include +#include #include #include @@ -54,15 +56,35 @@ static int read_all(int fd, uint8_t *p, size_t n) return 0; } +/* 连接 audiod:connect 非阻塞 + poll 2s 有界(对端 backlog 满/wedge 时绝不永久阻塞); + * 建连后 SO_SNDTIMEO 2s(tone 长写在 audiod 停摆时报错退出而非挂死)。 */ static int connect_sock(void) { int fd = socket(AF_UNIX, SOCK_STREAM, 0); if (fd < 0) return -1; + int fl = fcntl(fd, F_GETFL, 0); + if (fl >= 0) fcntl(fd, F_SETFL, fl | O_NONBLOCK); struct sockaddr_un a; memset(&a, 0, sizeof a); a.sun_family = AF_UNIX; snprintf(a.sun_path, sizeof a.sun_path, "%s", g_sock); - if (connect(fd, (struct sockaddr *)&a, sizeof a) < 0) { close(fd); return -1; } + int r = connect(fd, (struct sockaddr *)&a, sizeof a); + if (r < 0 && errno == EINPROGRESS) { + struct pollfd p; + p.fd = fd; p.events = POLLOUT; p.revents = 0; + if (poll(&p, 1, 2000) > 0) { + int err = 0; + socklen_t el = sizeof err; + if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &err, &el) == 0 && err != 0) { errno = err; r = -1; } + } else { + r = -1; + } + } + if (r < 0) { close(fd); return -1; } + if (fl >= 0) fcntl(fd, F_SETFL, fl); + struct timeval tv; + tv.tv_sec = 2; tv.tv_usec = 0; + setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof tv); return fd; } diff --git a/patch_v2/meow_audiod/meow_audio_host b/patch_v2/meow_audiod/meow_audio_host index f246e3fb6f372b760bd22834092fea699640fe2d..5cafc0f04aa5d54b3614a87e3e9a04ba50144cfd 100755 GIT binary patch delta 5245 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 HNXdTzUBz;N diff --git a/patch_v2/meow_audiod/meow_audiod b/patch_v2/meow_audiod/meow_audiod index b64d658fd28b637ba56a69f6bb15be16366c626e..ce77121f085f6bd2d529509d17e7ddb0fb8f45f9 100755 GIT binary patch delta 44205 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 RING_WAIT 余量) */ /* 客户端流状态 */ enum { CLS_OPEN = 0, CLS_PAUSED = 1, CLS_DRAINING = 2 }; /* DRAINING=被抢占,PCM 丢弃 */ @@ -94,12 +110,12 @@ static int g_logfd = -1; static volatile sig_atomic_t g_stop = 0; -/* ---- 共享态(g_mu 保护 + g_cond 唤醒) ---- */ +/* ---- 共享态(g_mu 保护 + g_cond 唤醒;g_cond 用 CLOCK_MONOTONIC,main 中初始化) ---- */ /* 前向声明(供 cli_free/dispatch 使用;定义见下) */ static void g_sid_reset(void); static void _audio_mark_reconfig_needed(void); static pthread_mutex_t g_mu = PTHREAD_MUTEX_INITIALIZER; -static pthread_cond_t g_cond = PTHREAD_COND_INITIALIZER; +static pthread_cond_t g_cond; struct client { int used; @@ -128,6 +144,21 @@ static uint32_t g_next_sid = 1; static uint64_t g_written_frames = 0; /* 当前流:客户端写入 ring 的帧 */ static uint64_t g_played_frames = 0; /* 当前流:播放线程写到设备的帧 */ static uint32_t g_underrun = 0; +static uint64_t g_drop_frames = 0; /* ring 满超时丢弃的帧(背压护栏,QUERY dropped=) */ +static uint32_t g_stall = 0; /* ALSA 可写 poll 超时次数(设备停摆;QUERY stall=) */ +static uint32_t g_txdrop = 0; /* server→client 下行帧丢弃(客户端不读;QUERY txdrop=) */ + +/* ring 写等待上限(env MEOW_AUDIO_RING_WAIT_MS 覆盖;测试用小值) */ +static int g_ring_wait_ms = RING_WAIT_DEFAULT; + +/* 线程心跳(watchdog 用;宽松计数,不加锁) */ +static volatile unsigned g_hb_io = 0; +static volatile unsigned g_hb_play = 0; + +/* 测试钩子(仅 env 显式开启;MEOW_AUDIO_TEST_WRITE_DELAY_MS / _WEDGE_AFTER_BYTES) */ +static int g_test_write_delay_ms = 0; +static long long g_test_wedge_after = -1; /* dev_write 累计字节≥此值后模拟设备 wedge(睡到 g_stop) */ +static uint64_t g_dev_bytes = 0; /* ring(SPSC:IO 线程写,播放线程读;g_mu + g_cond 保护) */ static uint8_t *g_ring = NULL; @@ -206,31 +237,43 @@ static int boot_mode_ok(void) } /* ---- 帧发送(仅 IO 线程用:OPEN_ACK/STATE/PREEMPTED/ACK) ---- */ -static int write_all(int fd, const uint8_t *p, size_t n) +/* 单发即丢:客户端 fd 是 O_NONBLOCK;拼装整帧一次 write(),写不全(对端不读/缓冲满) + * 就整帧丢弃并计数——绝不为慢客户端堵 IO 循环,也绝不写出半个帧让对端协议错位。 + * 丢 OPEN_ACK/ACK 的后果 = 客户端 3s 超时判流死重连(可接受);丢 PREEMPTED 由 App 侧 + * 播放停摆自检兜底。 */ +static int send_frame(int fd, uint16_t type, uint32_t req_id, const void *payload, uint32_t len) { - size_t off = 0; - while (off < n) { - ssize_t w = write(fd, p + off, n - off); - if (w < 0) { if (errno == EINTR) continue; return -1; } - if (w == 0) return -1; - off += (size_t)w; + if (len > MEOW_IPC_MAX) return -1; + uint8_t frame[MEOW_IPC_HDR_LEN + MEOW_IPC_MAX]; + uint32_t magic = MEOW_IPC_MAGIC; + uint16_t ver = MEOW_IPC_VERSION; + memcpy(frame + 0, &magic, 4); + memcpy(frame + 4, &ver, 2); + memcpy(frame + 6, &type, 2); + memcpy(frame + 8, &req_id, 4); + memcpy(frame + 12, &len, 4); + if (len && payload) memcpy(frame + MEOW_IPC_HDR_LEN, payload, len); + size_t total = MEOW_IPC_HDR_LEN + len; + ssize_t w = write(fd, frame, total); + if (w != (ssize_t)total) { + g_txdrop++; + if ((g_txdrop & 63u) == 1u) + logmsg("tx drop: fd=%d type=0x%04x len=%u wrote=%zd (total x%u, client not reading?)", + fd, (unsigned)type, (unsigned)len, w, (unsigned)g_txdrop); + return -1; } return 0; } -static int send_frame(int fd, uint16_t type, uint32_t req_id, const void *payload, uint32_t len) +/* cond 有界等待(g_cond 为 CLOCK_MONOTONIC;调用方已持 g_mu)。 */ +static void cond_wait_tmo(int ms) { - uint8_t hdr[MEOW_IPC_HDR_LEN]; - uint32_t magic = MEOW_IPC_MAGIC; - uint16_t ver = MEOW_IPC_VERSION; - memcpy(hdr + 0, &magic, 4); - memcpy(hdr + 4, &ver, 2); - memcpy(hdr + 6, &type, 2); - memcpy(hdr + 8, &req_id, 4); - memcpy(hdr + 12, &len, 4); - if (write_all(fd, hdr, sizeof hdr) != 0) return -1; - if (len && payload && write_all(fd, payload, len) != 0) return -1; - return 0; + struct timespec ts; + clock_gettime(CLOCK_MONOTONIC, &ts); + ts.tv_sec += ms / 1000; + ts.tv_nsec += (long)(ms % 1000) * 1000000L; + if (ts.tv_nsec >= 1000000000L) { ts.tv_sec++; ts.tv_nsec -= 1000000000L; } + pthread_cond_timedwait(&g_cond, &g_mu, &ts); } /* ---- frame 大小/位深 ---- */ @@ -279,22 +322,40 @@ static size_t ring_read_locked(uint8_t *dst, size_t want) return n; } -/* IO 线程写整块(调用方已持 g_mu,但可能阻塞等待空间——返回后释放由调用方负责)。 - * 返回 0=写入;-1=流已失效(被抢占/停止,丢弃)。 */ -static int ring_write_locked(const uint8_t *src, size_t want) +/* IO 线程写整块(调用方已持 g_mu)。**有界等待**:ring 满最多等 g_ring_wait_ms, + * 超时丢弃该块(返回 0)——背压绝不能退化成 IO 线程永久睡眠(真机长流卡死根因: + * 播放线程堵死 → ring 满 → IO cond_wait 永不醒 → accept 停摆 → 全链冻结)。 + * sid 为写入方开流时的代际:等待期间被抢占(g_st.sid 变化)立即丢弃(返回 0), + * 防止旧流 PCM 注入新流 ring(ring_rebuild 后错位)。 + * 返回实际写入字节数;0=被丢弃(超时/流死/被抢占)。 */ +static size_t ring_write_locked(const uint8_t *src, size_t want, uint32_t sid) { size_t fs = (size_t)frame_size(); if (fs == 0) fs = 1; size_t n = (want / fs) * fs; if (n == 0) return 0; + if (!g_ring || g_ring_cap < n) return 0; /* ring 未建/异常小:直接丢 */ + struct timespec deadline; + clock_gettime(CLOCK_MONOTONIC, &deadline); + deadline.tv_sec += g_ring_wait_ms / 1000; + deadline.tv_nsec += (long)(g_ring_wait_ms % 1000) * 1000000L; + if (deadline.tv_nsec >= 1000000000L) { deadline.tv_sec++; deadline.tv_nsec -= 1000000000L; } for (;;) { - if (g_stop) return -1; - /* 流失效:非当前授权/被抢占/暂停(PAUSE 不新增,但已缓冲保留) */ - if (!g_st.active) - return -1; + if (g_stop) return 0; + /* 流失效/代际变化:非当前授权、被抢占、被停止 → 丢弃 */ + if (!g_st.active || g_st.sid != sid) + return 0; size_t freeb = g_ring_cap - ring_bytes(); if (freeb >= n) break; - pthread_cond_wait(&g_cond, &g_mu); + int wr = pthread_cond_timedwait(&g_cond, &g_mu, &deadline); + if (wr == ETIMEDOUT) { + g_drop_frames += n / fs; + static unsigned s_droplog = 0; + if ((s_droplog++ & 63u) == 0) + logmsg("ring full >%dms: dropped %zu bytes (total dropped=%llu frames, playback stuck?)", + g_ring_wait_ms, n, (unsigned long long)g_drop_frames); + return 0; + } } size_t wpos = g_wpos; size_t first = g_ring_cap - wpos; @@ -303,7 +364,7 @@ static int ring_write_locked(const uint8_t *src, size_t want) if (take < n) memcpy(g_ring, src + take, n - take); g_wpos = (g_wpos + n) % g_ring_cap; pthread_cond_signal(&g_cond); - return 0; + return n; } /* 重建 ring(调用方已持 g_mu;按当前授权流参数算 ~200ms 容量;重建=清空旧流缓冲) */ @@ -327,6 +388,10 @@ static void ring_rebuild(void) } /* ---- amixer 封装(popen 限时;无 amixer → 优雅失败) ---- */ +/* 读子进程 stdout(非阻塞+poll 限时)。收割**必须有界**:驱动 wedge 时 amixer 可能 + * 挂在内核 ioctl 里,无条件 waitpid 会把调用线程(路由线程持 g_mu / IO 线程)一起拖死 + * ——真机长流卡死的级联路径之一。策略:先 WNOHANG 等 300ms;不死 → SIGKILL 再等 300ms; + * 仍不死(D 态)→ 放弃收割(泄漏一个子进程,换线程不卡死;已记日志)。 */ static char *popen_read_tmo(int tmo_ms, const char *cmd) { int p[2]; @@ -350,7 +415,23 @@ static char *popen_read_tmo(int tmo_ms, const char *cmd) off += (size_t)rd; } close(p[0]); - waitpid(pid, NULL, 0); + int reaped = 0; + for (int i = 0; i < 30; i++) { /* 300ms 优雅退出窗口 */ + if (waitpid(pid, NULL, WNOHANG) == pid) { reaped = 1; break; } + struct timespec ts = { 0, 10 * 1000000L }; + nanosleep(&ts, NULL); + } + if (!reaped) { + logmsg("popen: child %ld did not exit in 300ms, SIGKILL (%s)", (long)pid, cmd); + kill(pid, SIGKILL); + for (int i = 0; i < 30; i++) { + if (waitpid(pid, NULL, WNOHANG) == pid) { reaped = 1; break; } + struct timespec ts = { 0, 10 * 1000000L }; + nanosleep(&ts, NULL); + } + if (!reaped) + logmsg("popen: child %ld unkillable (D-state, driver wedged?) — abandon reap", (long)pid); + } buf[off] = 0; return buf; } @@ -411,7 +492,9 @@ static const char *port_name(int port) } } -/* 应用路由(numid=9)。port 0=idle;写后 cget 校验,失败记日志不重试风暴。 */ +/* 应用路由(numid=9)。port 0=idle;写后 cget 校验,失败记日志不重试风暴。 + * g_route_cur 为 plain int 松散写(路由线程不持 g_mu 调本函数——amixer popen 虽已有界, + * 仍不该在持锁状态执行外部命令;int 写对 MIPS32 天然原子,竞争最坏是 QUERY 读到上一拍值)。 */ static void apply_route(int port) { if (amixer_set(9, port, 1) < 0) { @@ -437,10 +520,11 @@ static int read_switch(const char *path) return atoi(buf); } -/* 路由评估(移植自 meow_route.c):4.4 优先;都不插不动;写失败不重试风暴。 */ -static void route_evaluate(int *last_hb, int *last_bal, int *last_target) +/* 路由评估(移植自 meow_route.c):4.4 优先;都不插不动;写失败不重试风暴。 + * manual:调用方快照的 g_route_manual(本函数不持 g_mu、不读全局)。 */ +static void route_evaluate(int manual, int *last_hb, int *last_bal, int *last_target) { - if (g_route_manual != -1) return; /* 手动模式:不自动切 */ + if (manual != -1) return; /* 手动模式:不自动切 */ int hb = read_switch("/sys/class/switch/headset/state"); int bal = read_switch("/sys/class/switch/balance/state"); if (hb < 0 || bal < 0) return; @@ -614,12 +698,12 @@ static int hw_probe(void) if (g_sink != SINK_ALSA) { g_hw_fmt = AUDIO_FMT_S16; g_hw_probed = 1; return 0; } if (g_hw_probed) return 0; #ifdef AUDIOD_HAVE_ALSA - int fd = open(DEV_PCM, O_RDWR); + int fd = open(DEV_PCM, O_RDWR | O_NONBLOCK); if (fd >= 0) { if (alsa_hw_params(fd, 44100, 2, SNDRV_PCM_FORMAT_S16_LE) == 0) { g_hw_fmt = AUDIO_FMT_S16; close(fd); g_hw_probed = 1; return 0; } close(fd); } - fd = open(DEV_PCM, O_RDWR); + fd = open(DEV_PCM, O_RDWR | O_NONBLOCK); if (fd >= 0) { if (alsa_hw_params(fd, 44100, 2, SNDRV_PCM_FORMAT_S32_LE) == 0) { g_hw_fmt = AUDIO_FMT_S32; close(fd); g_hw_probed = 1; return 0; } close(fd); @@ -652,6 +736,7 @@ static void wav_header(int fd, int rate, int ch, int bits, uint32_t data_len) } /* ---- 播放线程设备管理(dev_open/close/write 皆在播放线程调用) ---- */ +static void dev_close(void); /* 前向:dev_write 的 wedge 判死路径要用 */ static int dev_open(void) { @@ -659,7 +744,9 @@ static int dev_open(void) int bits = fmt_bps((int)fmt) * 8; if (g_sink == SINK_ALSA) { #ifdef AUDIOD_HAVE_ALSA - int fd = open(DEV_PCM, O_RDWR); + /* O_NONBLOCK:写路径走 poll(POLLOUT)+限时(dev_write),write 本身永不睡眠—— + * 驱动 wedge 时绝不能把播放线程永久压进内核(真机长流卡死根因防线)。 */ + int fd = open(DEV_PCM, O_RDWR | O_NONBLOCK); if (fd < 0) { logmsg("dev open %s: %s", DEV_PCM, strerror(errno)); return -1; } if (alsa_hw_params(fd, rate, ch, alsa_fmt_to_snd((int)fmt)) != 0) { logmsg("dev hw_params %u/%u/%s failed", (unsigned)rate, (unsigned)ch, fmt_name((int)fmt)); @@ -683,11 +770,29 @@ static int dev_open(void) static void dev_write(uint8_t *buf, size_t n) { + /* 测试钩子(仅 env 开启):写延迟(模拟慢设备/实时 pacing)与 wedge(模拟驱动卡死—— + * 睡到 g_stop,复现真机「播放线程永不返回」故障注入,验证 IO 线程/ring 不死锁)。 */ + if (g_test_write_delay_ms > 0) { + struct timespec ts = { g_test_write_delay_ms / 1000, (long)(g_test_write_delay_ms % 1000) * 1000000L }; + nanosleep(&ts, NULL); + } + if (g_test_wedge_after >= 0) { + if (g_dev_bytes >= (uint64_t)g_test_wedge_after) { + static int s_wedged = 0; + if (!s_wedged) { s_wedged = 1; logmsg("TEST: device wedged (simulated after %llu bytes)", (unsigned long long)g_dev_bytes); } + while (!g_stop) { + struct timespec ts = { 0, 100 * 1000000L }; + nanosleep(&ts, NULL); + } + return; + } + g_dev_bytes += n; + } if (g_sink == SINK_NULL) { g_played_frames += n / (size_t)frame_size(); return; } if (g_sink == SINK_ALSA) { #ifdef AUDIOD_HAVE_ALSA if (g_dev_fd < 0) { - /* 设备开失败(hw_params 拒/无卡):丢弃 PCM 防 ring 堵死 + 背压卡死客户端; + /* 设备开失败(hw_params 拒/无卡/wedge 后被判死):丢弃 PCM 防 ring 堵死 + 背压卡死客户端; * 日志限频(每 256 次一记),避免 write(-1) 错误风暴(真机踩过)。 */ static unsigned s_drop = 0; if ((s_drop++ % 256) == 0) @@ -695,10 +800,33 @@ static void dev_write(uint8_t *buf, size_t n) g_played_frames += n / (size_t)frame_size(); return; } + /* O_NONBLOCK + poll(POLLOUT) 模式:写前等可写(上限 ALSA_POLL_MS)。 + * 连续 ALSA_STALL_MAX 次超时 = 设备停摆(驱动 wedge 特征)→ PREPARE 自救仍无效 + * 则关卡进入丢弃模式(g_dev_open=0),下一路 OPEN 重开重试——播放线程绝不永久 + * 堵在内核 write 里(真机长流卡死的级联源头)。 */ + int stalls = 0; size_t off = 0; while (off < n) { + if (g_stop) break; + struct pollfd pf; + pf.fd = g_dev_fd; pf.events = POLLOUT; pf.revents = 0; + int pr = poll(&pf, 1, ALSA_POLL_MS); + if (pr == 0) { + g_stall++; + stalls++; + logmsg("alsa stall #%u (poll %dms no space, xrun-ish) -> PREPARE", + (unsigned)g_stall, ALSA_POLL_MS); + ioctl(g_dev_fd, SNDRV_PCM_IOCTL_PREPARE, 0); + if (stalls >= ALSA_STALL_MAX) { + logmsg("alsa WEDGED: %d consecutive stalls, close device + drop PCM until next OPEN", stalls); + dev_close(); + return; + } + continue; + } + if (pr < 0) { if (errno == EINTR) continue; logmsg("alsa poll err: %s", strerror(errno)); break; } ssize_t w = write(g_dev_fd, buf + off, n - off); - if (w > 0) { off += (size_t)w; continue; } + if (w > 0) { off += (size_t)w; stalls = 0; continue; } if (w < 0) { if (errno == EINTR || errno == EAGAIN) continue; if (errno == EPIPE) { /* xrun:重备 + 恢复(设计 §2) */ @@ -765,18 +893,21 @@ static void reconfigure_locked(void) /* 播放线程主体。 * 语义:只有当前授权流(g_st.active)喂 DAC;暂停时不读 ring(保留已缓冲); - * 停止/EOF 时不丢尾——先排空 ring 再关设备(否则 tone 末尾/缓冲尾被截断)。 */ + * 停止/EOF 时不丢尾——先排空 ring 再关设备(否则 tone 末尾/缓冲尾被截断)。 + * 所有等待为 COND_WAIT_MS 周期 timedwait:丢失唤醒最多迟 1s 自愈,SIGTERM 也能及时退。 */ static void *playback_thread(void *arg) { (void)arg; static uint8_t buf[READ_CHUNK]; for (;;) { + g_hb_play++; int have = 0; pthread_mutex_lock(&g_mu); for (;;) { + g_hb_play++; if (g_stop) { have = -1; break; } int fs = frame_size(); - if (fs <= 0) { pthread_cond_wait(&g_cond, &g_mu); continue; } /* 无流 param → 等 */ + if (fs <= 0) { cond_wait_tmo(COND_WAIT_MS); continue; } /* 无流 param → 等 */ if (g_reconfig_pending) { have = 1; break; } /* 重配 */ int draining = !g_st.active; int paused = g_st.active && g_paused; @@ -784,11 +915,11 @@ static void *playback_thread(void *arg) if ((draining && av < (size_t)fs) || paused) { /* 排空完毕(或暂停):若设备仍开且已排空 → 关;否则等待 */ if (draining && g_dev_open) dev_close(); - pthread_cond_wait(&g_cond, &g_mu); + cond_wait_tmo(COND_WAIT_MS); continue; } if (draining || av >= (size_t)fs) { have = 2; break; } /* 有数据可读(或排空态) */ - pthread_cond_wait(&g_cond, &g_mu); + cond_wait_tmo(COND_WAIT_MS); } if (have == -1) { pthread_mutex_unlock(&g_mu); break; } if (have == 1) { reconfigure_locked(); pthread_mutex_unlock(&g_mu); continue; } @@ -902,6 +1033,9 @@ static void dispatch(struct client *c, uint16_t type, uint32_t req_id, const uin g_paused = 0; g_written_frames = g_played_frames = 0; g_underrun = 0; + g_drop_frames = 0; /* 每流计数(txdrop 为全局客户端级,不随流清) */ + g_stall = 0; + g_dev_bytes = 0; /* 测试钩子计数随新流归零 */ /* 重建 ring + 标记重配 */ ring_rebuild(); _audio_mark_reconfig_needed(); @@ -919,12 +1053,10 @@ static void dispatch(struct client *c, uint16_t type, uint32_t req_id, const uin case MSG_AUDIO_WRITE: { /* 仅当前授权流、非 draining、非 paused 才入 ring;否则丢弃 */ if (g_st.active && c->sid == g_st.sid && c->state != CLS_DRAINING && !g_paused && c->state != CLS_PAUSED) { - if (g_ring) { - ring_write_locked(pl, len); - int fs = frame_size(); - if (fs > 0) - g_written_frames += len / (uint32_t)fs; - } + size_t wn = ring_write_locked(pl, len, g_st.sid); + int fs = frame_size(); + if (wn && fs > 0) + g_written_frames += wn / (uint32_t)fs; } break; } @@ -936,6 +1068,10 @@ static void dispatch(struct client *c, uint16_t type, uint32_t req_id, const uin if (sid == g_st.sid && g_st.active) { if (type == MSG_AUDIO_PAUSE) { g_paused = 1; c->state = CLS_PAUSED; logmsg("pause sid=%u", (unsigned)sid); } else if (type == MSG_AUDIO_RESUME){ g_paused = 0; c->state = CLS_OPEN; logmsg("resume sid=%u", (unsigned)sid); } + /* PAUSE/RESUME 必须唤醒播放线程(它可能正 timedwait 在 paused 分支; + * 旧代码 RESUME 不 signal,恢复后要等下一块 WRITE 才醒) */ + if (type != MSG_AUDIO_STOP) + pthread_cond_signal(&g_cond); else /* STOP */ { logmsg("STOP sid=%u (app=%s)", (unsigned)sid, g_st.app_id); g_st.active = 0; @@ -954,11 +1090,13 @@ static void dispatch(struct client *c, uint16_t type, uint32_t req_id, const uin } case MSG_AUDIO_QUERY: { char txt[1024]; - int rb = amixer_get(9, 1); + /* 路由口用缓存值 g_route_cur(路由线程维护),不在 IO 热路径 popen amixer—— + * 驱动 wedge 时 amixer 虽有界但仍会拖慢 IO 循环 1.5s/次。 */ + int rb = g_route_cur; int vol = g_vol_pct; snprintf(txt, sizeof txt, "active=%d app=%s sid=%u rate=%u ch=%u fmt=%s " - "written=%llu played=%llu underrun=%u paused=%d " + "written=%llu played=%llu underrun=%u dropped=%llu stall=%u txdrop=%u paused=%d " "route_mode=%s port=%d vol=%d\n", g_st.active ? 1 : 0, g_st.active ? g_st.app_id : "-", @@ -966,7 +1104,9 @@ static void dispatch(struct client *c, uint16_t type, uint32_t req_id, const uin g_st.active ? fmt_name((int)g_st.fmt) : "-", (unsigned long long)g_written_frames, (unsigned long long)g_played_frames, - (unsigned)g_underrun, g_paused, + (unsigned)g_underrun, + (unsigned long long)g_drop_frames, + (unsigned)g_stall, (unsigned)g_txdrop, g_paused, g_route_manual == -1 ? "auto" : "manual", (g_route_manual != -1 ? g_route_manual : rb), vol); @@ -1066,10 +1206,11 @@ static void *io_thread(void *arg) return NULL; } chmod(g_sock, 0666); - if (listen(lfd, 4) != 0) { logmsg("io: listen: %s", strerror(errno)); close(lfd); return NULL; } + if (listen(lfd, 8) != 0) { logmsg("io: listen: %s", strerror(errno)); close(lfd); return NULL; } logmsg("io thread listening on %s", g_sock); for (;;) { + g_hb_io++; if (g_stop) break; struct pollfd pfds[CLI_MAX + 1]; int n = 1; @@ -1080,7 +1221,16 @@ static void *io_thread(void *arg) n++; } int pr = poll(pfds, (nfds_t)n, 200); - if (pr < 0) { if (errno == EINTR) continue; break; } + if (pr < 0) { + if (errno == EINTR) continue; + /* poll 出错绝不退出线程(listener 一丢就是全守护失联,CLI ECONNREFUSED); + * 记日志(限频)+ 短睡后继续。 */ + static unsigned s_pollerr = 0; + if ((s_pollerr++ & 15u) == 0) logmsg("io: poll err: %s (x%u, keep going)", strerror(errno), s_pollerr); + struct timespec ts = { 0, 100 * 1000000L }; + nanosleep(&ts, NULL); + continue; + } /* pfds 是本轮新数组(revents 本轮清零),直接以 revents 为准(238 教训:每圈重建, * 杜绝陈旧 revents。勿在此清零)。 */ struct pollfd snaps[CLI_MAX + 1]; @@ -1140,8 +1290,9 @@ static void *route_thread(void *arg) } while (!g_stop) { pthread_mutex_lock(&g_mu); - route_evaluate(&last_hb, &last_bal, &last_target); + int manual = g_route_manual; /* 快照后放锁:amixer popen 不持 g_mu(防 wedge 级联) */ pthread_mutex_unlock(&g_mu); + route_evaluate(manual, &last_hb, &last_bal, &last_target); int naps = 5; /* 1000ms / 200ms 分段,即时响应 SIGTERM */ for (int k = 0; k < naps && !g_stop; k++) { struct timespec ts = { 0, 200 * 1000000L }; @@ -1154,8 +1305,10 @@ static void *route_thread(void *arg) static void on_sig(int sig) { (void)sig; + /* 只置标志(async-signal-safe):所有等待均为有界 timedwait(播放 1s / IO poll 200ms / + * 路由 200ms 分段 / ring 写 ≤g_ring_wait_ms),线程自行看到 g_stop 退出—— + * 不在信号处理器里调 pthread_cond_signal(非 async-signal-safe)。 */ g_stop = 1; - pthread_cond_signal(&g_cond); } int main(int argc, char **argv) @@ -1166,7 +1319,10 @@ int main(int argc, char **argv) if (!strcmp(argv[i], "--sock") && i + 1 < argc) snprintf(g_sock, sizeof g_sock, "%s", argv[++i]); else if (!strcmp(argv[i], "--out") && i + 1 < argc) snprintf(g_out_wav, sizeof g_out_wav, "%s", argv[++i]); else if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help")) { - printf("meow_audiod [--sock ] [--out ]\n env: MEOW_AUDIO_SOCK/MEOW_AUDIO_OUT/MEOW_AUDIO_SINK(alsa|file|null)/MEOW_AUDIO_AMIXER/MEOW_AUDIO_FORCE=1\n"); + printf("meow_audiod [--sock ] [--out ]\n" + " env: MEOW_AUDIO_SOCK/MEOW_AUDIO_OUT/MEOW_AUDIO_SINK(alsa|file|null)/MEOW_AUDIO_AMIXER/MEOW_AUDIO_FORCE=1\n" + " MEOW_AUDIO_RING_WAIT_MS (ring 满写等待上限, 缺省 5000)\n" + " MEOW_AUDIO_TEST_WRITE_DELAY_MS / MEOW_AUDIO_TEST_WEDGE_AFTER_BYTES (故障注入, 仅测试)\n"); return 0; } } @@ -1174,6 +1330,9 @@ int main(int argc, char **argv) if ((e = getenv("MEOW_AUDIO_OUT")) && e[0]) snprintf(g_out_wav, sizeof g_out_wav, "%s", e); if ((e = getenv("MEOW_AUDIO_AMIXER")) && e[0]) g_amixer = e; if ((e = getenv("MEOW_AUDIO_FORCE")) && e[0] == '1') g_force = 1; + if ((e = getenv("MEOW_AUDIO_RING_WAIT_MS")) && atoi(e) > 0) g_ring_wait_ms = atoi(e); + if ((e = getenv("MEOW_AUDIO_TEST_WRITE_DELAY_MS")) && atoi(e) > 0) g_test_write_delay_ms = atoi(e); + if ((e = getenv("MEOW_AUDIO_TEST_WEDGE_AFTER_BYTES")) && atoll(e) > 0) g_test_wedge_after = atoll(e); const char *sink = getenv("MEOW_AUDIO_SINK"); if (sink && sink[0]) { if (!strcmp(sink, "file")) g_sink = SINK_FILE; @@ -1196,19 +1355,49 @@ int main(int argc, char **argv) } log_open(); - logmsg("meow_audiod start: sock=%s sink=%d wav=%s force=%d", g_sock, g_sink, g_out_wav, g_force); + logmsg("meow_audiod start: sock=%s sink=%d wav=%s force=%d ring_wait=%dms%s%s", + g_sock, g_sink, g_out_wav, g_force, g_ring_wait_ms, + g_test_write_delay_ms > 0 ? " TEST-DELAY" : "", + g_test_wedge_after >= 0 ? " TEST-WEDGE" : ""); if (g_sink == SINK_ALSA) hw_probe(); g_vol_pct = settings_get_volume(); logmsg("volume init = %d%%", g_vol_pct); + /* g_cond 用 CLOCK_MONOTONIC(所有 timedwait 的基准;防系统时间跳变影响护栏超时) */ + { + pthread_condattr_t ca; + pthread_condattr_init(&ca); + pthread_condattr_setclock(&ca, CLOCK_MONOTONIC); + pthread_cond_init(&g_cond, &ca); + pthread_condattr_destroy(&ca); + } + pthread_t ti, tp, tr; pthread_create(&ti, NULL, io_thread, NULL); pthread_create(&tp, NULL, playback_thread, NULL); pthread_create(&tr, NULL, route_thread, NULL); + /* 主线程 = watchdog:心跳静默 >WD_SILENT_SEC 秒即告警(只告警不强杀—— + * 对卡在内核的线程任何外部干预都不安全;护栏保证其它线程/连接继续服务)。 */ + unsigned last_io = 0, last_play = 0; + int io_silent = 0, play_silent = 0; while (!g_stop) { struct timespec ts = { 1, 0 }; nanosleep(&ts, NULL); + if (g_stop) break; + unsigned io = g_hb_io, pl = g_hb_play; + io_silent = (io == last_io) ? io_silent + 1 : 0; last_io = io; + play_silent = (pl == last_play) ? play_silent + 1 : 0; last_play = pl; + if (io_silent == WD_SILENT_SEC || (io_silent > WD_SILENT_SEC && io_silent % 30 == 0)) + logmsg("WATCHDOG: io thread silent %ds (accept/read loop stuck?)", io_silent); + if (play_silent == WD_SILENT_SEC || (play_silent > WD_SILENT_SEC && play_silent % 30 == 0)) { + pthread_mutex_lock(&g_mu); + int act = g_st.active; + uint64_t wr = g_written_frames, plf = g_played_frames; + pthread_mutex_unlock(&g_mu); + logmsg("WATCHDOG: playback thread silent %ds (active=%d written=%llu played=%llu, device wedged?)", + play_silent, act, (unsigned long long)wr, (unsigned long long)plf); + } } logmsg("meow_audiod shutdown"); pthread_join(ti, NULL); diff --git a/patch_v2/meow_audiod/meow_audiod_host b/patch_v2/meow_audiod/meow_audiod_host index d1e5517f87893d0ace3c5f1b27a88f2e02767c25..47164c8889f3e64f5fabf28c25dd5a0a2b56b68b 100755 GIT binary patch literal 76656 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 literal 75744 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 X<`6ww<=ksGhr3R``mj@ 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 IkRh`F1L|`)z5oCK delta 7783 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 diff --git a/patch_v2/meow_audiod/test_audiod_host.c b/patch_v2/meow_audiod/test_audiod_host.c index 15a6508..1263e7f 100644 --- a/patch_v2/meow_audiod/test_audiod_host.c +++ b/patch_v2/meow_audiod/test_audiod_host.c @@ -18,10 +18,12 @@ #include #include #include +#include #include #include #include #include +#include #include #include #include @@ -38,17 +40,36 @@ static void check(int cond, const char *name) else { printf(" FAIL %s\n", name); g_fail++; } } -/* ---- 原始 IPC 客户端 ---- */ +/* ---- 原始 IPC 客户端(全有界:connect 非阻塞 2s + SO_SNDTIMEO 2s——回归卡死时 + * 测试 FAIL 而不是跟着挂死) ---- */ struct cli { int fd; }; static int cli_connect(struct cli *c) { c->fd = socket(AF_UNIX, SOCK_STREAM, 0); if (c->fd < 0) return -1; + int fl = fcntl(c->fd, F_GETFL, 0); + if (fl >= 0) fcntl(c->fd, F_SETFL, fl | O_NONBLOCK); struct sockaddr_un a; memset(&a, 0, sizeof a); a.sun_family = AF_UNIX; snprintf(a.sun_path, sizeof a.sun_path, "%s", TSOCK); - if (connect(c->fd, (struct sockaddr *)&a, sizeof a) < 0) { close(c->fd); return -1; } + int r = connect(c->fd, (struct sockaddr *)&a, sizeof a); + if (r < 0 && errno == EINPROGRESS) { + struct pollfd p; + p.fd = c->fd; p.events = POLLOUT; p.revents = 0; + if (poll(&p, 1, 2000) > 0) { + int err = 0; + socklen_t el = sizeof err; + if (getsockopt(c->fd, SOL_SOCKET, SO_ERROR, &err, &el) == 0 && err != 0) { errno = err; r = -1; } + } else { + r = -1; + } + } + if (r < 0) { close(c->fd); return -1; } + if (fl >= 0) fcntl(c->fd, F_SETFL, fl); + struct timeval tv; + tv.tv_sec = 2; tv.tv_usec = 0; + setsockopt(c->fd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof tv); return 0; } static int w_all(int fd, const void *p, size_t n) @@ -96,20 +117,42 @@ static void stop_audiod(void) if (g_audiod_pid > 0) { kill(g_audiod_pid, SIGTERM); waitpid(g_audiod_pid, NULL, 0); g_audiod_pid = -1; } } -static int start_audiod(void) +/* 带超时的停止:SIGTERM 后最多等 tmo_ms;不退 → SIGKILL 并返回 0(卡死回归显形)。 */ +static int stop_audiod_tmo(int tmo_ms) +{ + if (g_audiod_pid <= 0) return 1; + kill(g_audiod_pid, SIGTERM); + int ok = 0; + for (int i = 0; i < tmo_ms / 50; i++) { + if (waitpid(g_audiod_pid, NULL, WNOHANG) == g_audiod_pid) { ok = 1; break; } + usleep(50000); + } + if (!ok) { kill(g_audiod_pid, SIGKILL); waitpid(g_audiod_pid, NULL, 0); } + g_audiod_pid = -1; + return ok; +} + +static int start_audiod_ex(const char *sink, const char *wedge_after, const char *ring_wait_ms) { pid_t pid = fork(); if (pid == 0) { - setenv("MEOW_AUDIO_SINK", "file", 1); + setenv("MEOW_AUDIO_SINK", sink, 1); setenv("MEOW_AUDIO_OUT", TWAV, 1); setenv("MEOW_AUDIO_SOCK", TSOCK, 1); setenv("MEOW_AUDIO_FORCE", "1", 1); + if (wedge_after) setenv("MEOW_AUDIO_TEST_WEDGE_AFTER_BYTES", wedge_after, 1); + if (ring_wait_ms) setenv("MEOW_AUDIO_RING_WAIT_MS", ring_wait_ms, 1); execl("./meow_audiod_host", "meow_audiod_host", (char *)0); _exit(127); } return pid; } +static int start_audiod(void) +{ + return start_audiod_ex("file", NULL, NULL); +} + /* 直接客户端 open */ static int do_open(struct cli *c, int rate, int ch, int fmt, m_audio_open_ack_t *ack) { @@ -289,6 +332,65 @@ int main(void) check(strstr(q, "active=0") != NULL, "EOF recycle -> inactive"); close(c3q.fd); + /* ---- T5:长流回归(3 分钟等效 PCM 持续灌;FILE sink 全速排空 → 加速时钟等效)。 + * 回归目标:真机「长流卡死」——喂流期间 listener/IO 循环必须持续可服务, + * 帧数零丢失、零 underrun、零丢弃,STOP 后排空落盘完整。 ---- */ + printf("[T5 long stream (3min equivalent)]\n"); + struct cli l5; + check(cli_connect(&l5) == 0, "connect L5"); + m_audio_open_ack_t ackL5; + check(do_open(&l5, 44100, 2, AUDIO_FMT_S16, &ackL5) == 0 && ackL5.err == MEOW_OK, "open L5"); + uint32_t fs5 = (uint32_t)ackL5.grant_ch * (ackL5.grant_fmt == AUDIO_FMT_S16 ? 2u : 4u); + if (fs5 == 0) fs5 = 4; + uint64_t total_frames = 44100ULL * 180; /* 3 分钟等效流 */ + uint64_t total_bytes = total_frames * fs5; + uint8_t chunk[4096]; + memset(chunk, 0x5A, sizeof chunk); /* 内容无关:测完整性/不卡死 */ + size_t per = (sizeof chunk / fs5) * fs5; + uint64_t sent = 0; + int werr = 0, probe_n = 0, probe_ok = 0; + while (sent < total_bytes) { + uint64_t w = total_bytes - sent; + if (w > per) w = per; + if (do_write(&l5, chunk, (uint32_t)w) != 0) { werr = 1; break; } + sent += w; + if (sent % (512 * per) == 0) { /* 每 2MB 探一次 listener 活性 */ + struct cli s5; + s5.fd = -1; + probe_n++; + if (cli_connect(&s5) == 0) { + char q5[1024]; + if (do_query(&s5, q5, sizeof q5) == 0 && strstr(q5, "active=1")) probe_ok++; + close(s5.fd); + } + } + } + check(!werr && sent == total_bytes, "long feed completed (io never stalled)"); + printf(" fed %llu bytes (%llu frames), mid-feed status probes %d/%d alive\n", + (unsigned long long)sent, (unsigned long long)(sent / fs5), probe_ok, probe_n); + check(probe_n >= 10 && probe_ok == probe_n, "listener/io alive during long feed"); + do_ctrl(&l5, MSG_AUDIO_STOP, ackL5.stream_id); + char expect[64]; + snprintf(expect, sizeof expect, "played=%llu", (unsigned long long)total_frames); + int drained = 0; + char q5[1024]; + for (int i = 0; i < 300; i++) { /* 最多 30s 等排空 */ + if (do_query(&l5, q5, sizeof q5) == 0 && strstr(q5, expect)) { drained = 1; break; } + usleep(100000); + } + check(drained, "long stream fully played (played == fed frames)"); + if (drained) + check(strstr(q5, "underrun=0") != NULL && strstr(q5, "dropped=0") != NULL, + "no underrun/drop on long stream"); + usleep(300000); /* 等 dev_close 回填 WAV 头 */ + close(l5.fd); + { + FILE *f = fopen(TWAV, "rb"); + long sz = -1; + if (f) { fseek(f, 0, SEEK_END); sz = ftell(f); fclose(f); } + check(sz == (long)(44 + total_bytes), "long WAV size == 44 + fed bytes"); + } + /* ---- T4:tone 写 WAV(由 CLI 走完整 IPC 链路;mipsel/host CLI 共用) ---- */ printf("[T4 tone -> WAV]\n"); unlink(TWAV); @@ -305,6 +407,78 @@ int main(void) { FILE *f = fopen(TWAV, "rb"); if (f) { fseek(f, 0, SEEK_END); printf("%ld bytes\n", ftell(f)); fclose(f); } } stop_audiod(); + + /* ---- T6:设备 wedge 生存(故障注入复现真机长流卡死场景)。 + * MEOW_AUDIO_TEST_WEDGE_AFTER_BYTES=128KB → 播放线程永久堵在 dev_write(睡到 g_stop)。 + * 旧代码:ring 满 → IO 线程 ring_write cond_wait 永不醒 → accept 停摆 → 全链冻结。 + * 护栏后:ring 写有界(RING_WAIT_MS=50ms)超时丢弃,IO/accept/preempt 全部存活。 ---- */ + printf("[T6 device wedge survival]\n"); + unlink(TSOCK); + g_audiod_pid = start_audiod_ex("null", "131072", "50"); + usleep(400000); + struct cli w6; + check(cli_connect(&w6) == 0, "connect W6"); + m_audio_open_ack_t ackW6; + check(do_open(&w6, 44100, 2, AUDIO_FMT_S16, &ackW6) == 0 && ackW6.err == MEOW_OK, "open W6"); + int werr6 = 0; + uint64_t sent6 = 0; + for (int i = 0; i < 100; i++) { /* 400KB:128KB 后 wedge,其余全靠丢弃 */ + if (do_write(&w6, chunk, (uint32_t)per) != 0) { werr6 = 1; break; } + sent6 += per; + } + check(!werr6 && sent6 == 100 * (uint64_t)per, "feed continues across wedge (no deadlock)"); + struct cli s6; + s6.fd = -1; + char q6[1024]; + int io_alive = 0; + if (cli_connect(&s6) == 0) { + if (do_query(&s6, q6, sizeof q6) == 0 && strstr(q6, "route_mode=")) io_alive = 1; + close(s6.fd); + } + check(io_alive, "io loop alive after wedge (connect+query served)"); + check(io_alive && strstr(q6, "dropped=") != NULL && atoi(strstr(q6, "dropped=") + 8) > 0, + "drop policy engaged (dropped>0)"); + struct cli p6; + p6.fd = -1; + int pre6 = 0; + if (cli_connect(&p6) == 0) { + m_audio_open_ack_t ak6; + if (do_open(&p6, 48000, 2, AUDIO_FMT_S16, &ak6) == 0 && ak6.err == MEOW_OK) pre6 = 1; + close(p6.fd); + } + check(pre6, "preempt OPEN granted while wedged"); + close(w6.fd); + check(stop_audiod_tmo(5000) != 0, "wedged audiod exits on SIGTERM within 5s"); + + /* ---- T7:慢/不读客户端下行丢弃(server→client 写绝不堵 IO 循环)。 + * Z 狂发 QUERY 从不读响应 → server 下行缓冲灌满 → send_frame 单发即丢(txdrop++)。 + * 护栏断言:server 不卡死、新连接照常服务、txdrop 有计数。 ---- */ + printf("[T7 slow-client tx drop]\n"); + unlink(TSOCK); + g_audiod_pid = start_audiod_ex("null", NULL, NULL); + usleep(400000); + struct cli z7; + check(cli_connect(&z7) == 0, "connect Z7"); + int serr7 = 0, sent7 = 0; + for (int i = 0; i < 2000; i++) { + if (sf(z7.fd, MSG_AUDIO_QUERY, 9, NULL, 0) != 0) { serr7 = 1; break; } + sent7++; + } + check(!serr7 && sent7 == 2000, "query spam sent (client never reads)"); + struct cli f7; + f7.fd = -1; + char q7[1024]; + int alive7 = 0; + if (cli_connect(&f7) == 0) { + if (do_query(&f7, q7, sizeof q7) == 0 && strstr(q7, "route_mode=")) alive7 = 1; + close(f7.fd); + } + check(alive7, "server responsive after tx drops"); + check(alive7 && strstr(q7, "txdrop=") != NULL && atoi(strstr(q7, "txdrop=") + 7) > 0, + "txdrop counted"); + close(z7.fd); + stop_audiod(); + printf("=== SUMMARY: pass=%d fail=%d ===\n", g_pass, g_fail); return g_fail ? 1 : 0; } diff --git a/patch_v2/sdk/meow_ui_audio.c b/patch_v2/sdk/meow_ui_audio.c index e16afb8..eb7a008 100644 --- a/patch_v2/sdk/meow_ui_audio.c +++ b/patch_v2/sdk/meow_ui_audio.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include @@ -73,15 +74,39 @@ static const char *sock_path(void) return (e && e[0]) ? e : AUD_SOCK_DEFAULT; } +/* 连接 audiod。**全部有界**:connect 非阻塞 + poll 2s(对端 listen backlog 满/wedge 时 + * 阻塞 connect 会把 App 播放线程永久压进内核——真机长流卡死时 ncm 卡死的同款路径); + * 建连后 SO_SNDTIMEO/RCVTIMEO 2s:audiod 停摆时 write 超时返回错误 → 标记流死, + * App 走「重新 open」恢复路径,绝不永久阻塞。 */ +#define AUD_CONN_TMO_MS 2000 static int connect_path(const char *path) { int fd = socket(AF_UNIX, SOCK_STREAM, 0); if (fd < 0) return -1; + int fl = fcntl(fd, F_GETFL, 0); + if (fl >= 0) fcntl(fd, F_SETFL, fl | O_NONBLOCK); struct sockaddr_un a; memset(&a, 0, sizeof a); a.sun_family = AF_UNIX; strncpy(a.sun_path, path, sizeof a.sun_path - 1); - if (connect(fd, (struct sockaddr *)&a, sizeof a) < 0) { close(fd); return -1; } + int r = connect(fd, (struct sockaddr *)&a, sizeof a); + if (r < 0 && errno == EINPROGRESS) { + struct pollfd p; + p.fd = fd; p.events = POLLOUT; p.revents = 0; + if (poll(&p, 1, AUD_CONN_TMO_MS) > 0) { + int err = 0; + socklen_t el = sizeof err; + if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &err, &el) == 0 && err != 0) { errno = err; r = -1; } + } else { + r = -1; /* 超时/错误 */ + } + } + if (r < 0) { close(fd); return -1; } + if (fl >= 0) fcntl(fd, F_SETFL, fl); /* 回阻塞模式;读写超时由 SO_*TIMEO 兜底 */ + struct timeval tv; + tv.tv_sec = AUD_CONN_TMO_MS / 1000; tv.tv_usec = 0; + setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof tv); + setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof tv); return fd; } diff --git a/scripts/build/fw_content.conf b/scripts/build/fw_content.conf index fb9360b..38f0db1 100644 --- a/scripts/build/fw_content.conf +++ b/scripts/build/fw_content.conf @@ -38,8 +38,8 @@ patch_v2/meow_svc_power/meow_svc_power|/usr/bin/meow_svc_power|39ae3aa255695a97f patch_v2/meow_verify/meow_verify|/usr/bin/meow_verify|6c2e8ed24aebe5caf41e7aed391312d5|II期验签 2B(多公钥+v2签名块 agent-221) patch_v2/meow_crash/meow_crash|/usr/bin/meow_crash|62781084445e82351bcadbdadbe4c7fc|系统级崩溃捕获 (agent-187) patch_v2/meow_svc_perf/meow_svc_perf|/usr/bin/meow_svc_perf|7ea196de9d59ab8cbd1e26edb7762772|性能专项服务 M2.75(net_json 补 network 闭合括号,修 /api/system JSON 解析失败) -patch_v2/meow_audiod/meow_audiod|/usr/bin/meow_audiod|a6e4c2950b74a28748d7b31a9a680b31|独占音频守护 M2.91(+开机武装 hbc3000 FPGA 根治 PCM 启动死锁) -patch_v2/meow_audiod/meow_audio|/usr/bin/meow_audio|5cc3c35459409e93672448c99543dc93|audiod 用户侧 CLI(status/tone/route/vol;md5 打包时统一填 agent-244) +patch_v2/meow_audiod/meow_audiod|/usr/bin/meow_audiod|86a8b6793d516c90bbd12c2997b30d8f|独占音频守护 M2.91(+开机武装 hbc3000 FPGA 根治 PCM 启动死锁;+长流防卡死护栏 §12:ring有界写/ALSA poll自愈/popen有界收割/tx丢弃/watchdog) +patch_v2/meow_audiod/meow_audio|/usr/bin/meow_audio|c23b96490842f54324b855fd9c2467a5|audiod 用户侧 CLI(status/tone/route/vol;connect/write 全有界 2s 超时) # ---- 开机 init 脚本(etc/init.d,数字决定启动顺序,按文件名自然序)---- patch_v2/meow_sysui/S70meow_sysui|/etc/init.d/S70meow_sysui|e435affcb56499e5229728c6ae2524b9|sysui 自启 M2.85(launcher.conf enabled=1+迁移)