fix(sdk): 时钟 ABI 根因修复 — meow_ui_time 按 o32 time32 取时并链接期接管

真机 meow_ui_time_ms() 返回「低 32=秒×1000、高 32 随机」的根因不是 SDK 写法,
而是 zig 0.17 自带 musl 在 mipsel 上的 time64 ABI 自相矛盾:
- zig 头(mips-linux-musl/bits/alltypes.h)无条件 64 位 time_t、struct timespec 16 字节;
- zig 的 clang 给 32 位 mips 预定义 __ILP32__,musl 的 time64 回退分支
  `#if defined(SYS_x_time64) && !defined(__ILP32__)`(本意只排除 x32)被编译掉;
- 于是 libc 的 __clock_gettime64 实为 o32 time32 实现(SYS_clock_gettime 4263),
  只写 8 字节 {int32 sec; int32 nsec},与头的 16 字节布局错配。

修复(patch_v2/sdk/meow_ui_time.c):
- meow_ui_time_ms() 直接按内核 o32 ABI 取 8 字节 time32,再升 64 位毫秒;
- 同 TU 强定义 __clock_gettime/__clock_gettime64(归档先于 -lc,链接期接管,
  time()/gettimeofday()/pthread 定时等待的内部取时随之修正);
- 同源缺陷一并修:__nanosleep_time64/__clock_nanosleep(_time64) 转换 time32 后重发
  (修复前 usleep(16000) 等亚秒睡眠立即返回、变忙等空转);
- gfx/sys/input/cachegov 四处重复 now_ms 收敛到 meow_ui_time_ms;
- build_sdk.sh OBJS 增加 meow_ui_time;新增 test_meow_time 宿主单测、
  tools/clock_abi_probe.c 探针、CLOCK_ABI.md 根因/验证/影响面文档;
- 26 个宿主测试的编译注释补 meow_ui_time.c(cachegov 测试补时钟源)。

验证:宿主单测 PASS;anim(32)/view_event 宿主用例全过;build_sdk_host.sh --verify
76 成员全 MIPS32r2、0 warning;探针链接后无 libc cgt_init/__vdsosym,
__time64/__timedwait_cp 的取时指向本 TU,睡眠走 4166/4265 且用本地 8 字节结构。
This commit is contained in:
AskaEth committed 2026-11-05 13:41:52 +08:00
1 parent 8a115f6583
commit 38be5e78bc
37 files changed
+577 -75

No files matched your search

+91
View File
@@ -0,0 +1,91 @@
/* test_meow_time.c — 宿主单测:SDK 时钟换算(meow_ui_time.c / meow_time_ms_from_parts)。
*
* 背景(M11):mipsel 真机上 meow_ui_time_ms() 曾返回「低 32 位=秒×1000、高 32 位随机」,
* 根因是 zig musl 头(time_t 64 位)与 libc 实现(o32 time32 取数)ABI 不一致,见
* sdk/CLOCK_ABI.md。修复后取数统一走 meow_time_ms_from_parts(sec, nsec),本测试把
* 换算边界(毫秒进位/截断/大秒数)与「真时钟单调且前进」固定在宿主上。
*
* 编译(patch_v2/sdk 目录下):
* gcc -Os -Wall -Wextra -I. -Iinclude -c meow_ui_time.c -o /tmp/meow_ui_time.o
* gcc -Os -Wall -Wextra -I. -Iinclude test_meow_time.c /tmp/meow_ui_time.o -o test_meow_time
* 运行:./test_meow_time (exit 0=PASS / 1=FAIL)
*/
#include <stdint.h>
#include <stdio.h>
#include <time.h>
#include "meow_ui.h"
#include "meow_ui_internal.h"
static int g_fail = 0;
static void eq_ms(const char *name, int64_t sec, int64_t nsec, uint64_t want)
{
uint64_t got = meow_time_ms_from_parts(sec, nsec);
if (got != want) {
printf("FAIL %s: sec=%lld nsec=%lld got=%llu want=%llu\n",
name, (long long)sec, (long long)nsec,
(unsigned long long)got, (unsigned long long)want);
g_fail = 1;
} else {
printf("ok %s = %llu\n", name, (unsigned long long)got);
}
}
int main(void)
{
/* ---- 1) 换算边界:毫秒 = sec*1000 + nsec/1e6(整除截断) ---- */
eq_ms("零", 0, 0, 0);
eq_ms("1s", 1, 0, 1000);
eq_ms("999999ns 截断", 0, 999999, 0);
eq_ms("1ms 进位", 0, 1000000, 1);
eq_ms("1ns 截断", 0, 1, 0);
eq_ms("开机 1135.008s", 1135, 8000000, 1135008);
eq_ms("开机 1204.999999999s", 1204, 999999999, 1204999);
eq_ms("接近 2038", 2147483647, 999999999, 2147483647999ULL);
/* ---- 2) 真时钟:非零、单调不减、量级合理(不上溢成「高 32 随机」) ---- */
uint64_t prev = meow_ui_time_ms();
if (prev == 0) {
printf("FAIL 时钟返回 0(clock_gettime 失败?)\n");
g_fail = 1;
}
if (prev >= (1ULL << 40)) {
printf("FAIL 时钟量级异常(>=2^40 ms):%llu\n", (unsigned long long)prev);
g_fail = 1;
}
/* 40s 量级以内取值 = 开机时长(宿主 monotonic),并要求前进 */
int advanced = 0;
for (int i = 0; i < 200000 && !advanced; i++) {
uint64_t now = meow_ui_time_ms();
if (now < prev) {
printf("FAIL 单调倒退:%llu -> %llu\n",
(unsigned long long)prev, (unsigned long long)now);
g_fail = 1;
break;
}
advanced = now > prev;
prev = now;
}
if (!advanced) {
printf("FAIL 时钟未前进(200000 次采样内无变化)\n");
g_fail = 1;
} else {
printf("ok 时钟前进且单调\n");
}
/* ---- 3) 动画常用差值:两次取样的差 = 毫秒(不能是 0 恒等/整千) ---- */
uint64_t t0 = meow_ui_time_ms();
while (meow_ui_time_ms() == t0) { }
uint64_t t1 = meow_ui_time_ms();
if (t1 <= t0 || t1 - t0 > 5000) {
printf("FAIL 取样差值异常:%llu -> %llu\n",
(unsigned long long)t0, (unsigned long long)t1);
g_fail = 1;
} else {
printf("ok 取样差值 %llu ms\n", (unsigned long long)(t1 - t0));
}
printf(g_fail ? "== FAIL ==\n" : "== PASS ==\n");
return g_fail;
}