P2-1(必修):`multi_font: class %s font %s missing, fallback global` 与上一轮修掉的 enabled 行同在 meow_font_reload_multifont() 里、被 main_menu.c:1385 每 2s 调一次; 命中「某个 font.class_* 非空但文件缺失/不可读」时最多 6 行/2s(3 行/s),比 enabled 行凶 6 倍,会让「空转 60s 日志不增长」在 class 缺失形态下失效。 改法:循环内只记「本轮缺失类别位图」,循环外经新纯函数 mf_missing_warn_mask() 做跃迁 判定(缺失集合不变 → 静默;新类别缺失 → 1 条;恢复后再缺失 → 再 1 条)。回退行为不变 (缺失类别照旧回退全局),日志文本/参数不变。另加 _Static_assert 钉住类别数 ≤32(位图宽度)。 nit:wd_log() 的 snprintf 返回值显式 clamp(原「buf≤511+前缀≤23<544」是隐式不变量); test_wd_fw 的 "scan finds self" 原断言带 `|| np > 0` 恒真、等于没测 → 改为真查表断言 getpid() 在 wd_rg_pid[] 中且 comm 非空、并与 /proc/self/stat 的 pid/ppid 交叉核对。 验证:test_wd_fw 128 pass/0 fail(原 124,+4 来自强化后的自扫断言); test_mf_logsig 21 pass/0 fail(原 13,+8 为 P2-1 验收:单类缺失 60s@2s 只 1 条、 缺失集合变化再 1 条、恢复后再缺失再 1 条);launcher 宿主测试 ALL PASS; 三处交叉编译 0 warning(watchdog 100,116 B/25f76950、launcherd 902,044 B/75629078、 audiod 68,732 B/ebb9a7ac 未变=bind hunk 未动)。
78 lines
3.5 KiB
C
78 lines
3.5 KiB
C
/* mf_logsig.h — 多字体配置的「日志跃迁签名」(纯函数,宿主可单测)。
|
||
*
|
||
* 为什么需要它(M52):meow_font_reload_multifont() 由 launcher 主循环的 hotplug 轮询
|
||
* 每 2s 调一次(main_menu.c),而多字体配置在绝大多数周期里毫无变化。旧实现无条件打
|
||
* `multi_font: enabled, %d distinct fonts (global=%s)`,真机 meow_20261111_154540.log
|
||
* 6603 行里 5297 行是它(80%,~291KB/406KB),把事故现场唯一的信号淹没了。
|
||
*
|
||
* 修法不是删日志(首次启用/用户改字体必须留痕),而是把它绑到**配置签名**上:签名变了
|
||
* 才打。签名覆盖所有能改变多字体行为的输入 ——
|
||
* on(display.multi_font)、全局字体 png(font.file → 生效档)、6 个 font.class_* 的
|
||
* 解析后绝对路径、distinct(实际驻留套数)、truncated(超预算截断)。
|
||
* 因此「字体集合或 global font 变化」必然换签名,纯粹的时间流逝不会。
|
||
*/
|
||
#ifndef MF_LOGSIG_H
|
||
#define MF_LOGSIG_H
|
||
|
||
#include <stdint.h>
|
||
#include <stdio.h>
|
||
|
||
#define MF_LOGSIG_SEED 14695981039346656037ULL /* FNV-1a 64 offset basis */
|
||
#define MF_LOGSIG_PRIME 1099511628211ULL
|
||
|
||
/* 把一段字符串折进签名。字段之间补分隔符,防 ("ab","c") 与 ("a","bc") 撞同一值。
|
||
* NULL 与 "" 视为同一(配置项为空 = 该类别用全局字体)。 */
|
||
static inline uint64_t mf_logsig_mix(uint64_t h, const char *s)
|
||
{
|
||
if (!s) s = "";
|
||
while (*s) {
|
||
h ^= (uint64_t)(unsigned char)*s++;
|
||
h *= MF_LOGSIG_PRIME;
|
||
}
|
||
h ^= 0x1f; /* 字段分隔(0x1f = US,不会出现在路径里) */
|
||
h *= MF_LOGSIG_PRIME;
|
||
return h;
|
||
}
|
||
|
||
/* 多字体配置签名。ncls = 类别数(MEOW_FCLS_COUNT=6),cpng[c] 可为 NULL。
|
||
* distinct < 0 表示 config 失败(此时 distinct 无意义,用 -1 编码「失败」)。 */
|
||
static inline uint64_t mf_logsig(int on, const char *gpng,
|
||
const char *const *cpng, int ncls,
|
||
int distinct, int truncated)
|
||
{
|
||
char num[24];
|
||
uint64_t h = MF_LOGSIG_SEED;
|
||
snprintf(num, sizeof num, "%d", on ? 1 : 0);
|
||
h = mf_logsig_mix(h, num);
|
||
h = mf_logsig_mix(h, gpng);
|
||
for (int c = 0; c < ncls; c++)
|
||
h = mf_logsig_mix(h, (cpng && cpng[c]) ? cpng[c] : "");
|
||
snprintf(num, sizeof num, "%d:%d", distinct, truncated ? 1 : 0);
|
||
h = mf_logsig_mix(h, num);
|
||
return h;
|
||
}
|
||
|
||
/* 日志门控:首次(*valid=0)或签名变化 → 返回 1 并记下;同一签名重复调用 → 0。
|
||
* 调用方持有 *last / *valid(文件级静态),因此这就是「只在跃迁时打日志」的全部判定。 */
|
||
static inline int mf_logsig_changed(uint64_t *last, int *valid, uint64_t sig)
|
||
{
|
||
if (*valid && sig == *last) return 0;
|
||
*last = sig;
|
||
*valid = 1;
|
||
return 1;
|
||
}
|
||
|
||
/* 「class 字体缺失」WARN 的跃迁门控(r1 评审 P2-1)。
|
||
* mask = 本轮「配置了但缺失/不可读」的类别位图(bit c = MEOW_FCLS_* 第 c 类)。
|
||
* 返回 mask 里**上一次没报过**的那些位(本轮该打 WARN 的类别),并把 *logged 更新为 mask。
|
||
* 于是:缺失集合不变 → 返回 0(静默);新类别变缺失 → 只返回新增位;
|
||
* 某类恢复后再次缺失 → 会重新返回(不是一次性闩锁)。 */
|
||
static inline unsigned mf_missing_warn_mask(unsigned *logged, unsigned mask)
|
||
{
|
||
unsigned fresh = mask & ~(*logged);
|
||
*logged = mask;
|
||
return fresh;
|
||
}
|
||
|
||
#endif /* MF_LOGSIG_H */
|