authorgravatar for services@mlugg.co.ukmlugg <services@mlugg.co.uk> 2026-08-07 19:24:07+02:00
committergravatar for services@mlugg.co.ukmlugg <services@mlugg.co.uk> 2026-08-07 19:24:07+02:00
log3d35188fe8c423e7afed863def0fa9ac347230f2
tree1f173c2a5163ff865432506264be9464ca3d431d
parent9d27b6289b592d312618d87819d533dc6e140ccd
parentfae25d72a94f09500cd15c7ff09caf939e7af1ab

Merge pull request 'remove haiku from defaultSingleThreaded' (#32137) from ypsvlq/zig:master into master

Reviewed-on: https://codeberg.org/ziglang/zig/pulls/32137 Reviewed-by: mlugg <services@mlugg.co.uk>

5 files changed, 101 insertions(+), 93 deletions(-)

lib/std/Io/Threaded.zig+69-5
...@@ -829,6 +829,7 @@ const Thread = struct {...@@ -829,6 +829,7 @@ const Thread = struct {
829 /// Always released when `Status.cancelation` is set to `.parked`.829 /// Always released when `Status.cancelation` is set to `.parked`.
830 futex_waiter: if (use_parking_futex) ?*parking_futex.Waiter else ?noreturn,830 futex_waiter: if (use_parking_futex) ?*parking_futex.Waiter else ?noreturn,
831 unpark_flag: UnparkFlag,831 unpark_flag: UnparkFlag,
832 park_tid: if (ParkTid == std.Thread.Id) void else ParkTid,
832833
833 csprng: Csprng,834 csprng: Csprng,
834835
...@@ -1220,7 +1221,7 @@ const Thread = struct {...@@ -1220,7 +1221,7 @@ const Thread = struct {
1220 parking_futex.removeCanceledWaiter(futex_waiter);1221 parking_futex.removeCanceledWaiter(futex_waiter);
1221 }1222 }
1222 if (need_unpark_flag) setUnparkFlag(&thread.unpark_flag);1223 if (need_unpark_flag) setUnparkFlag(&thread.unpark_flag);
1223 unpark(&.{thread.id}, null);1224 unpark(&.{if (ParkTid == std.Thread.Id) thread.id else thread.park_tid}, null);
1224 return false;1225 return false;
1225 },1226 },
12261227
...@@ -1749,6 +1750,7 @@ fn worker(t: *Threaded) void {...@@ -1749,6 +1750,7 @@ fn worker(t: *Threaded) void {
1749 .cancel_protection = .unblocked,1750 .cancel_protection = .unblocked,
1750 .futex_waiter = undefined,1751 .futex_waiter = undefined,
1751 .unpark_flag = unpark_flag_init,1752 .unpark_flag = unpark_flag_init,
1753 .park_tid = if (ParkTid == std.Thread.Id) {} else getParkTid(),
1752 .csprng = .uninitialized,1754 .csprng = .uninitialized,
1753 };1755 };
1754 Thread.current = &thread;1756 Thread.current = &thread;
...@@ -17431,6 +17433,7 @@ const use_parking_futex = switch (native_os) {...@@ -17431,6 +17433,7 @@ const use_parking_futex = switch (native_os) {
17431 .windows => true, // RtlWaitOnAddress is a userland implementation anyway17433 .windows => true, // RtlWaitOnAddress is a userland implementation anyway
17432 .netbsd => true, // NetBSD has `futex(2)`, but it's historically been quite buggy. TODO: evaluate whether it's okay to use now.17434 .netbsd => true, // NetBSD has `futex(2)`, but it's historically been quite buggy. TODO: evaluate whether it's okay to use now.
17433 .illumos => true, // Illumos has no futex mechanism17435 .illumos => true, // Illumos has no futex mechanism
17436 .haiku => true, // Haiku has no futex mechanism
17434 else => false,17437 else => false,
17435};17438};
17436const use_parking_sleep = switch (native_os) {17439const use_parking_sleep = switch (native_os) {
...@@ -17476,7 +17479,7 @@ const parking_futex = struct {...@@ -17476,7 +17479,7 @@ const parking_futex = struct {
17476 const Waiter = struct {17479 const Waiter = struct {
17477 node: std.DoublyLinkedList.Node,17480 node: std.DoublyLinkedList.Node,
17478 address: usize,17481 address: usize,
17479 tid: std.Thread.Id,17482 tid: ParkTid,
17480 /// `thread_status.cancelation` is `.parked` while the thread is waiting. The single thread17483 /// `thread_status.cancelation` is `.parked` while the thread is waiting. The single thread
17481 /// which atomically updates it (to `.none` or `.canceling`) is responsible for:17484 /// which atomically updates it (to `.none` or `.canceling`) is responsible for:
17482 ///17485 ///
...@@ -17517,7 +17520,7 @@ const parking_futex = struct {...@@ -17517,7 +17520,7 @@ const parking_futex = struct {
1751717520
17518 // Put the threadlocal access outside of the critical section.17521 // Put the threadlocal access outside of the critical section.
17519 const opt_thread = Thread.current;17522 const opt_thread = Thread.current;
17520 const self_tid = if (opt_thread) |thread| thread.id else std.Thread.getCurrentId();17523 const self_tid = getParkTid();
1752117524
17522 var waiter: Waiter = .{17525 var waiter: Waiter = .{
17523 .node = undefined, // populated by list append17526 .node = undefined, // populated by list append
...@@ -17765,7 +17768,12 @@ const parking_sleep = struct {...@@ -17765,7 +17768,12 @@ const parking_sleep = struct {
17765 },17768 },
17766 }17769 }
17767 }17770 }
17771
17768 // Uncancelable sleep; we expect not to be manually unparked.17772 // Uncancelable sleep; we expect not to be manually unparked.
17773
17774 // On systems where parking the thread requires a one-time setup operation (e.g. creating a
17775 // semaphore), we need to ensure that setup is done before we call `park`.
17776 _ = getParkTid();
17769 var dummy_flag: UnparkFlag = unpark_flag_init;17777 var dummy_flag: UnparkFlag = unpark_flag_init;
17770 if (park(timeout, null, if (need_unpark_flag) &dummy_flag)) {17778 if (park(timeout, null, if (need_unpark_flag) &dummy_flag)) {
17771 unreachable; // unexpected unpark17779 unreachable; // unexpected unpark
...@@ -17804,7 +17812,7 @@ const ParkingMutex = struct {...@@ -17804,7 +17812,7 @@ const ParkingMutex = struct {
17804 /// Never modified once the `Waiter` is in the linked list.17812 /// Never modified once the `Waiter` is in the linked list.
17805 next: ?*Waiter,17813 next: ?*Waiter,
17806 /// Never modified once the `Waiter` is in the linked list.17814 /// Never modified once the `Waiter` is in the linked list.
17807 tid: std.Thread.Id,17815 tid: ParkTid,
17808 };17816 };
17809 fn lock(m: *ParkingMutex) void {17817 fn lock(m: *ParkingMutex) void {
17810 state: switch (State.unlocked) { // assume 'unlocked' to optimize for uncontended case17818 state: switch (State.unlocked) { // assume 'unlocked' to optimize for uncontended case
...@@ -17820,7 +17828,7 @@ const ParkingMutex = struct {...@@ -17820,7 +17828,7 @@ const ParkingMutex = struct {
1782017828
17821 .locked_once, _ => |last_state| {17829 .locked_once, _ => |last_state| {
17822 const old_waiter = last_state.waiter();17830 const old_waiter = last_state.waiter();
17823 const self_tid = if (Thread.current) |t| t.id else std.Thread.getCurrentId();17831 const self_tid = getParkTid();
17824 var waiter: Waiter = .{17832 var waiter: Waiter = .{
17825 .next = old_waiter,17833 .next = old_waiter,
17826 .unpark_flag = unpark_flag_init,17834 .unpark_flag = unpark_flag_init,
...@@ -17948,9 +17956,36 @@ fn setUnparkFlag(f: *UnparkFlag) void {...@@ -17948,9 +17956,36 @@ fn setUnparkFlag(f: *UnparkFlag) void {
17948/// but it seems that someone at Microsoft forgot how big their TIDs are supposed to be.17956/// but it seems that someone at Microsoft forgot how big their TIDs are supposed to be.
17949const UnparkTid = switch (native_os) {17957const UnparkTid = switch (native_os) {
17950 .windows => usize,17958 .windows => usize,
17959 else => ParkTid,
17960};
17961
17962const ParkTid = switch (native_os) {
17963 .haiku => std.c.sem_id,
17951 else => std.Thread.Id,17964 else => std.Thread.Id,
17952};17965};
1795317966
17967threadlocal var park_sem: std.c.sem_id = -1;
17968
17969fn getParkTid() ParkTid {
17970 switch (native_os) {
17971 .haiku => {
17972 if (park_sem == -1) {
17973 park_sem = std.c._kern_create_sem(0, null);
17974 if (park_sem < 0) @panic("_kern_create_sem failed");
17975 _ = std.c.on_exit_thread(destroyParkSem, null);
17976 }
17977 return park_sem;
17978 },
17979 else => {
17980 return if (Thread.current) |thread| thread.id else std.Thread.getCurrentId();
17981 },
17982 }
17983}
17984
17985fn destroyParkSem(_: ?*anyopaque) callconv(.c) void {
17986 _ = std.c._kern_delete_sem(park_sem);
17987}
17988
17954fn park(17989fn park(
17955 timeout: Io.Timeout,17990 timeout: Io.Timeout,
17956 /// This value has no semantic effect, but may allow the OS to optimize the operation.17991 /// This value has no semantic effect, but may allow the OS to optimize the operation.
...@@ -18016,6 +18051,27 @@ fn park(...@@ -18016,6 +18051,27 @@ fn park(
18016 }18051 }
18017 },18052 },
18018 .illumos => @panic("TODO: illumos lwp_park"),18053 .illumos => @panic("TODO: illumos lwp_park"),
18054 .haiku => {
18055 const timeout_flags: u32, const timeout_us = switch (timeout) {
18056 .none => .{ 0, 0 },
18057 .deadline => |deadline| .{
18058 if (deadline.clock == .real) std.c.B_ABSOLUTE_TIMEOUT | std.c.B_TIMEOUT_REAL_TIME_BASE else std.c.B_ABSOLUTE_TIMEOUT,
18059 deadline.raw.toMicroseconds(),
18060 },
18061 .duration => |duration| .{
18062 if (duration.clock == .real) std.c.B_ABSOLUTE_TIMEOUT | std.c.B_TIMEOUT_REAL_TIME_BASE else std.c.B_ABSOLUTE_TIMEOUT,
18063 nowPosix(duration.clock).addDuration(duration.raw).toMicroseconds(),
18064 },
18065 };
18066 while (true) {
18067 switch (std.c._kern_acquire_sem_etc(park_sem, 1, timeout_flags, timeout_us)) {
18068 0 => return,
18069 std.c.E.B_TIMED_OUT => return error.Timeout,
18070 std.c.E.B_INTERRUPTED => {},
18071 else => unreachable,
18072 }
18073 }
18074 },
18019 else => comptime unreachable,18075 else => comptime unreachable,
18020 }18076 }
18021}18077}
...@@ -18058,6 +18114,14 @@ fn unpark(tids: []const UnparkTid, addr_hint: ?*const anyopaque) void {...@@ -18058,6 +18114,14 @@ fn unpark(tids: []const UnparkTid, addr_hint: ?*const anyopaque) void {
18058 }18114 }
18059 },18115 },
18060 .illumos => @panic("TODO: illumos lwp_unpark"),18116 .illumos => @panic("TODO: illumos lwp_unpark"),
18117 .haiku => {
18118 for (tids) |tid| {
18119 switch (std.c._kern_release_sem_etc(tid, 1, 0)) {
18120 0 => {},
18121 else => recoverableOsBugDetected(),
18122 }
18123 }
18124 },
18061 else => comptime unreachable,18125 else => comptime unreachable,
18062 }18126 }
18063}18127}
lib/std/Thread.zig+3-4
...@@ -719,10 +719,9 @@ const PosixThreadImpl = struct {...@@ -719,10 +719,9 @@ const PosixThreadImpl = struct {
719 },719 },
720 .haiku => {720 .haiku => {
721 var system_info: std.c.system_info = undefined;721 var system_info: std.c.system_info = undefined;
722 const rc = std.c.get_system_info(&system_info); // always returns B_OK722 return switch (std.c.get_system_info(&system_info)) {
723 return switch (posix.errno(rc)) {723 0 => @as(usize, @intCast(system_info.cpu_count)),
724 .SUCCESS => @as(usize, @intCast(system_info.cpu_count)),724 else => error.Unexpected,
725 else => |err| posix.unexpectedErrno(err),
726 };725 };
727 },726 },
728 else => {727 else => {
lib/std/c.zig+11-11
...@@ -2991,6 +2991,7 @@ pub const SIG = switch (native_os) {...@@ -2991,6 +2991,7 @@ pub const SIG = switch (native_os) {
2991 pub const UNBLOCK = 2;2991 pub const UNBLOCK = 2;
2992 pub const SETMASK = 3;2992 pub const SETMASK = 3;
29932993
2994 pub const IO: SIG = .POLL;
2994 pub const IOT: SIG = .ABRT;2995 pub const IOT: SIG = .ABRT;
29952996
2996 HUP = 1,2997 HUP = 1,
...@@ -11267,31 +11268,30 @@ pub const signalfd_siginfo = illumos.signalfd_siginfo;...@@ -11267,31 +11268,30 @@ pub const signalfd_siginfo = illumos.signalfd_siginfo;
11267pub const taskid_t = illumos.taskid_t;11268pub const taskid_t = illumos.taskid_t;
11268pub const zoneid_t = illumos.zoneid_t;11269pub const zoneid_t = illumos.zoneid_t;
1126911270
11271pub const B_ABSOLUTE_TIMEOUT = haiku.B_ABSOLUTE_TIMEOUT;
11272pub const B_OS_NAME_LENGTH = haiku.B_OS_NAME_LENGTH;
11273pub const B_TIMEOUT_REAL_TIME_BASE = haiku.B_TIMEOUT_REAL_TIME_BASE;
11270pub const DirEnt = haiku.DirEnt;11274pub const DirEnt = haiku.DirEnt;
11271pub const _get_next_area_info = haiku._get_next_area_info;11275pub const _kern_acquire_sem_etc = haiku._kern_acquire_sem_etc;
11272pub const _get_next_image_info = haiku._get_next_image_info;11276pub const _kern_create_sem = haiku._kern_create_sem;
11273pub const _get_team_info = haiku._get_team_info;11277pub const _kern_delete_sem = haiku._kern_delete_sem;
11274pub const _kern_get_current_team = haiku._kern_get_current_team;
11275pub const _kern_open_dir = haiku._kern_open_dir;11278pub const _kern_open_dir = haiku._kern_open_dir;
11276pub const _kern_read_dir = haiku._kern_read_dir;11279pub const _kern_read_dir = haiku._kern_read_dir;
11277pub const _kern_read_stat = haiku._kern_read_stat;11280pub const _kern_read_stat = haiku._kern_read_stat;
11281pub const _kern_release_sem_etc = haiku._kern_release_sem_etc;
11278pub const _kern_rewind_dir = haiku._kern_rewind_dir;11282pub const _kern_rewind_dir = haiku._kern_rewind_dir;
11279pub const readv_pos = haiku.readv_pos;
11280pub const writev_pos = haiku.writev_pos;
11281pub const area_id = haiku.area_id;11283pub const area_id = haiku.area_id;
11282pub const area_info = haiku.area_info;
11283pub const directory_which = haiku.directory_which;
11284pub const find_directory = haiku.find_directory;
11285pub const find_thread = haiku.find_thread;11284pub const find_thread = haiku.find_thread;
11286pub const get_system_info = haiku.get_system_info;11285pub const get_system_info = haiku.get_system_info;
11287pub const image_info = haiku.image_info;11286pub const on_exit_thread = haiku.on_exit_thread;
11288pub const port_id = haiku.port_id;11287pub const port_id = haiku.port_id;
11288pub const readv_pos = haiku.readv_pos;
11289pub const sem_id = haiku.sem_id;11289pub const sem_id = haiku.sem_id;
11290pub const status_t = haiku.status_t;11290pub const status_t = haiku.status_t;
11291pub const system_info = haiku.system_info;11291pub const system_info = haiku.system_info;
11292pub const team_id = haiku.team_id;11292pub const team_id = haiku.team_id;
11293pub const team_info = haiku.team_info;
11294pub const thread_id = haiku.thread_id;11293pub const thread_id = haiku.thread_id;
11294pub const writev_pos = haiku.writev_pos;
1129511295
11296pub const AUTH = openbsd.AUTH;11296pub const AUTH = openbsd.AUTH;
11297pub const BI = openbsd.BI;11297pub const BI = openbsd.BI;
lib/std/c/haiku.zig+18-69
...@@ -1,15 +1,8 @@...@@ -1,15 +1,8 @@
1const std = @import("../std.zig");1const std = @import("../std.zig");
2const assert = std.debug.assert;
3const builtin = @import("builtin");2const builtin = @import("builtin");
4const maxInt = std.math.maxInt;3const assert = std.debug.assert;
5const iovec = std.posix.iovec;
6const iovec_const = std.posix.iovec_const;
7const socklen_t = std.c.socklen_t;
8const fd_t = std.c.fd_t;4const fd_t = std.c.fd_t;
9const off_t = std.c.off_t;5const off_t = std.c.off_t;
10const PATH_MAX = std.c.PATH_MAX;
11const uid_t = std.c.uid_t;
12const gid_t = std.c.gid_t;
13const dev_t = std.c.dev_t;6const dev_t = std.c.dev_t;
14const ino_t = std.c.ino_t;7const ino_t = std.c.ino_t;
158
...@@ -17,52 +10,27 @@ comptime {...@@ -17,52 +10,27 @@ comptime {
17 assert(builtin.os.tag == .haiku); // Prevent access of std.c symbols on wrong OS.10 assert(builtin.os.tag == .haiku); // Prevent access of std.c symbols on wrong OS.
18}11}
1912
20pub extern "root" fn _errnop() *i32;13pub const B_OS_NAME_LENGTH = 32;
21pub extern "root" fn find_directory(which: directory_which, volume: i32, createIt: bool, path_ptr: [*]u8, length: i32) u64;14pub const B_ABSOLUTE_TIMEOUT = 0x10;
22pub extern "root" fn find_thread(thread_name: ?*anyopaque) i32;15pub const B_TIMEOUT_REAL_TIME_BASE = 0x40;
23pub extern "root" fn get_system_info(system_info: *system_info) usize;16
24pub extern "root" fn _get_team_info(team: i32, team_info: *team_info, size: usize) i32;17pub extern "root" fn _kern_create_sem(count: c_int, name: ?[*:0]const u8) sem_id;
25pub extern "root" fn _get_next_area_info(team: i32, cookie: *i64, area_info: *area_info, size: usize) i32;18pub extern "root" fn _kern_delete_sem(id: sem_id) status_t;
26pub extern "root" fn _get_next_image_info(team: i32, cookie: *i32, image_info: *image_info, size: usize) i32;19pub extern "root" fn _kern_acquire_sem_etc(id: sem_id, count: u32, flags: u32, timeout: i64) status_t;
27pub extern "root" fn _kern_get_current_team() team_id;20pub extern "root" fn _kern_release_sem_etc(id: sem_id, count: u32, flags: u32) status_t;
28pub extern "root" fn _kern_open_dir(fd: fd_t, path: [*:0]const u8) fd_t;21pub extern "root" fn _kern_open_dir(fd: fd_t, path: [*:0]const u8) fd_t;
29pub extern "root" fn _kern_read_dir(fd: fd_t, buffer: [*]u8, bufferSize: usize, maxCount: u32) isize;22pub extern "root" fn _kern_read_dir(fd: fd_t, buffer: [*]u8, bufferSize: usize, maxCount: u32) isize;
30pub extern "root" fn _kern_rewind_dir(fd: fd_t) status_t;23pub extern "root" fn _kern_rewind_dir(fd: fd_t) status_t;
31pub extern "root" fn _kern_read_stat(fd: fd_t, path: [*:0]const u8, traverseLink: bool, stat: *std.c.Stat, statSize: usize) status_t;24pub extern "root" fn _kern_read_stat(fd: fd_t, path: [*:0]const u8, traverseLink: bool, stat: *std.c.Stat, statSize: usize) status_t;
32pub extern "root" fn readv_pos(fd: fd_t, pos: off_t, vec: [*]const std.c.iovec, count: i32) isize;
33pub extern "root" fn writev_pos(fd: fd_t, pos: off_t, vec: [*]const std.c.iovec_const, count: i32) isize;
3425
35pub const area_info = extern struct {26pub extern "root" fn on_exit_thread(callback: *const fn (?*anyopaque) callconv(.c) void, data: ?*anyopaque) status_t;
36 area: u32,27pub extern "root" fn find_thread(name: ?[*:0]const u8) thread_id;
37 name: [32]u8,28pub extern "root" fn get_system_info(info: *system_info) status_t;
38 size: usize,
39 lock: u32,
40 protection: u32,
41 team_id: i32,
42 ram_size: u32,
43 copy_count: u32,
44 in_count: u32,
45 out_count: u32,
46 address: *anyopaque,
47};
4829
49pub const image_info = extern struct {30pub extern "root" fn _errnop() *i32;
50 id: u32,31
51 image_type: u32,32pub extern "root" fn readv_pos(fd: fd_t, pos: off_t, vec: [*]const std.c.iovec, count: i32) isize;
52 sequence: i32,33pub extern "root" fn writev_pos(fd: fd_t, pos: off_t, vec: [*]const std.c.iovec_const, count: i32) isize;
53 init_order: i32,
54 init_routine: *anyopaque,
55 term_routine: *anyopaque,
56 device: i32,
57 node: i64,
58 name: [PATH_MAX]u8,
59 text: *anyopaque,
60 data: *anyopaque,
61 text_size: i32,
62 data_size: i32,
63 api_version: i32,
64 abi: i32,
65};
6634
67pub const system_info = extern struct {35pub const system_info = extern struct {
68 boot_time: i64,36 boot_time: i64,
...@@ -86,31 +54,12 @@ pub const system_info = extern struct {...@@ -86,31 +54,12 @@ pub const system_info = extern struct {
86 max_teams: u32,54 max_teams: u32,
87 used_teams: u32,55 used_teams: u32,
88 kernel_name: [256]u8,56 kernel_name: [256]u8,
89 kernel_build_date: [32]u8,57 kernel_build_date: [B_OS_NAME_LENGTH]u8,
90 kernel_build_time: [32]u8,58 kernel_build_time: [B_OS_NAME_LENGTH]u8,
91 kernel_version: i64,59 kernel_version: i64,
92 abi: u32,60 abi: u32,
93};61};
9462
95pub const team_info = extern struct {
96 team_id: i32,
97 thread_count: i32,
98 image_count: i32,
99 area_count: i32,
100 debugger_nub_thread: i32,
101 debugger_nub_port: i32,
102 argc: i32,
103 args: [64]u8,
104 uid: uid_t,
105 gid: gid_t,
106};
107
108pub const directory_which = enum(i32) {
109 B_USER_SETTINGS_DIRECTORY = 0xbbe,
110
111 _,
112};
113
114pub const area_id = i32;63pub const area_id = i32;
115pub const port_id = i32;64pub const port_id = i32;
116pub const sem_id = i32;65pub const sem_id = i32;
src/target.zig-4
...@@ -118,10 +118,6 @@ pub fn defaultSingleThreaded(target: *const std.Target) bool {...@@ -118,10 +118,6 @@ pub fn defaultSingleThreaded(target: *const std.Target) bool {
118 .wasm32, .wasm64 => return true,118 .wasm32, .wasm64 => return true,
119 else => {},119 else => {},
120 }120 }
121 switch (target.os.tag) {
122 .haiku => return true,
123 else => {},
124 }
125 return false;121 return false;
126}122}
127123