feature. See also
. The project being documented here (as the example) is the Zig library itself.
Thread.PosixThreadImpl
const PosixThreadImpl = struct
File
Code
const PosixThreadImpl = struct {
const c = std.c;
pub const ThreadHandle = c.pthread_t;
fn getCurrentId() Id {
switch (native_os) {
.linux => {
return LinuxThreadImpl.getCurrentId();
},
.driverkit, .ios, .maccatalyst, .macos, .tvos, .visionos, .watchos => {
var thread_id: u64 = undefined;
assert(c.pthread_threadid_np(null, &thread_id) == 0);
return thread_id;
},
.dragonfly => {
return @as(u32, @bitCast(c.lwp_gettid()));
},
.netbsd => {
return @as(u32, @bitCast(c._lwp_self()));
},
.freebsd => {
return @as(u32, @bitCast(c.pthread_getthreadid_np()));
},
.openbsd => {
return @as(u32, @bitCast(c.getthrid()));
},
.haiku => {
return @as(u32, @bitCast(c.find_thread(null)));
},
.serenity => {
return @as(u32, @bitCast(c.pthread_self()));
},
else => {
return @intFromPtr(c.pthread_self());
},
}
}
fn getCpuCount() !usize {
switch (native_os) {
.linux => {
return LinuxThreadImpl.getCpuCount();
},
.emscripten => {
return @as(usize, @intCast(std.os.emscripten.emscripten_num_logical_cores()));
},
.openbsd => {
var count: c_int = undefined;
var count_size: usize = @sizeOf(c_int);
const mib = [_]c_int{ std.c.CTL.HW, std.c.HW.NCPUONLINE };
posix.sysctl(&mib, &count, &count_size, null, 0) catch |err| switch (err) {
error.NameTooLong, error.UnknownName => unreachable,
else => |e| return e,
};
return @as(usize, @intCast(count));
},
.illumos, .serenity => {
// /dev/kstat via ioctls, and traverse a linked list for each
// cpu. (illumos)
const rc = c.sysconf(@backingInt(std.c._SC.NPROCESSORS_ONLN));
return switch (posix.errno(rc)) {
.SUCCESS => @as(usize, @intCast(rc)),
else => |err| posix.unexpectedErrno(err),
};
},
.haiku => {
var system_info: std.c.system_info = undefined;
const rc = std.c.get_system_info(&system_info);
return switch (posix.errno(rc)) {
.SUCCESS => @as(usize, @intCast(system_info.cpu_count)),
else => |err| posix.unexpectedErrno(err),
};
},
else => {
var count: c_int = undefined;
var count_len: usize = @sizeOf(c_int);
const name = comptime if (target.os.tag.isDarwin()) "hw.logicalcpu" else "hw.ncpu";
switch (posix.errno(posix.system.sysctlbyname(name, &count, &count_len, null, 0))) {
.SUCCESS => return @intCast(count),
.FAULT => unreachable,
.PERM => return error.PermissionDenied,
.NOMEM => return error.SystemResources,
.NOENT => unreachable,
else => |err| return posix.unexpectedErrno(err),
}
},
}
}
handle: ThreadHandle,
fn spawn(config: SpawnConfig, comptime f: anytype, args: anytype) !Impl {
const Args = @TypeOf(args);
const allocator = std.heap.c_allocator;
const Instance = struct {
fn entryFn(raw_arg: ?*anyopaque) callconv(.c) ?*anyopaque {
const args_ptr: *Args = @ptrCast(@alignCast(raw_arg));
defer allocator.destroy(args_ptr);
return callFn(f, args_ptr.*);
}
};
const args_ptr = try allocator.create(Args);
args_ptr.* = args;
errdefer allocator.destroy(args_ptr);
var attr: c.pthread_attr_t = undefined;
if (c.pthread_attr_init(&attr) != .SUCCESS) return error.SystemResources;
defer assert(c.pthread_attr_destroy(&attr) == .SUCCESS);
const stack_size = @max(config.stack_size, 16 * 1024);
assert(c.pthread_attr_setstacksize(&attr, stack_size) == .SUCCESS);
assert(c.pthread_attr_setguardsize(&attr, std.heap.pageSize()) == .SUCCESS);
var handle: c.pthread_t = undefined;
switch (c.pthread_create(
&handle,
&attr,
Instance.entryFn,
@ptrCast(args_ptr),
)) {
.SUCCESS => return Impl{ .handle = handle },
.AGAIN => return error.SystemResources,
.PERM => unreachable,
.INVAL => unreachable,
else => |err| return posix.unexpectedErrno(err),
}
}
fn getHandle(self: Impl) ThreadHandle {
return self.handle;
}
fn detach(self: Impl) void {
switch (c.pthread_detach(self.handle)) {
.SUCCESS => {},
.INVAL => unreachable,
.SRCH => unreachable,
else => unreachable,
}
}
fn join(self: Impl) void {
switch (c.pthread_join(self.handle, null)) {
.SUCCESS => {},
.INVAL => unreachable,
.SRCH => unreachable,
.DEADLK => unreachable,
else => unreachable,
}
}
}