Files
MeowOS-SDK/sdk/test_meow_time.c
T
AskaEth a07f9752d3 SDK: 内置 mipsel o32 时钟/睡眠 ABI 修复(meow_ui_time.c)+ 宿主单测
zig 0.17 内置 musl 在 mipsel 上头声明 64 位 time_t、实现走 time32 系统调用
(__ILP32__ 守卫),导致 meow_ui_time_ms() 毫秒位恒 0、高 32 位随机,
usleep(16000) 立即返回(帧节拍/轮询变忙等空转)。主仓已验证的修复逐字节
搬入公开仓:取时按内核 o32 ABI(8 字节 {int32 sec; int32 nsec})再升 64 位,
同 TU 强定义 __clock_gettime/64 与睡眠入口,链接期接管 libc。

- meow_ui_time.c / CLOCK_ABI.md:cp 搬运,md5 与主仓一致(含原注释与依据链)
- meow_ui_gfx.c:删掉 now_ms/meow_ui_time_ms(避免与 meow_ui_time.o 重复符号),
  6 处内部调用改外部 meow_ui_time_ms;<time.h> 不再使用
- meow_ui_internal.h:补 meow_time_ms_from_parts 声明
- build_sdk.sh:OBJS 首位加 meow_ui_time,头注释写明归档须排在 -lc 之前
- test_meow_time.c:适配公开仓构建方式,加负 sec 回绕两例,输出断言数(15)
- sdk/README.md:公开说明本次修复、链接顺序要求与已知限制(2038 前有效)
- tuku/test/run_tests.sh、run_webtoon_tests.sh:$SDK 源文件清单补 meow_ui_time.c
  (宿主集成测试直接编 SDK 源,否则链接期 undefined symbol)

验证:sdk/build_sdk.sh 0 warning;宿主 test_meow_time == PASS == checks=15;
tuku 两套测试全 PASS(run_tests 462+106+325 断言、webtoon 240 断言,0 failed);
探针/ picbrowser 反汇编确认 __clock_gettime 取自本 TU(8 字节 time32 + 升位),
无 libc VDSO 前导;picbrowser 仍为 MIPS32r2 静态 ELF。
2026-11-05 20:27:26 +08:00

112 lines
4.5 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/* test_meow_time.c — 宿主单测:SDK 时钟换算(meow_ui_time.c / meow_time_ms_from_parts)。
*
* 背景(M11/M21):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),本测试把
* 换算边界(毫秒进位/截断/大秒数/负值回绕)与「真时钟单调且前进」固定在宿主上。
*
* 注意:宿主(非 mips)编译时 meow_ui_time.c 走 MEOW_TIME32_KERNEL_ABI=0 分支,即普通
* clock_gettime —— 本测试**不能**证明 mipsel o32 路径正确(那条路径只靠反汇编证据)。
*
* 编译(在 sdk/ 目录下):
* gcc -Os -Wall -Wextra -I. -Iinclude -c meow_ui_time.c -o meow_ui_time_host.o
* gcc -Os -Wall -Wextra -I. -Iinclude test_meow_time.c meow_ui_time_host.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 unsigned long g_checks = 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);
g_checks++;
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("(sec,0) 整秒", 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("跨秒 1.999999999s", 1, 999999999, 1999);
eq_ms("开机 1204.999999999s", 1204, 999999999, 1204999);
eq_ms("接近 2038", 2147483647, 999999999, 2147483647999ULL);
/* ---- 2) 负值:from_parts 只做无符号升位((uint64_t)sec*1000 按二补回绕),不钳制。
* 真正把内核 time32 的负 sec 钳成 0 的是 meow_ui_time.c 的 time32_clamp(),它只在
* mipsel 分支编译、宿主不可达;这里把 from_parts 的回绕语义钉住,防止有人悄悄把它
* 理解成「负值 = 0」而改掉换算。 ---- */
eq_ms("负 sec 回绕(-1s)", -1, 0, 0xFFFFFFFFFFFFFC18ULL);
eq_ms("负 sec+1ms 回绕", -1, 1000000, 0xFFFFFFFFFFFFFC19ULL);
/* ---- 3) 真时钟:非零、单调不减、量级合理(不上溢成「高 32 随机」) ---- */
uint64_t prev = meow_ui_time_ms();
g_checks++;
if (prev == 0) {
printf("FAIL 时钟返回 0(clock_gettime 失败?)\n");
g_fail = 1;
}
g_checks++;
if (prev >= (1ULL << 40)) {
printf("FAIL 时钟量级异常(>=2^40 ms):%llu\n", (unsigned long long)prev);
g_fail = 1;
}
/* 有界采样(避免时钟停走时测试挂死):要求单调不减且确实前进 */
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;
}
g_checks++;
if (!advanced) {
printf("FAIL 时钟未前进(200000 次采样内无变化)\n");
g_fail = 1;
} else {
printf("ok 时钟前进且单调\n");
}
/* ---- 4) 动画常用差值:两次取样的差 = 毫秒(不能是 0 恒等/整千) ---- */
uint64_t t0 = meow_ui_time_ms();
int waited = 0;
for (int i = 0; i < 200000 && !waited; i++)
waited = meow_ui_time_ms() != t0;
uint64_t t1 = meow_ui_time_ms();
g_checks++;
if (!waited || 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");
printf("checks=%lu\n", g_checks);
return g_fail;
}