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 {...@@ -81,3 +81,8 @@ pub const sockaddr = extern struct {
81};81};
8282
83pub const sa_family_t = u8;83pub 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;...@@ -53,3 +53,13 @@ pub extern "c" fn malloc(usize) ?&c_void;
53pub extern "c" fn realloc(&c_void, usize) ?&c_void;53pub extern "c" fn realloc(&c_void, usize) ?&c_void;
54pub extern "c" fn free(&c_void) void;54pub extern "c" fn free(&c_void) void;
55pub extern "c" fn posix_memalign(memptr: &&c_void, alignment: usize, size: usize) c_int;55pub 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");...@@ -3,3 +3,8 @@ pub use @import("../os/linux/errno.zig");
3pub extern "c" fn getrandom(buf_ptr: &u8, buf_len: usize, flags: c_uint) c_int;3pub extern "c" fn getrandom(buf_ptr: &u8, buf_len: usize, flags: c_uint) c_int;
4extern "c" fn __errno_location() &c_int;4extern "c" fn __errno_location() &c_int;
5pub const _errno = __errno_location;5pub 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");...@@ -2,6 +2,10 @@ const std = @import("../index.zig");
2const builtin = @import("builtin");2const builtin = @import("builtin");
3const Os = builtin.Os;3const Os = builtin.Os;
4const is_windows = builtin.os == Os.windows;4const is_windows = builtin.os == Os.windows;
5const is_posix = switch (builtin.os) {
6 builtin.Os.linux, builtin.Os.macosx => true,
7 else => false,
8};
5const os = this;9const os = this;
610
7test "std.os" {11test "std.os" {
...@@ -2343,21 +2347,39 @@ pub fn posixGetSockOptConnectError(sockfd: i32) PosixConnectError!void {...@@ -2343,21 +2347,39 @@ pub fn posixGetSockOptConnectError(sockfd: i32) PosixConnectError!void {
2343}2347}
23442348
2345pub const Thread = struct {2349pub const Thread = struct {
2346 pid: i32,2350 pid: pid_t,
2347 allocator: ?&mem.Allocator,2351 allocator: ?&mem.Allocator,
2348 stack: []u8,2352 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
2350 pub fn wait(self: &const Thread) void {2359 pub fn wait(self: &const Thread) void {
2351 while (true) {2360 if (use_pthreads) {
2352 const pid_value = @atomicLoad(i32, &self.pid, builtin.AtomicOrder.SeqCst);2361 const err = c.pthread_join(self.pthread_handle, null);
2353 if (pid_value == 0) break;2362 switch (err) {
2354 const rc = linux.futex_wait(@ptrToInt(&self.pid), linux.FUTEX_WAIT, pid_value, null);2363 0 => {},
2355 switch (linux.getErrno(rc)) {2364 posix.EINVAL => unreachable,
2356 0 => continue,2365 posix.ESRCH => unreachable,
2357 posix.EINTR => continue,2366 posix.EDEADLK => unreachable,
2358 posix.EAGAIN => continue,
2359 else => unreachable,2367 else => unreachable,
2360 }2368 }
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");
2361 }2383 }
2362 if (self.allocator) |a| {2384 if (self.allocator) |a| {
2363 a.free(self.stack);2385 a.free(self.stack);
...@@ -2429,31 +2451,67 @@ pub fn spawnThread(stack: []u8, context: var, comptime startFn: var) SpawnThread...@@ -2429,31 +2451,67 @@ pub fn spawnThread(stack: []u8, context: var, comptime startFn: var) SpawnThread
2429 thread_ptr.stack = stack;2451 thread_ptr.stack = stack;
2430 thread_ptr.allocator = null;2452 thread_ptr.allocator = null;
24312453
2432 const threadMain = struct {2454 const MainFuncs = struct {
2433 extern fn threadMain(ctx_addr: usize) u8 {2455 extern fn linuxThreadMain(ctx_addr: usize) u8 {
2434 if (@sizeOf(Context) == 0) {2456 if (@sizeOf(Context) == 0) {
2435 return startFn({});2457 return startFn({});
2436 } else {2458 } else {
2437 return startFn(*@intToPtr(&const Context, ctx_addr));2459 return startFn(*@intToPtr(&const Context, ctx_addr));
2438 }2460 }
2439 }2461 }
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_SIGHAND2487 const err = c.pthread_create(&thread_ptr.pthread_handle, &attr, MainFuncs.posixThreadMain, @intToPtr(&c_void, arg));
2443 | posix.CLONE_THREAD | posix.CLONE_SYSVSEM // | posix.CLONE_SETTLS2488 switch (err) {
2444 | posix.CLONE_PARENT_SETTID | posix.CLONE_CHILD_CLEARTID | posix.CLONE_DETACHED;2489 0 => return thread_ptr,
2445 const newtls: usize = 0;2490 posix.EAGAIN => return SpawnThreadError.SystemResources,
2446 const rc = posix.clone(threadMain, stack_end, flags, arg, &thread_ptr.pid, newtls, &thread_ptr.pid);2491 posix.EPERM => unreachable,
2447 const err = posix.getErrno(rc);2492 posix.EINVAL => unreachable,
2448 switch (err) {2493 else => return unexpectedErrorPosix(usize(err)),
2449 0 => return thread_ptr,2494 }
2450 posix.EAGAIN => return SpawnThreadError.ThreadQuotaExceeded,2495 } else if (builtin.os == builtin.Os.linux) {
2451 posix.EINVAL => unreachable,2496 // use linux API directly
2452 posix.ENOMEM => return SpawnThreadError.SystemResources,2497 const flags = posix.CLONE_VM | posix.CLONE_FS | posix.CLONE_FILES | posix.CLONE_SIGHAND
2453 posix.ENOSPC => unreachable,2498 | posix.CLONE_THREAD | posix.CLONE_SYSVSEM // | posix.CLONE_SETTLS
2454 posix.EPERM => unreachable,2499 | posix.CLONE_PARENT_SETTID | posix.CLONE_CHILD_CLEARTID | posix.CLONE_DETACHED;
2455 posix.EUSERS => unreachable,2500 const newtls: usize = 0;
2456 else => return unexpectedErrorPosix(err),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");
2457 }2515 }
2458}2516}
24592517
std/os/test.zig+2-2
...@@ -44,8 +44,8 @@ test "access file" {...@@ -44,8 +44,8 @@ test "access file" {
44}44}
4545
46test "spawn threads" {46test "spawn threads" {
47 if (builtin.os != builtin.Os.linux) {47 if (builtin.os == builtin.Os.windows) {
48 // TODO implement threads on macos and windows48 // TODO implement threads on windows
49 return;49 return;
50 }50 }
5151