threads(M6): getCurrentId, docs, and CI wiring — threading built
New thread_self=42 syscall backs runtime.Thread.getCurrentId (the calling thread's kernel task id). thread-test gains an id mode: two workers read getCurrentId and the main thread confirms all three ids are non-zero and distinct. Per-thread threadlocal TLS is deferred by design (no consumer; it would need context-switched fs.base for an unused feature), as are RwLock/WaitGroup. Marks the threading feature built (M1-M6): threading.md + docs/README.md status updated, all thread-* cases wired into qemu_test.py. Gate thread-id PASS; full suite green: 21/21 (thread-spawn/join/futex/mutex/id, aspace-refcount, + 15 guardrail cases), zig build clean, zig build test green.
This commit is contained in:
@@ -149,6 +149,8 @@ pub fn run(case: []const u8, boot_information: *const BootInformation) void {
|
||||
threadFutexTest(boot_information);
|
||||
} else if (eql(case, "thread-mutex")) {
|
||||
threadMutexTest(boot_information);
|
||||
} else if (eql(case, "thread-id")) {
|
||||
threadIdTest(boot_information);
|
||||
} else if (eql(case, "args")) {
|
||||
argsTest(boot_information);
|
||||
} else if (eql(case, "init")) {
|
||||
@@ -1646,6 +1648,47 @@ fn threadMutexTest(boot_information: *const BootInformation) void {
|
||||
result();
|
||||
}
|
||||
|
||||
/// Thread identity (docs/threading-plan.md M6): `thread-test` in id mode spawns two
|
||||
/// workers that each read `runtime.Thread.getCurrentId`; the main thread confirms all
|
||||
/// three ids are non-zero and distinct — proof each thread has its own kernel identity.
|
||||
fn threadIdTest(boot_information: *const BootInformation) void {
|
||||
log("DANOS-TEST-BEGIN: thread-id\n", .{});
|
||||
if (boot_information.initial_ramdisk_len == 0) {
|
||||
check("bootloader handed over an initial_ramdisk", false);
|
||||
result();
|
||||
return;
|
||||
}
|
||||
const image = @as([*]const u8, @ptrFromInt(boot_handoff.physicalToVirtual(boot_information.initial_ramdisk_base)))[0..boot_information.initial_ramdisk_len];
|
||||
const rd = initial_ramdisk.Reader.init(image) orelse {
|
||||
check("initial_ramdisk image is valid", false);
|
||||
result();
|
||||
return;
|
||||
};
|
||||
|
||||
var started = false;
|
||||
var i: u32 = 0;
|
||||
while (i < rd.count) : (i += 1) {
|
||||
const item = rd.entry(i) orelse continue;
|
||||
if (!eql(item.name, "thread-test")) continue;
|
||||
started = if (process.spawnProcess(item.blob, 4, &.{ "thread-test", "id" })) true else |_| false;
|
||||
break;
|
||||
}
|
||||
check("thread-test (id mode) spawned", started);
|
||||
|
||||
const ok_marker = "thread-id: ok";
|
||||
const fail_marker = "thread-id: FAIL";
|
||||
scheduler.setPriority(1);
|
||||
const deadline = architecture.millis() + 12000;
|
||||
while (architecture.millis() < deadline) {
|
||||
if (bufferHas(ok_marker) or bufferHas(fail_marker)) break;
|
||||
scheduler.yield();
|
||||
}
|
||||
scheduler.setPriority(4);
|
||||
|
||||
check("each thread has a distinct, non-zero getCurrentId", bufferHas(ok_marker) and !bufferHas(fail_marker));
|
||||
result();
|
||||
}
|
||||
|
||||
/// The full PID-1 path: the bootloader read /system/services/init off the boot volume and
|
||||
/// handed it over; load it as a user ELF and spawn it as a real ring-3 process
|
||||
/// — the same call the normal boot path makes — then confirm it beats. init
|
||||
|
||||
Reference in New Issue
Block a user