authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-08-06 17:32:55-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-08-06 17:32:55-04:00
logc02ed805122cb05dfb21a30e626e25994b3eb698
treed63d84c3eba4cd1d9c28a41ac7979eeff4784843
parent72bac72338af64a73668721cd035dfdf1ff2badb
parent24d74cbf44b34b180b2df5557927d9d2e4c9e443

Merge branch 'mdsteele-threadid'


5 files changed, 72 insertions(+), 7 deletions(-)

std/c/index.zig+1
...@@ -58,6 +58,7 @@ pub extern "pthread" fn pthread_create(noalias newthread: *pthread_t, noalias at...@@ -58,6 +58,7 @@ pub extern "pthread" fn pthread_create(noalias newthread: *pthread_t, noalias at
58pub extern "pthread" fn pthread_attr_init(attr: *pthread_attr_t) c_int;58pub extern "pthread" fn pthread_attr_init(attr: *pthread_attr_t) c_int;
59pub extern "pthread" fn pthread_attr_setstack(attr: *pthread_attr_t, stackaddr: *c_void, stacksize: usize) c_int;59pub extern "pthread" fn pthread_attr_setstack(attr: *pthread_attr_t, stackaddr: *c_void, stacksize: usize) c_int;
60pub extern "pthread" fn pthread_attr_destroy(attr: *pthread_attr_t) c_int;60pub extern "pthread" fn pthread_attr_destroy(attr: *pthread_attr_t) c_int;
61pub extern "pthread" fn pthread_self() pthread_t;
61pub extern "pthread" fn pthread_join(thread: pthread_t, arg_return: ?*?*c_void) c_int;62pub extern "pthread" fn pthread_join(thread: pthread_t, arg_return: ?*?*c_void) c_int;
6263
63pub const pthread_t = *@OpaqueType();64pub const pthread_t = *@OpaqueType();
std/os/index.zig+47-7
...@@ -160,7 +160,7 @@ test "os.getRandomBytes" {...@@ -160,7 +160,7 @@ test "os.getRandomBytes" {
160 try getRandomBytes(buf_b[0..]);160 try getRandomBytes(buf_b[0..]);
161161
162 // Check if random (not 100% conclusive)162 // Check if random (not 100% conclusive)
163 assert( !mem.eql(u8, buf_a, buf_b) );163 assert(!mem.eql(u8, buf_a, buf_b));
164}164}
165165
166/// Raises a signal in the current kernel thread, ending its execution.166/// Raises a signal in the current kernel thread, ending its execution.
...@@ -2516,26 +2516,66 @@ pub const Thread = struct {...@@ -2516,26 +2516,66 @@ pub const Thread = struct {
2516 data: Data,2516 data: Data,
25172517
2518 pub const use_pthreads = is_posix and builtin.link_libc;2518 pub const use_pthreads = is_posix and builtin.link_libc;
2519
2520 /// Represents a kernel thread handle.
2521 /// May be an integer or a pointer depending on the platform.
2522 /// On Linux and POSIX, this is the same as Id.
2523 pub const Handle = if (use_pthreads)
2524 c.pthread_t
2525 else switch (builtin.os) {
2526 builtin.Os.linux => i32,
2527 builtin.Os.windows => windows.HANDLE,
2528 else => @compileError("Unsupported OS"),
2529 };
2530
2531 /// Represents a unique ID per thread.
2532 /// May be an integer or pointer depending on the platform.
2533 /// On Linux and POSIX, this is the same as Handle.
2534 pub const Id = switch (builtin.os) {
2535 builtin.Os.windows => windows.DWORD,
2536 else => Handle,
2537 };
2538
2519 pub const Data = if (use_pthreads)2539 pub const Data = if (use_pthreads)
2520 struct {2540 struct {
2521 handle: c.pthread_t,2541 handle: Thread.Handle,
2522 stack_addr: usize,2542 stack_addr: usize,
2523 stack_len: usize,2543 stack_len: usize,
2524 }2544 }
2525 else switch (builtin.os) {2545 else switch (builtin.os) {
2526 builtin.Os.linux => struct {2546 builtin.Os.linux => struct {
2527 pid: i32,2547 handle: Thread.Handle,
2528 stack_addr: usize,2548 stack_addr: usize,
2529 stack_len: usize,2549 stack_len: usize,
2530 },2550 },
2531 builtin.Os.windows => struct {2551 builtin.Os.windows => struct {
2532 handle: windows.HANDLE,2552 handle: Thread.Handle,
2533 alloc_start: *c_void,2553 alloc_start: *c_void,
2534 heap_handle: windows.HANDLE,2554 heap_handle: windows.HANDLE,
2535 },2555 },
2536 else => @compileError("Unsupported OS"),2556 else => @compileError("Unsupported OS"),
2537 };2557 };
25382558
2559 /// Returns the ID of the calling thread.
2560 /// Makes a syscall every time the function is called.
2561 /// On Linux and POSIX, this Id is the same as a Handle.
2562 pub fn getCurrentId() Id {
2563 if (use_pthreads) {
2564 return c.pthread_self();
2565 } else
2566 return switch (builtin.os) {
2567 builtin.Os.linux => linux.gettid(),
2568 builtin.Os.windows => windows.GetCurrentThreadId(),
2569 else => @compileError("Unsupported OS"),
2570 };
2571 }
2572
2573 /// Returns the handle of this thread.
2574 /// On Linux and POSIX, this is the same as Id.
2575 pub fn handle(self: Thread) Handle {
2576 return self.data.handle;
2577 }
2578
2539 pub fn wait(self: *const Thread) void {2579 pub fn wait(self: *const Thread) void {
2540 if (use_pthreads) {2580 if (use_pthreads) {
2541 const err = c.pthread_join(self.data.handle, null);2581 const err = c.pthread_join(self.data.handle, null);
...@@ -2550,9 +2590,9 @@ pub const Thread = struct {...@@ -2550,9 +2590,9 @@ pub const Thread = struct {
2550 } else switch (builtin.os) {2590 } else switch (builtin.os) {
2551 builtin.Os.linux => {2591 builtin.Os.linux => {
2552 while (true) {2592 while (true) {
2553 const pid_value = @atomicLoad(i32, &self.data.pid, builtin.AtomicOrder.SeqCst);2593 const pid_value = @atomicLoad(i32, &self.data.handle, builtin.AtomicOrder.SeqCst);
2554 if (pid_value == 0) break;2594 if (pid_value == 0) break;
2555 const rc = linux.futex_wait(@ptrToInt(&self.data.pid), linux.FUTEX_WAIT, pid_value, null);2595 const rc = linux.futex_wait(@ptrToInt(&self.data.handle), linux.FUTEX_WAIT, pid_value, null);
2556 switch (linux.getErrno(rc)) {2596 switch (linux.getErrno(rc)) {
2557 0 => continue,2597 0 => continue,
2558 posix.EINTR => continue,2598 posix.EINTR => continue,
...@@ -2734,7 +2774,7 @@ pub fn spawnThread(context: var, comptime startFn: var) SpawnThreadError!*Thread...@@ -2734,7 +2774,7 @@ pub fn spawnThread(context: var, comptime startFn: var) SpawnThreadError!*Thread
2734 // use linux API directly. TODO use posix.CLONE_SETTLS and initialize thread local storage correctly2774 // use linux API directly. TODO use posix.CLONE_SETTLS and initialize thread local storage correctly
2735 const flags = posix.CLONE_VM | posix.CLONE_FS | posix.CLONE_FILES | posix.CLONE_SIGHAND | posix.CLONE_THREAD | posix.CLONE_SYSVSEM | posix.CLONE_PARENT_SETTID | posix.CLONE_CHILD_CLEARTID | posix.CLONE_DETACHED;2775 const flags = posix.CLONE_VM | posix.CLONE_FS | posix.CLONE_FILES | posix.CLONE_SIGHAND | posix.CLONE_THREAD | posix.CLONE_SYSVSEM | posix.CLONE_PARENT_SETTID | posix.CLONE_CHILD_CLEARTID | posix.CLONE_DETACHED;
2736 const newtls: usize = 0;2776 const newtls: usize = 0;
2737 const rc = posix.clone(MainFuncs.linuxThreadMain, stack_end, flags, arg, &thread_ptr.data.pid, newtls, &thread_ptr.data.pid);2777 const rc = posix.clone(MainFuncs.linuxThreadMain, stack_end, flags, arg, &thread_ptr.data.handle, newtls, &thread_ptr.data.handle);
2738 const err = posix.getErrno(rc);2778 const err = posix.getErrno(rc);
2739 switch (err) {2779 switch (err) {
2740 0 => return thread_ptr,2780 0 => return thread_ptr,
std/os/linux/index.zig+4
...@@ -947,6 +947,10 @@ pub fn getpid() i32 {...@@ -947,6 +947,10 @@ pub fn getpid() i32 {
947 return @bitCast(i32, @truncate(u32, syscall0(SYS_getpid)));947 return @bitCast(i32, @truncate(u32, syscall0(SYS_getpid)));
948}948}
949949
950pub fn gettid() i32 {
951 return @bitCast(i32, @truncate(u32, syscall0(SYS_gettid)));
952}
953
950pub fn sigprocmask(flags: u32, noalias set: *const sigset_t, noalias oldset: ?*sigset_t) usize {954pub fn sigprocmask(flags: u32, noalias set: *const sigset_t, noalias oldset: ?*sigset_t) usize {
951 return syscall4(SYS_rt_sigprocmask, flags, @ptrToInt(set), @ptrToInt(oldset), NSIG / 8);955 return syscall4(SYS_rt_sigprocmask, flags, @ptrToInt(set), @ptrToInt(oldset), NSIG / 8);
952}956}
std/os/test.zig+17
...@@ -34,6 +34,23 @@ test "access file" {...@@ -34,6 +34,23 @@ test "access file" {
34 try os.deleteTree(a, "os_test_tmp");34 try os.deleteTree(a, "os_test_tmp");
35}35}
3636
37fn testThreadIdFn(thread_id: *os.Thread.Id) void {
38 thread_id.* = os.Thread.getCurrentId();
39}
40
41test "std.os.Thread.getCurrentId" {
42 var thread_current_id: os.Thread.Id = undefined;
43 const thread = try os.spawnThread(&thread_current_id, testThreadIdFn);
44 const thread_id = thread.handle();
45 thread.wait();
46 switch (builtin.os) {
47 builtin.Os.windows => assert(os.Thread.getCurrentId() != thread_current_id),
48 else => {
49 assert(thread_current_id == thread_id);
50 },
51 }
52}
53
37test "spawn threads" {54test "spawn threads" {
38 var shared_ctx: i32 = 1;55 var shared_ctx: i32 = 1;
3956
std/os/windows/kernel32.zig+3
...@@ -63,6 +63,9 @@ pub extern "kernel32" stdcallcc fn GetConsoleMode(in_hConsoleHandle: HANDLE, out...@@ -63,6 +63,9 @@ pub extern "kernel32" stdcallcc fn GetConsoleMode(in_hConsoleHandle: HANDLE, out
6363
64pub extern "kernel32" stdcallcc fn GetCurrentDirectoryA(nBufferLength: WORD, lpBuffer: ?LPSTR) DWORD;64pub extern "kernel32" stdcallcc fn GetCurrentDirectoryA(nBufferLength: WORD, lpBuffer: ?LPSTR) DWORD;
6565
66pub extern "kernel32" stdcallcc fn GetCurrentThread() HANDLE;
67pub extern "kernel32" stdcallcc fn GetCurrentThreadId() DWORD;
68
66pub extern "kernel32" stdcallcc fn GetEnvironmentStringsA() ?[*]u8;69pub extern "kernel32" stdcallcc fn GetEnvironmentStringsA() ?[*]u8;
6770
68pub extern "kernel32" stdcallcc fn GetEnvironmentVariableA(lpName: LPCSTR, lpBuffer: LPSTR, nSize: DWORD) DWORD;71pub extern "kernel32" stdcallcc fn GetEnvironmentVariableA(lpName: LPCSTR, lpBuffer: LPSTR, nSize: DWORD) DWORD;