aboutsummaryrefslogtreecommitdiff
path: root/lib/std/Thread.zig
diff options
context:
space:
mode:
authorAndrew Kelley <andrew@ziglang.org>2024-03-18 22:39:59 -0700
committerAndrew Kelley <andrew@ziglang.org>2024-03-19 11:45:09 -0700
commitcd62005f19ff966d2c42de4daeb9a1e4b644bf76 (patch)
tree4bb316708afaf79c971808df792d8fe86274789b /lib/std/Thread.zig
parent7057bffc14602add697eb566b83934b7ad3fd81c (diff)
downloadzig-cd62005f19ff966d2c42de4daeb9a1e4b644bf76.tar.gz
zig-cd62005f19ff966d2c42de4daeb9a1e4b644bf76.zip
extract std.posix from std.os
closes #5019
Diffstat (limited to 'lib/std/Thread.zig')
-rw-r--r--lib/std/Thread.zig144
1 files changed, 72 insertions, 72 deletions
diff --git a/lib/std/Thread.zig b/lib/std/Thread.zig
index e895183331..abdeb00360 100644
--- a/lib/std/Thread.zig
+++ b/lib/std/Thread.zig
@@ -5,9 +5,11 @@
const std = @import("std.zig");
const builtin = @import("builtin");
const math = std.math;
-const os = std.os;
const assert = std.debug.assert;
const target = builtin.target;
+const native_os = builtin.os.tag;
+const posix = std.posix;
+const windows = std.os.windows;
pub const Futex = @import("Thread/Futex.zig");
pub const ResetEvent = @import("Thread/ResetEvent.zig");
@@ -18,23 +20,23 @@ pub const RwLock = @import("Thread/RwLock.zig");
pub const Pool = @import("Thread/Pool.zig");
pub const WaitGroup = @import("Thread/WaitGroup.zig");
-pub const use_pthreads = target.os.tag != .windows and target.os.tag != .wasi and builtin.link_libc;
+pub const use_pthreads = native_os != .windows and native_os != .wasi and builtin.link_libc;
const Thread = @This();
-const Impl = if (target.os.tag == .windows)
+const Impl = if (native_os == .windows)
WindowsThreadImpl
else if (use_pthreads)
PosixThreadImpl
-else if (target.os.tag == .linux)
+else if (native_os == .linux)
LinuxThreadImpl
-else if (target.os.tag == .wasi)
+else if (native_os == .wasi)
WasiThreadImpl
else
UnsupportedImpl;
impl: Impl,
-pub const max_name_len = switch (target.os.tag) {
+pub const max_name_len = switch (native_os) {
.linux => 15,
.windows => 31,
.macos, .ios, .watchos, .tvos => 63,
@@ -50,7 +52,7 @@ pub const SetNameError = error{
NameTooLong,
Unsupported,
Unexpected,
-} || os.PrctlError || os.WriteError || std.fs.File.OpenError || std.fmt.BufPrintError;
+} || posix.PrctlError || posix.WriteError || std.fs.File.OpenError || std.fmt.BufPrintError;
pub fn setName(self: Thread, name: []const u8) SetNameError!void {
if (name.len > max_name_len) return error.NameTooLong;
@@ -62,21 +64,21 @@ pub fn setName(self: Thread, name: []const u8) SetNameError!void {
break :blk name_buf[0..name.len :0];
};
- switch (target.os.tag) {
+ switch (native_os) {
.linux => if (use_pthreads) {
if (self.getHandle() == std.c.pthread_self()) {
// Set the name of the calling thread (no thread id required).
- const err = try os.prctl(.SET_NAME, .{@intFromPtr(name_with_terminator.ptr)});
- switch (@as(os.E, @enumFromInt(err))) {
+ const err = try posix.prctl(.SET_NAME, .{@intFromPtr(name_with_terminator.ptr)});
+ switch (@as(posix.E, @enumFromInt(err))) {
.SUCCESS => return,
- else => |e| return os.unexpectedErrno(e),
+ else => |e| return posix.unexpectedErrno(e),
}
} else {
const err = std.c.pthread_setname_np(self.getHandle(), name_with_terminator.ptr);
switch (err) {
.SUCCESS => return,
.RANGE => unreachable,
- else => |e| return os.unexpectedErrno(e),
+ else => |e| return posix.unexpectedErrno(e),
}
}
} else {
@@ -95,21 +97,21 @@ pub fn setName(self: Thread, name: []const u8) SetNameError!void {
const byte_len = math.cast(c_ushort, len * 2) orelse return error.NameTooLong;
// Note: NT allocates its own copy, no use-after-free here.
- const unicode_string = os.windows.UNICODE_STRING{
+ const unicode_string = windows.UNICODE_STRING{
.Length = byte_len,
.MaximumLength = byte_len,
.Buffer = &buf,
};
- switch (os.windows.ntdll.NtSetInformationThread(
+ switch (windows.ntdll.NtSetInformationThread(
self.getHandle(),
.ThreadNameInformation,
&unicode_string,
- @sizeOf(os.windows.UNICODE_STRING),
+ @sizeOf(windows.UNICODE_STRING),
)) {
.SUCCESS => return,
.NOT_IMPLEMENTED => return error.Unsupported,
- else => |err| return os.windows.unexpectedStatus(err),
+ else => |err| return windows.unexpectedStatus(err),
}
},
.macos, .ios, .watchos, .tvos => if (use_pthreads) {
@@ -119,7 +121,7 @@ pub fn setName(self: Thread, name: []const u8) SetNameError!void {
const err = std.c.pthread_setname_np(name_with_terminator.ptr);
switch (err) {
.SUCCESS => return,
- else => |e| return os.unexpectedErrno(e),
+ else => |e| return posix.unexpectedErrno(e),
}
},
.netbsd, .solaris, .illumos => if (use_pthreads) {
@@ -129,7 +131,7 @@ pub fn setName(self: Thread, name: []const u8) SetNameError!void {
.INVAL => unreachable,
.SRCH => unreachable,
.NOMEM => unreachable,
- else => |e| return os.unexpectedErrno(e),
+ else => |e| return posix.unexpectedErrno(e),
}
},
.freebsd, .openbsd => if (use_pthreads) {
@@ -148,7 +150,7 @@ pub fn setName(self: Thread, name: []const u8) SetNameError!void {
.FAULT => unreachable,
.NAMETOOLONG => unreachable, // already checked
.SRCH => unreachable,
- else => |e| return os.unexpectedErrno(e),
+ else => |e| return posix.unexpectedErrno(e),
}
},
else => {},
@@ -159,7 +161,7 @@ pub fn setName(self: Thread, name: []const u8) SetNameError!void {
pub const GetNameError = error{
Unsupported,
Unexpected,
-} || os.PrctlError || os.ReadError || std.fs.File.OpenError || std.fmt.BufPrintError;
+} || posix.PrctlError || posix.ReadError || std.fs.File.OpenError || std.fmt.BufPrintError;
/// On Windows, the result is encoded as [WTF-8](https://simonsapin.github.io/wtf-8/).
/// On other platforms, the result is an opaque sequence of bytes with no particular encoding.
@@ -167,21 +169,21 @@ pub fn getName(self: Thread, buffer_ptr: *[max_name_len:0]u8) GetNameError!?[]co
buffer_ptr[max_name_len] = 0;
var buffer: [:0]u8 = buffer_ptr;
- switch (target.os.tag) {
+ switch (native_os) {
.linux => if (use_pthreads) {
if (self.getHandle() == std.c.pthread_self()) {
// Get the name of the calling thread (no thread id required).
- const err = try os.prctl(.GET_NAME, .{@intFromPtr(buffer.ptr)});
- switch (@as(os.E, @enumFromInt(err))) {
+ const err = try posix.prctl(.GET_NAME, .{@intFromPtr(buffer.ptr)});
+ switch (@as(posix.E, @enumFromInt(err))) {
.SUCCESS => return std.mem.sliceTo(buffer, 0),
- else => |e| return os.unexpectedErrno(e),
+ else => |e| return posix.unexpectedErrno(e),
}
} else {
const err = std.c.pthread_getname_np(self.getHandle(), buffer.ptr, max_name_len + 1);
switch (err) {
.SUCCESS => return std.mem.sliceTo(buffer, 0),
.RANGE => unreachable,
- else => |e| return os.unexpectedErrno(e),
+ else => |e| return posix.unexpectedErrno(e),
}
}
} else {
@@ -196,10 +198,10 @@ pub fn getName(self: Thread, buffer_ptr: *[max_name_len:0]u8) GetNameError!?[]co
return if (data_len >= 1) buffer[0 .. data_len - 1] else null;
},
.windows => {
- const buf_capacity = @sizeOf(os.windows.UNICODE_STRING) + (@sizeOf(u16) * max_name_len);
- var buf: [buf_capacity]u8 align(@alignOf(os.windows.UNICODE_STRING)) = undefined;
+ const buf_capacity = @sizeOf(windows.UNICODE_STRING) + (@sizeOf(u16) * max_name_len);
+ var buf: [buf_capacity]u8 align(@alignOf(windows.UNICODE_STRING)) = undefined;
- switch (os.windows.ntdll.NtQueryInformationThread(
+ switch (windows.ntdll.NtQueryInformationThread(
self.getHandle(),
.ThreadNameInformation,
&buf,
@@ -207,12 +209,12 @@ pub fn getName(self: Thread, buffer_ptr: *[max_name_len:0]u8) GetNameError!?[]co
null,
)) {
.SUCCESS => {
- const string = @as(*const os.windows.UNICODE_STRING, @ptrCast(&buf));
+ const string = @as(*const windows.UNICODE_STRING, @ptrCast(&buf));
const len = std.unicode.wtf16LeToWtf8(buffer, string.Buffer.?[0 .. string.Length / 2]);
return if (len > 0) buffer[0..len] else null;
},
.NOT_IMPLEMENTED => return error.Unsupported,
- else => |err| return os.windows.unexpectedStatus(err),
+ else => |err| return windows.unexpectedStatus(err),
}
},
.macos, .ios, .watchos, .tvos => if (use_pthreads) {
@@ -220,7 +222,7 @@ pub fn getName(self: Thread, buffer_ptr: *[max_name_len:0]u8) GetNameError!?[]co
switch (err) {
.SUCCESS => return std.mem.sliceTo(buffer, 0),
.SRCH => unreachable,
- else => |e| return os.unexpectedErrno(e),
+ else => |e| return posix.unexpectedErrno(e),
}
},
.netbsd, .solaris, .illumos => if (use_pthreads) {
@@ -229,7 +231,7 @@ pub fn getName(self: Thread, buffer_ptr: *[max_name_len:0]u8) GetNameError!?[]co
.SUCCESS => return std.mem.sliceTo(buffer, 0),
.INVAL => unreachable,
.SRCH => unreachable,
- else => |e| return os.unexpectedErrno(e),
+ else => |e| return posix.unexpectedErrno(e),
}
},
.freebsd, .openbsd => if (use_pthreads) {
@@ -246,7 +248,7 @@ pub fn getName(self: Thread, buffer_ptr: *[max_name_len:0]u8) GetNameError!?[]co
.INVAL => unreachable,
.FAULT => unreachable,
.SRCH => unreachable,
- else => |e| return os.unexpectedErrno(e),
+ else => |e| return posix.unexpectedErrno(e),
}
},
else => {},
@@ -255,7 +257,7 @@ pub fn getName(self: Thread, buffer_ptr: *[max_name_len:0]u8) GetNameError!?[]co
}
/// Represents an ID per thread guaranteed to be unique only within a process.
-pub const Id = switch (target.os.tag) {
+pub const Id = switch (native_os) {
.linux,
.dragonfly,
.netbsd,
@@ -265,7 +267,7 @@ pub const Id = switch (target.os.tag) {
.wasi,
=> u32,
.macos, .ios, .watchos, .tvos => u64,
- .windows => os.windows.DWORD,
+ .windows => windows.DWORD,
else => usize,
};
@@ -368,13 +370,13 @@ pub const YieldError = error{
/// Yields the current thread potentially allowing other threads to run.
pub fn yield() YieldError!void {
- if (builtin.os.tag == .windows) {
+ if (native_os == .windows) {
// The return value has to do with how many other threads there are; it is not
// an error condition on Windows.
- _ = os.windows.kernel32.SwitchToThread();
+ _ = windows.kernel32.SwitchToThread();
return;
}
- switch (os.errno(os.system.sched_yield())) {
+ switch (posix.errno(posix.system.sched_yield())) {
.SUCCESS => return,
.NOSYS => return error.SystemCannotYield,
else => return error.SystemCannotYield,
@@ -390,7 +392,7 @@ const Completion = std.atomic.Value(enum(u8) {
/// Used by the Thread implementations to call the spawned function with the arguments.
fn callFn(comptime f: anytype, args: anytype) switch (Impl) {
- WindowsThreadImpl => std.os.windows.DWORD,
+ WindowsThreadImpl => windows.DWORD,
LinuxThreadImpl => u8,
PosixThreadImpl => ?*anyopaque,
else => unreachable,
@@ -470,13 +472,11 @@ const UnsupportedImpl = struct {
fn unsupported(unused: anytype) noreturn {
_ = unused;
- @compileError("Unsupported operating system " ++ @tagName(target.os.tag));
+ @compileError("Unsupported operating system " ++ @tagName(native_os));
}
};
const WindowsThreadImpl = struct {
- const windows = os.windows;
-
pub const ThreadHandle = windows.HANDLE;
fn getCurrentId() windows.DWORD {
@@ -584,7 +584,7 @@ const PosixThreadImpl = struct {
pub const ThreadHandle = c.pthread_t;
fn getCurrentId() Id {
- switch (target.os.tag) {
+ switch (native_os) {
.linux => {
return LinuxThreadImpl.getCurrentId();
},
@@ -616,15 +616,15 @@ const PosixThreadImpl = struct {
}
fn getCpuCount() !usize {
- switch (target.os.tag) {
+ switch (native_os) {
.linux => {
return LinuxThreadImpl.getCpuCount();
},
.openbsd => {
var count: c_int = undefined;
var count_size: usize = @sizeOf(c_int);
- const mib = [_]c_int{ os.CTL.HW, os.system.HW.NCPUONLINE };
- os.sysctl(&mib, &count, &count_size, null, 0) catch |err| switch (err) {
+ const mib = [_]c_int{ std.c.CTL.HW, std.c.HW.NCPUONLINE };
+ std.c.sysctl(&mib, &count, &count_size, null, 0) catch |err| switch (err) {
error.NameTooLong, error.UnknownName => unreachable,
else => |e| return e,
};
@@ -634,25 +634,25 @@ const PosixThreadImpl = struct {
// The "proper" way to get the cpu count would be to query
// /dev/kstat via ioctls, and traverse a linked list for each
// cpu.
- const rc = c.sysconf(os._SC.NPROCESSORS_ONLN);
- return switch (os.errno(rc)) {
+ const rc = c.sysconf(std.c._SC.NPROCESSORS_ONLN);
+ return switch (posix.errno(rc)) {
.SUCCESS => @as(usize, @intCast(rc)),
- else => |err| os.unexpectedErrno(err),
+ else => |err| posix.unexpectedErrno(err),
};
},
.haiku => {
- var system_info: os.system.system_info = undefined;
- const rc = os.system.get_system_info(&system_info); // always returns B_OK
- return switch (os.errno(rc)) {
+ 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| os.unexpectedErrno(err),
+ else => |err| posix.unexpectedErrno(err),
};
},
else => {
var count: c_int = undefined;
var count_len: usize = @sizeOf(c_int);
const name = if (comptime target.isDarwin()) "hw.logicalcpu" else "hw.ncpu";
- os.sysctlbynameZ(name, &count, &count_len, null, 0) catch |err| switch (err) {
+ posix.sysctlbynameZ(name, &count, &count_len, null, 0) catch |err| switch (err) {
error.NameTooLong, error.UnknownName => unreachable,
else => |e| return e,
};
@@ -699,7 +699,7 @@ const PosixThreadImpl = struct {
.AGAIN => return error.SystemResources,
.PERM => unreachable,
.INVAL => unreachable,
- else => |err| return os.unexpectedErrno(err),
+ else => |err| return posix.unexpectedErrno(err),
}
}
@@ -1013,7 +1013,7 @@ const WasiThreadImpl = struct {
};
const LinuxThreadImpl = struct {
- const linux = os.linux;
+ const linux = std.os.linux;
pub const ThreadHandle = i32;
@@ -1028,9 +1028,9 @@ const LinuxThreadImpl = struct {
}
fn getCpuCount() !usize {
- const cpu_set = try os.sched_getaffinity(0);
+ const cpu_set = try posix.sched_getaffinity(0);
// TODO: should not need this usize cast
- return @as(usize, os.CPU_COUNT(cpu_set));
+ return @as(usize, posix.CPU_COUNT(cpu_set));
}
thread: *ThreadCompletion,
@@ -1228,10 +1228,10 @@ const LinuxThreadImpl = struct {
// map all memory needed without read/write permissions
// to avoid committing the whole region right away
// anonymous mapping ensures file descriptor limits are not exceeded
- const mapped = os.mmap(
+ const mapped = posix.mmap(
null,
map_bytes,
- os.PROT.NONE,
+ posix.PROT.NONE,
.{ .TYPE = .PRIVATE, .ANONYMOUS = true },
-1,
0,
@@ -1244,24 +1244,24 @@ const LinuxThreadImpl = struct {
else => |e| return e,
};
assert(mapped.len >= map_bytes);
- errdefer os.munmap(mapped);
+ errdefer posix.munmap(mapped);
// map everything but the guard page as read/write
- os.mprotect(
+ posix.mprotect(
@alignCast(mapped[guard_offset..]),
- os.PROT.READ | os.PROT.WRITE,
+ posix.PROT.READ | posix.PROT.WRITE,
) catch |err| switch (err) {
error.AccessDenied => unreachable,
else => |e| return e,
};
// Prepare the TLS segment and prepare a user_desc struct when needed on x86
- var tls_ptr = os.linux.tls.prepareTLS(mapped[tls_offset..]);
- var user_desc: if (target.cpu.arch == .x86) os.linux.user_desc else void = undefined;
+ var tls_ptr = linux.tls.prepareTLS(mapped[tls_offset..]);
+ var user_desc: if (target.cpu.arch == .x86) linux.user_desc else void = undefined;
if (target.cpu.arch == .x86) {
defer tls_ptr = @intFromPtr(&user_desc);
user_desc = .{
- .entry_number = os.linux.tls.tls_image.gdt_entry_number,
+ .entry_number = linux.tls.tls_image.gdt_entry_number,
.base_addr = tls_ptr,
.limit = 0xfffff,
.flags = .{
@@ -1286,7 +1286,7 @@ const LinuxThreadImpl = struct {
linux.CLONE.PARENT_SETTID | linux.CLONE.CHILD_CLEARTID |
linux.CLONE.SIGHAND | linux.CLONE.SYSVSEM | linux.CLONE.SETTLS;
- switch (linux.getErrno(linux.clone(
+ switch (linux.E.init(linux.clone(
Instance.entryFn,
@intFromPtr(&mapped[stack_offset]),
flags,
@@ -1302,7 +1302,7 @@ const LinuxThreadImpl = struct {
.NOSPC => unreachable,
.PERM => unreachable,
.USERS => unreachable,
- else => |err| return os.unexpectedErrno(err),
+ else => |err| return posix.unexpectedErrno(err),
}
}
@@ -1319,7 +1319,7 @@ const LinuxThreadImpl = struct {
}
fn join(self: Impl) void {
- defer os.munmap(self.thread.mapped);
+ defer posix.munmap(self.thread.mapped);
var spin: u8 = 10;
while (true) {
@@ -1334,7 +1334,7 @@ const LinuxThreadImpl = struct {
continue;
}
- switch (linux.getErrno(linux.futex_wait(
+ switch (linux.E.init(linux.futex_wait(
&self.thread.child_tid.raw,
linux.FUTEX.WAIT,
tid,
@@ -1383,7 +1383,7 @@ test "setName, getName" {
// Wait for the main thread to have set the thread field in the context.
ctx.start_wait_event.wait();
- switch (target.os.tag) {
+ switch (native_os) {
.windows => testThreadName(&ctx.thread) catch |err| switch (err) {
error.Unsupported => return error.SkipZigTest,
else => return err,
@@ -1406,7 +1406,7 @@ test "setName, getName" {
context.start_wait_event.set();
context.test_done_event.wait();
- switch (target.os.tag) {
+ switch (native_os) {
.macos, .ios, .watchos, .tvos => {
const res = thread.setName("foobar");
try std.testing.expectError(error.Unsupported, res);