From ad6a79f327f6762baf9661341330c5a190c6d718 Mon Sep 17 00:00:00 2001 From: Elaine Gibson Date: Mon, 3 Aug 2026 09:59:04 +0100 Subject: [PATCH 1/3] std.c.haiku: cleanup --- lib/std/Thread.zig | 7 ++-- lib/std/c.zig | 14 ++------ lib/std/c/haiku.zig | 80 +++++++-------------------------------------- 3 files changed, 17 insertions(+), 84 deletions(-) diff --git a/lib/std/Thread.zig b/lib/std/Thread.zig index ad3fc383d9f5564d88ffec430d390f8cb75fd9bb..0cc439d07da7d8a6c0de39a65bf83800ea9b6992 100644 --- a/lib/std/Thread.zig +++ b/lib/std/Thread.zig @@ -719,10 +719,9 @@ const PosixThreadImpl = struct { }, .haiku => { var system_info: std.c.system_info = undefined; - const rc = std.c.get_system_info(&system_info); // always returns B_OK - return switch (posix.errno(rc)) { - .SUCCESS => @as(usize, @intCast(system_info.cpu_count)), - else => |err| posix.unexpectedErrno(err), + return switch (std.c.get_system_info(&system_info)) { + 0 => @as(usize, @intCast(system_info.cpu_count)), + else => error.Unexpected, }; }, else => { diff --git a/lib/std/c.zig b/lib/std/c.zig index 9f0feda6b37e4146bcebbdf26bdb97aefb4e7508..7d9a4b1d49caa7755db57477cdf9a6703ff3ecf2 100644 --- a/lib/std/c.zig +++ b/lib/std/c.zig @@ -11267,31 +11267,23 @@ pub const signalfd_siginfo = illumos.signalfd_siginfo; pub const taskid_t = illumos.taskid_t; pub const zoneid_t = illumos.zoneid_t; +pub const B_OS_NAME_LENGTH = haiku.B_OS_NAME_LENGTH; pub const DirEnt = haiku.DirEnt; -pub const _get_next_area_info = haiku._get_next_area_info; -pub const _get_next_image_info = haiku._get_next_image_info; -pub const _get_team_info = haiku._get_team_info; -pub const _kern_get_current_team = haiku._kern_get_current_team; pub const _kern_open_dir = haiku._kern_open_dir; pub const _kern_read_dir = haiku._kern_read_dir; pub const _kern_read_stat = haiku._kern_read_stat; pub const _kern_rewind_dir = haiku._kern_rewind_dir; -pub const readv_pos = haiku.readv_pos; -pub const writev_pos = haiku.writev_pos; pub const area_id = haiku.area_id; -pub const area_info = haiku.area_info; -pub const directory_which = haiku.directory_which; -pub const find_directory = haiku.find_directory; pub const find_thread = haiku.find_thread; pub const get_system_info = haiku.get_system_info; -pub const image_info = haiku.image_info; pub const port_id = haiku.port_id; +pub const readv_pos = haiku.readv_pos; pub const sem_id = haiku.sem_id; pub const status_t = haiku.status_t; pub const system_info = haiku.system_info; pub const team_id = haiku.team_id; -pub const team_info = haiku.team_info; pub const thread_id = haiku.thread_id; +pub const writev_pos = haiku.writev_pos; pub const AUTH = openbsd.AUTH; pub const BI = openbsd.BI; diff --git a/lib/std/c/haiku.zig b/lib/std/c/haiku.zig index dd599ca83735d3c470859cd5c59c73a167983e27..768935574d2912e79ea21f5bf1b4cd1f6f80b800 100644 --- a/lib/std/c/haiku.zig +++ b/lib/std/c/haiku.zig @@ -1,15 +1,8 @@ const std = @import("../std.zig"); -const assert = std.debug.assert; const builtin = @import("builtin"); -const maxInt = std.math.maxInt; -const iovec = std.posix.iovec; -const iovec_const = std.posix.iovec_const; -const socklen_t = std.c.socklen_t; +const assert = std.debug.assert; const fd_t = std.c.fd_t; const off_t = std.c.off_t; -const PATH_MAX = std.c.PATH_MAX; -const uid_t = std.c.uid_t; -const gid_t = std.c.gid_t; const dev_t = std.c.dev_t; const ino_t = std.c.ino_t; @@ -17,53 +10,21 @@ comptime { assert(builtin.os.tag == .haiku); // Prevent access of std.c symbols on wrong OS. } -pub extern "root" fn _errnop() *i32; -pub extern "root" fn find_directory(which: directory_which, volume: i32, createIt: bool, path_ptr: [*]u8, length: i32) u64; -pub extern "root" fn find_thread(thread_name: ?*anyopaque) i32; -pub extern "root" fn get_system_info(system_info: *system_info) usize; -pub extern "root" fn _get_team_info(team: i32, team_info: *team_info, size: usize) i32; -pub extern "root" fn _get_next_area_info(team: i32, cookie: *i64, area_info: *area_info, size: usize) i32; -pub extern "root" fn _get_next_image_info(team: i32, cookie: *i32, image_info: *image_info, size: usize) i32; -pub extern "root" fn _kern_get_current_team() team_id; +pub const B_OS_NAME_LENGTH = 32; + pub extern "root" fn _kern_open_dir(fd: fd_t, path: [*:0]const u8) fd_t; pub extern "root" fn _kern_read_dir(fd: fd_t, buffer: [*]u8, bufferSize: usize, maxCount: u32) isize; pub extern "root" fn _kern_rewind_dir(fd: fd_t) status_t; pub extern "root" fn _kern_read_stat(fd: fd_t, path: [*:0]const u8, traverseLink: bool, stat: *std.c.Stat, statSize: usize) status_t; + +pub extern "root" fn find_thread(name: ?[*:0]const u8) thread_id; +pub extern "root" fn get_system_info(info: *system_info) status_t; + +pub extern "root" fn _errnop() *i32; + pub extern "root" fn readv_pos(fd: fd_t, pos: off_t, vec: [*]const std.c.iovec, count: i32) isize; pub extern "root" fn writev_pos(fd: fd_t, pos: off_t, vec: [*]const std.c.iovec_const, count: i32) isize; -pub const area_info = extern struct { - area: u32, - name: [32]u8, - size: usize, - lock: u32, - protection: u32, - team_id: i32, - ram_size: u32, - copy_count: u32, - in_count: u32, - out_count: u32, - address: *anyopaque, -}; - -pub const image_info = extern struct { - id: u32, - image_type: u32, - sequence: i32, - init_order: i32, - init_routine: *anyopaque, - term_routine: *anyopaque, - device: i32, - node: i64, - name: [PATH_MAX]u8, - text: *anyopaque, - data: *anyopaque, - text_size: i32, - data_size: i32, - api_version: i32, - abi: i32, -}; - pub const system_info = extern struct { boot_time: i64, cpu_count: u32, @@ -86,31 +47,12 @@ pub const system_info = extern struct { max_teams: u32, used_teams: u32, kernel_name: [256]u8, - kernel_build_date: [32]u8, - kernel_build_time: [32]u8, + kernel_build_date: [B_OS_NAME_LENGTH]u8, + kernel_build_time: [B_OS_NAME_LENGTH]u8, kernel_version: i64, abi: u32, }; -pub const team_info = extern struct { - team_id: i32, - thread_count: i32, - image_count: i32, - area_count: i32, - debugger_nub_thread: i32, - debugger_nub_port: i32, - argc: i32, - args: [64]u8, - uid: uid_t, - gid: gid_t, -}; - -pub const directory_which = enum(i32) { - B_USER_SETTINGS_DIRECTORY = 0xbbe, - - _, -}; - pub const area_id = i32; pub const port_id = i32; pub const sem_id = i32; -- 2.54.0 From 845103fc9e9260e4aad188d029d06c61e631848f Mon Sep 17 00:00:00 2001 From: Elaine Gibson Date: Mon, 3 Aug 2026 11:52:08 +0100 Subject: [PATCH 2/3] std.Io.Threaded: implement park and unpark for haiku --- lib/std/Io/Threaded.zig | 74 ++++++++++++++++++++++++++++++++++++++--- lib/std/c.zig | 8 +++++ lib/std/c/haiku.zig | 7 ++++ 3 files changed, 84 insertions(+), 5 deletions(-) diff --git a/lib/std/Io/Threaded.zig b/lib/std/Io/Threaded.zig index c6473678a20326c606cabf29bd16e27af9ffd843..6f63dd5c9e4eaa601073addf93fe3fdfe9a5dc51 100644 --- a/lib/std/Io/Threaded.zig +++ b/lib/std/Io/Threaded.zig @@ -829,6 +829,7 @@ const Thread = struct { /// Always released when `Status.cancelation` is set to `.parked`. futex_waiter: if (use_parking_futex) ?*parking_futex.Waiter else ?noreturn, unpark_flag: UnparkFlag, + park_tid: if (ParkTid == std.Thread.Id) void else ParkTid, csprng: Csprng, @@ -1220,7 +1221,7 @@ const Thread = struct { parking_futex.removeCanceledWaiter(futex_waiter); } if (need_unpark_flag) setUnparkFlag(&thread.unpark_flag); - unpark(&.{thread.id}, null); + unpark(&.{if (ParkTid == std.Thread.Id) thread.id else thread.park_tid}, null); return false; }, @@ -1749,6 +1750,7 @@ fn worker(t: *Threaded) void { .cancel_protection = .unblocked, .futex_waiter = undefined, .unpark_flag = unpark_flag_init, + .park_tid = if (ParkTid == std.Thread.Id) {} else getParkTid(), .csprng = .uninitialized, }; Thread.current = &thread; @@ -17430,6 +17432,7 @@ const use_parking_futex = switch (native_os) { .windows => true, // RtlWaitOnAddress is a userland implementation anyway .netbsd => true, // NetBSD has `futex(2)`, but it's historically been quite buggy. TODO: evaluate whether it's okay to use now. .illumos => true, // Illumos has no futex mechanism + .haiku => true, // Haiku has no futex mechanism else => false, }; const use_parking_sleep = switch (native_os) { @@ -17475,7 +17478,7 @@ const parking_futex = struct { const Waiter = struct { node: std.DoublyLinkedList.Node, address: usize, - tid: std.Thread.Id, + tid: ParkTid, /// `thread_status.cancelation` is `.parked` while the thread is waiting. The single thread /// which atomically updates it (to `.none` or `.canceling`) is responsible for: /// @@ -17516,7 +17519,7 @@ const parking_futex = struct { // Put the threadlocal access outside of the critical section. const opt_thread = Thread.current; - const self_tid = if (opt_thread) |thread| thread.id else std.Thread.getCurrentId(); + const self_tid = getParkTid(); var waiter: Waiter = .{ .node = undefined, // populated by list append @@ -17764,7 +17767,12 @@ const parking_sleep = struct { }, } } + // Uncancelable sleep; we expect not to be manually unparked. + + // On systems where parking the thread requires a one-time setup operation (e.g. creating a + // semaphore), we need to ensure that setup is done before we call `park`. + _ = getParkTid(); var dummy_flag: UnparkFlag = unpark_flag_init; if (park(timeout, null, if (need_unpark_flag) &dummy_flag)) { unreachable; // unexpected unpark @@ -17803,7 +17811,7 @@ const ParkingMutex = struct { /// Never modified once the `Waiter` is in the linked list. next: ?*Waiter, /// Never modified once the `Waiter` is in the linked list. - tid: std.Thread.Id, + tid: ParkTid, }; fn lock(m: *ParkingMutex) void { state: switch (State.unlocked) { // assume 'unlocked' to optimize for uncontended case @@ -17819,7 +17827,7 @@ const ParkingMutex = struct { .locked_once, _ => |last_state| { const old_waiter = last_state.waiter(); - const self_tid = if (Thread.current) |t| t.id else std.Thread.getCurrentId(); + const self_tid = getParkTid(); var waiter: Waiter = .{ .next = old_waiter, .unpark_flag = unpark_flag_init, @@ -17947,9 +17955,36 @@ fn setUnparkFlag(f: *UnparkFlag) void { /// but it seems that someone at Microsoft forgot how big their TIDs are supposed to be. const UnparkTid = switch (native_os) { .windows => usize, + else => ParkTid, +}; + +const ParkTid = switch (native_os) { + .haiku => std.c.sem_id, else => std.Thread.Id, }; +threadlocal var park_sem: std.c.sem_id = -1; + +fn getParkTid() ParkTid { + switch (native_os) { + .haiku => { + if (park_sem == -1) { + park_sem = std.c._kern_create_sem(0, null); + if (park_sem < 0) @panic("_kern_create_sem failed"); + _ = std.c.on_exit_thread(destroyParkSem, null); + } + return park_sem; + }, + else => { + return if (Thread.current) |thread| thread.id else std.Thread.getCurrentId(); + }, + } +} + +fn destroyParkSem(_: ?*anyopaque) callconv(.c) void { + _ = std.c._kern_delete_sem(park_sem); +} + fn park( timeout: Io.Timeout, /// This value has no semantic effect, but may allow the OS to optimize the operation. @@ -18015,6 +18050,27 @@ fn park( } }, .illumos => @panic("TODO: illumos lwp_park"), + .haiku => { + const timeout_flags: u32, const timeout_us = switch (timeout) { + .none => .{ 0, 0 }, + .deadline => |deadline| .{ + if (deadline.clock == .real) std.c.B_ABSOLUTE_TIMEOUT | std.c.B_TIMEOUT_REAL_TIME_BASE else std.c.B_ABSOLUTE_TIMEOUT, + deadline.raw.toMicroseconds(), + }, + .duration => |duration| .{ + if (duration.clock == .real) std.c.B_ABSOLUTE_TIMEOUT | std.c.B_TIMEOUT_REAL_TIME_BASE else std.c.B_ABSOLUTE_TIMEOUT, + nowPosix(duration.clock).addDuration(duration.raw).toMicroseconds(), + }, + }; + while (true) { + switch (std.c._kern_acquire_sem_etc(park_sem, 1, timeout_flags, timeout_us)) { + 0 => return, + std.c.E.B_TIMED_OUT => return error.Timeout, + std.c.E.B_INTERRUPTED => {}, + else => unreachable, + } + } + }, else => comptime unreachable, } } @@ -18057,6 +18113,14 @@ fn unpark(tids: []const UnparkTid, addr_hint: ?*const anyopaque) void { } }, .illumos => @panic("TODO: illumos lwp_unpark"), + .haiku => { + for (tids) |tid| { + switch (std.c._kern_release_sem_etc(tid, 1, 0)) { + 0 => {}, + else => recoverableOsBugDetected(), + } + } + }, else => comptime unreachable, } } diff --git a/lib/std/c.zig b/lib/std/c.zig index 7d9a4b1d49caa7755db57477cdf9a6703ff3ecf2..a586082ec6e0318f54f80beaa3e2e49bf4bc0c5d 100644 --- a/lib/std/c.zig +++ b/lib/std/c.zig @@ -2991,6 +2991,7 @@ pub const SIG = switch (native_os) { pub const UNBLOCK = 2; pub const SETMASK = 3; + pub const IO: SIG = .POLL; pub const IOT: SIG = .ABRT; HUP = 1, @@ -11267,15 +11268,22 @@ pub const signalfd_siginfo = illumos.signalfd_siginfo; pub const taskid_t = illumos.taskid_t; pub const zoneid_t = illumos.zoneid_t; +pub const B_ABSOLUTE_TIMEOUT = haiku.B_ABSOLUTE_TIMEOUT; pub const B_OS_NAME_LENGTH = haiku.B_OS_NAME_LENGTH; +pub const B_TIMEOUT_REAL_TIME_BASE = haiku.B_TIMEOUT_REAL_TIME_BASE; pub const DirEnt = haiku.DirEnt; +pub const _kern_acquire_sem_etc = haiku._kern_acquire_sem_etc; +pub const _kern_create_sem = haiku._kern_create_sem; +pub const _kern_delete_sem = haiku._kern_delete_sem; pub const _kern_open_dir = haiku._kern_open_dir; pub const _kern_read_dir = haiku._kern_read_dir; pub const _kern_read_stat = haiku._kern_read_stat; +pub const _kern_release_sem_etc = haiku._kern_release_sem_etc; pub const _kern_rewind_dir = haiku._kern_rewind_dir; pub const area_id = haiku.area_id; pub const find_thread = haiku.find_thread; pub const get_system_info = haiku.get_system_info; +pub const on_exit_thread = haiku.on_exit_thread; pub const port_id = haiku.port_id; pub const readv_pos = haiku.readv_pos; pub const sem_id = haiku.sem_id; diff --git a/lib/std/c/haiku.zig b/lib/std/c/haiku.zig index 768935574d2912e79ea21f5bf1b4cd1f6f80b800..dd8bb8abf621324ba3ff2c9765f17524e30624c6 100644 --- a/lib/std/c/haiku.zig +++ b/lib/std/c/haiku.zig @@ -11,12 +11,19 @@ comptime { } pub const B_OS_NAME_LENGTH = 32; +pub const B_ABSOLUTE_TIMEOUT = 0x10; +pub const B_TIMEOUT_REAL_TIME_BASE = 0x40; +pub extern "root" fn _kern_create_sem(count: c_int, name: ?[*:0]const u8) sem_id; +pub extern "root" fn _kern_delete_sem(id: sem_id) status_t; +pub extern "root" fn _kern_acquire_sem_etc(id: sem_id, count: u32, flags: u32, timeout: i64) status_t; +pub extern "root" fn _kern_release_sem_etc(id: sem_id, count: u32, flags: u32) status_t; pub extern "root" fn _kern_open_dir(fd: fd_t, path: [*:0]const u8) fd_t; pub extern "root" fn _kern_read_dir(fd: fd_t, buffer: [*]u8, bufferSize: usize, maxCount: u32) isize; pub extern "root" fn _kern_rewind_dir(fd: fd_t) status_t; pub extern "root" fn _kern_read_stat(fd: fd_t, path: [*:0]const u8, traverseLink: bool, stat: *std.c.Stat, statSize: usize) status_t; +pub extern "root" fn on_exit_thread(callback: *const fn (?*anyopaque) callconv(.c) void, data: ?*anyopaque) status_t; pub extern "root" fn find_thread(name: ?[*:0]const u8) thread_id; pub extern "root" fn get_system_info(info: *system_info) status_t; -- 2.54.0 From fae25d72a94f09500cd15c7ff09caf939e7af1ab Mon Sep 17 00:00:00 2001 From: Elaine Gibson Date: Mon, 3 Aug 2026 11:52:34 +0100 Subject: [PATCH 3/3] compiler: remove haiku from defaultSingleThreaded --- src/target.zig | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/target.zig b/src/target.zig index c64fd988cf4de9c881a8e79041ea8f7b80b099d0..e2cbd3e1839dd77df3d6926ee7333dccf405558c 100644 --- a/src/target.zig +++ b/src/target.zig @@ -118,10 +118,6 @@ pub fn defaultSingleThreaded(target: *const std.Target) bool { .wasm32, .wasm64 => return true, else => {}, } - switch (target.os.tag) { - .haiku => return true, - else => {}, - } return false; } -- 2.54.0