authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-04-28 23:30:13-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-04-28 23:30:13-04:00
loga344cb03bc3c48f3c7fec32dc19c1bcad0910941
tree3e96d3f2cda6b77445e4fe613a4d913303cbf49b
parenta10351b439769c57454e19915365b21e43f408bc

*WIP* use pthreads when linking libc


5 files changed, 107 insertions(+), 29 deletions(-)

std/c/darwin.zig+5
......@@ -81,3 +81,8 @@ pub const sockaddr = extern struct {
8181};
8282
8383pub const sa_family_t = u8;
84
85pub const pthread_attr_t = extern struct {
86 __sig: c_long,
87 __opaque: [56]u8,
88};
std/c/index.zig+10
......@@ -53,3 +53,13 @@ pub extern "c" fn malloc(usize) ?&c_void;
5353pub extern "c" fn realloc(&c_void, usize) ?&c_void;
5454pub extern "c" fn free(&c_void) void;
5555pub extern "c" fn posix_memalign(memptr: &&c_void, alignment: usize, size: usize) c_int;
56
57pub extern "c" fn pthread_create(noalias newthread: &pthread_t,
58 noalias attr: ?&const pthread_attr_t, start_routine: extern fn(?&c_void) ?&c_void,
59 noalias arg: ?&c_void) c_int;
60pub extern "c" fn pthread_attr_init(attr: &pthread_attr_t) c_int;
61pub extern "c" fn pthread_attr_setstack(attr: &pthread_attr_t, stackaddr: &c_void, stacksize: usize) c_int;
62pub extern "c" fn pthread_attr_destroy(attr: &pthread_attr_t) c_int;
63pub extern "c" fn pthread_join(thread: pthread_t, arg_return: ?&?&c_void) c_int;
64
65pub const pthread_t = &@OpaqueType();
std/c/linux.zig+5
......@@ -3,3 +3,8 @@ pub use @import("../os/linux/errno.zig");
33pub extern "c" fn getrandom(buf_ptr: &u8, buf_len: usize, flags: c_uint) c_int;
44extern "c" fn __errno_location() &c_int;
55pub const _errno = __errno_location;
6
7pub const pthread_attr_t = extern struct {
8 __size: [56]u8,
9 __align: c_long,
10};
std/os/index.zig+85-27
......@@ -2,6 +2,10 @@ const std = @import("../index.zig");
22const builtin = @import("builtin");
33const Os = builtin.Os;
44const is_windows = builtin.os == Os.windows;
5const is_posix = switch (builtin.os) {
6 builtin.Os.linux, builtin.Os.macosx => true,
7 else => false,
8};
59const os = this;
610
711test "std.os" {
......@@ -2343,21 +2347,39 @@ pub fn posixGetSockOptConnectError(sockfd: i32) PosixConnectError!void {
23432347}
23442348
23452349pub const Thread = struct {
2346 pid: i32,
2350 pid: pid_t,
23472351 allocator: ?&mem.Allocator,
23482352 stack: []u8,
2353 pthread_handle: pthread_t,
2354
2355 pub const use_pthreads = is_posix and builtin.link_libc;
2356 const pthread_t = if (use_pthreads) c.pthread_t else void;
2357 const pid_t = if (!use_pthreads) i32 else void;
23492358
23502359 pub fn wait(self: &const Thread) void {
2351 while (true) {
2352 const pid_value = @atomicLoad(i32, &self.pid, builtin.AtomicOrder.SeqCst);
2353 if (pid_value == 0) break;
2354 const rc = linux.futex_wait(@ptrToInt(&self.pid), linux.FUTEX_WAIT, pid_value, null);
2355 switch (linux.getErrno(rc)) {
2356 0 => continue,
2357 posix.EINTR => continue,
2358 posix.EAGAIN => continue,
2360 if (use_pthreads) {
2361 const err = c.pthread_join(self.pthread_handle, null);
2362 switch (err) {
2363 0 => {},
2364 posix.EINVAL => unreachable,
2365 posix.ESRCH => unreachable,
2366 posix.EDEADLK => unreachable,
23592367 else => unreachable,
23602368 }
2369 } else if (builtin.os == builtin.Os.linux) {
2370 while (true) {
2371 const pid_value = @atomicLoad(i32, &self.pid, builtin.AtomicOrder.SeqCst);
2372 if (pid_value == 0) break;
2373 const rc = linux.futex_wait(@ptrToInt(&self.pid), linux.FUTEX_WAIT, pid_value, null);
2374 switch (linux.getErrno(rc)) {
2375 0 => continue,
2376 posix.EINTR => continue,
2377 posix.EAGAIN => continue,
2378 else => unreachable,
2379 }
2380 }
2381 } else {
2382 @compileError("Unsupported OS");
23612383 }
23622384 if (self.allocator) |a| {
23632385 a.free(self.stack);
......@@ -2429,31 +2451,67 @@ pub fn spawnThread(stack: []u8, context: var, comptime startFn: var) SpawnThread
24292451 thread_ptr.stack = stack;
24302452 thread_ptr.allocator = null;
24312453
2432 const threadMain = struct {
2433 extern fn threadMain(ctx_addr: usize) u8 {
2454 const MainFuncs = struct {
2455 extern fn linuxThreadMain(ctx_addr: usize) u8 {
24342456 if (@sizeOf(Context) == 0) {
24352457 return startFn({});
24362458 } else {
24372459 return startFn(*@intToPtr(&const Context, ctx_addr));
24382460 }
24392461 }
2440 }.threadMain;
2462 extern fn posixThreadMain(ctx: ?&c_void) ?&c_void {
2463 if (@sizeOf(Context) == 0) {
2464 _ = startFn({});
2465 return null;
2466 } else {
2467 _ = startFn(*@ptrCast(&const Context, @alignCast(@alignOf(Context), ctx)));
2468 return null;
2469 }
2470 }
2471 };
2472
2473 if (builtin.os == builtin.Os.windows) {
2474 // use windows API directly
2475 @compileError("TODO support spawnThread for Windows");
2476 } else if (Thread.use_pthreads) {
2477 // use pthreads
2478 var attr: c.pthread_attr_t = undefined;
2479 if (c.pthread_attr_init(&attr) != 0) return SpawnThreadError.SystemResources;
2480 defer assert(c.pthread_attr_destroy(&attr) == 0);
2481
2482 const stack_size = stack_end - @ptrToInt(stack.ptr);
2483 if (c.pthread_attr_setstack(&attr, @ptrCast(&c_void, stack.ptr), stack_size) != 0) {
2484 return SpawnThreadError.SystemResources;
2485 }
24412486
2442 const flags = posix.CLONE_VM | posix.CLONE_FS | posix.CLONE_FILES | posix.CLONE_SIGHAND
2443 | posix.CLONE_THREAD | posix.CLONE_SYSVSEM // | posix.CLONE_SETTLS
2444 | posix.CLONE_PARENT_SETTID | posix.CLONE_CHILD_CLEARTID | posix.CLONE_DETACHED;
2445 const newtls: usize = 0;
2446 const rc = posix.clone(threadMain, stack_end, flags, arg, &thread_ptr.pid, newtls, &thread_ptr.pid);
2447 const err = posix.getErrno(rc);
2448 switch (err) {
2449 0 => return thread_ptr,
2450 posix.EAGAIN => return SpawnThreadError.ThreadQuotaExceeded,
2451 posix.EINVAL => unreachable,
2452 posix.ENOMEM => return SpawnThreadError.SystemResources,
2453 posix.ENOSPC => unreachable,
2454 posix.EPERM => unreachable,
2455 posix.EUSERS => unreachable,
2456 else => return unexpectedErrorPosix(err),
2487 const err = c.pthread_create(&thread_ptr.pthread_handle, &attr, MainFuncs.posixThreadMain, @intToPtr(&c_void, arg));
2488 switch (err) {
2489 0 => return thread_ptr,
2490 posix.EAGAIN => return SpawnThreadError.SystemResources,
2491 posix.EPERM => unreachable,
2492 posix.EINVAL => unreachable,
2493 else => return unexpectedErrorPosix(usize(err)),
2494 }
2495 } else if (builtin.os == builtin.Os.linux) {
2496 // use linux API directly
2497 const flags = posix.CLONE_VM | posix.CLONE_FS | posix.CLONE_FILES | posix.CLONE_SIGHAND
2498 | posix.CLONE_THREAD | posix.CLONE_SYSVSEM // | posix.CLONE_SETTLS
2499 | posix.CLONE_PARENT_SETTID | posix.CLONE_CHILD_CLEARTID | posix.CLONE_DETACHED;
2500 const newtls: usize = 0;
2501 const rc = posix.clone(MainFuncs.linuxThreadMain, stack_end, flags, arg, &thread_ptr.pid, newtls, &thread_ptr.pid);
2502 const err = posix.getErrno(rc);
2503 switch (err) {
2504 0 => return thread_ptr,
2505 posix.EAGAIN => return SpawnThreadError.ThreadQuotaExceeded,
2506 posix.EINVAL => unreachable,
2507 posix.ENOMEM => return SpawnThreadError.SystemResources,
2508 posix.ENOSPC => unreachable,
2509 posix.EPERM => unreachable,
2510 posix.EUSERS => unreachable,
2511 else => return unexpectedErrorPosix(err),
2512 }
2513 } else {
2514 @compileError("Unsupported OS");
24572515 }
24582516}
24592517
std/os/test.zig+2-2
......@@ -44,8 +44,8 @@ test "access file" {
4444}
4545
4646test "spawn threads" {
47 if (builtin.os != builtin.Os.linux) {
48 // TODO implement threads on macos and windows
47 if (builtin.os == builtin.Os.windows) {
48 // TODO implement threads on windows
4949 return;
5050 }
5151