真机 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 字节结构。
95 lines
3.6 KiB
C
95 lines
3.6 KiB
C
/* clock_abi_probe.c — 时钟 ABI 最小探针(M11)。
|
||
*
|
||
* 用途:在宿主或真机上一眼看出「编译器头文件声明的 time_t 宽度」与「libc 实际写入的
|
||
* struct timespec 宽度」是否一致——这正是 meow_ui_time_ms 真机故障的根因(详见
|
||
* sdk/CLOCK_ABI.md)。做法:先把 struct timespec 整块填 0xAA,再调 clock_gettime,
|
||
* 看哪些字节被写回:
|
||
* - 正确(time64:tv_sec 8B + tv_nsec 4B):偏移 0..11 被写,8..11 不再是 0xAA;
|
||
* - 坏(libc 只做 o32 time32:只写 8B):偏移 8..11 仍是 0xAA → 退出码 2;
|
||
* - 头/库宽度相反(头 8B、库写 16B)也会在偏移检查里暴露。
|
||
*
|
||
* 构建(宿主):
|
||
* gcc -Os -Wall -Wextra tools/clock_abi_probe.c -o clock_abi_probe
|
||
* 构建(mipsel 静态,测裸 zig libc):
|
||
* ~/.tools/zig-mipsel-cc -Os -static tools/clock_abi_probe.c -o clock_abi_probe
|
||
* 构建(mipsel + SDK,测修复后的归档是否接管 clock_gettime):
|
||
* ~/.tools/zig-mipsel-cc -Os -static -DMEOW_PROBE_WITH_SDK -I. -Iinclude \
|
||
* tools/clock_abi_probe.c meow_ui.a <sysroot>/lib/libz.a -lpthread -o clock_abi_probe_sdk
|
||
*
|
||
* 运行:./clock_abi_probe
|
||
* 退出码:0=ABI 一致且时钟单调、量级合理;1=时钟值异常;2=libc 只写了 8 字节(ABI 不一致)。
|
||
*/
|
||
#include <stddef.h>
|
||
#include <stdint.h>
|
||
#include <stdio.h>
|
||
#include <string.h>
|
||
#include <time.h>
|
||
|
||
#ifdef MEOW_PROBE_WITH_SDK
|
||
#include "meow_ui.h"
|
||
#endif
|
||
|
||
#define PAD_BYTE 0xAA
|
||
|
||
static uint64_t now_ms(void)
|
||
{
|
||
struct timespec ts;
|
||
clock_gettime(CLOCK_MONOTONIC, &ts);
|
||
return (uint64_t)ts.tv_sec * 1000u + (uint64_t)ts.tv_nsec / 1000000u;
|
||
}
|
||
|
||
int main(void)
|
||
{
|
||
int rc = 0;
|
||
struct timespec ts;
|
||
unsigned char raw[sizeof(struct timespec)];
|
||
|
||
printf("sizeof(time_t)=%u sizeof(long)=%u sizeof(struct timespec)=%u\n",
|
||
(unsigned)sizeof(time_t), (unsigned)sizeof(long), (unsigned)sizeof(struct timespec));
|
||
printf("offsetof(tv_sec)=%u offsetof(tv_nsec)=%u\n",
|
||
(unsigned)offsetof(struct timespec, tv_sec), (unsigned)offsetof(struct timespec, tv_nsec));
|
||
|
||
memset(&ts, PAD_BYTE, sizeof ts);
|
||
int r = clock_gettime(CLOCK_MONOTONIC, &ts);
|
||
memcpy(raw, &ts, sizeof raw);
|
||
printf("clock_gettime ret=%d tv_sec=%lld tv_nsec=%ld\n", r, (long long)ts.tv_sec, (long)ts.tv_nsec);
|
||
printf("raw:");
|
||
for (unsigned i = 0; i < sizeof raw; i++) printf(" %02x", raw[i]);
|
||
printf("\n");
|
||
|
||
if (r != 0) {
|
||
printf("FAIL clock_gettime 失败\n");
|
||
return 1;
|
||
}
|
||
/* tv_nsec 所在 4 字节必须被 libc 写过 */
|
||
if (sizeof(struct timespec) > 8 && raw[8] == PAD_BYTE && raw[9] == PAD_BYTE &&
|
||
raw[10] == PAD_BYTE && raw[11] == PAD_BYTE) {
|
||
printf("FAIL libc 只写了 8 字节 time32(头声明 %u 字节)→ ABI 不一致\n",
|
||
(unsigned)sizeof(struct timespec));
|
||
rc = 2;
|
||
}
|
||
|
||
uint64_t a = now_ms();
|
||
uint64_t b = now_ms();
|
||
if (b < a || b - a > 5000 || b >= (1ULL << 40)) {
|
||
printf("FAIL 毫秒值异常: a=%llu b=%llu\n",
|
||
(unsigned long long)a, (unsigned long long)b);
|
||
rc = rc ? rc : 1;
|
||
} else {
|
||
printf("ok now_ms a=%llu b=%llu\n", (unsigned long long)a, (unsigned long long)b);
|
||
}
|
||
|
||
#ifdef MEOW_PROBE_WITH_SDK
|
||
uint64_t s1 = meow_ui_time_ms();
|
||
uint64_t s2 = meow_ui_time_ms();
|
||
printf("meow_ui_time_ms: %llu %llu\n", (unsigned long long)s1, (unsigned long long)s2);
|
||
if (s2 < s1 || s2 - s1 > 5000 || s2 >= (1ULL << 40) || s2 == 0) {
|
||
printf("FAIL meow_ui_time_ms 异常\n");
|
||
rc = rc ? rc : 1;
|
||
}
|
||
#endif
|
||
|
||
printf(rc ? "== FAIL (rc=%d) ==\n" : "== PASS ==\n", rc);
|
||
return rc;
|
||
}
|