authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-08-06 16:12:37-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-08-06 16:12:37-04:00
log647fd0f4f1f99bc5bb7783cfc293e026974207c5
tree267afddfbebed33a4742246e6a17768acc8fa663
parent72bac72338af64a73668721cd035dfdf1ff2badb
parent7a2401ef1eca3446279469b092e6f9c9653e38f8

Merge branch 'threadid' of https://github.com/mdsteele/zig into mdsteele-threadid


4 files changed, 51 insertions(+), 6 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+36-6
...@@ -2516,26 +2516,56 @@ pub const Thread = struct {...@@ -2516,26 +2516,56 @@ 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 /// An type representing a kernel thread ID.
2521 pub const Id = if (use_pthreads)
2522 c.pthread_t
2523 else switch (builtin.os) {
2524 builtin.Os.linux => i32,
2525 builtin.Os.windows => windows.HANDLE,
2526 else => @compileError("Unsupported OS"),
2527 };
2528
2519 pub const Data = if (use_pthreads)2529 pub const Data = if (use_pthreads)
2520 struct {2530 struct {
2521 handle: c.pthread_t,2531 handle: Thread.Id,
2522 stack_addr: usize,2532 stack_addr: usize,
2523 stack_len: usize,2533 stack_len: usize,
2524 }2534 }
2525 else switch (builtin.os) {2535 else switch (builtin.os) {
2526 builtin.Os.linux => struct {2536 builtin.Os.linux => struct {
2527 pid: i32,2537 handle: Thread.Id,
2528 stack_addr: usize,2538 stack_addr: usize,
2529 stack_len: usize,2539 stack_len: usize,
2530 },2540 },
2531 builtin.Os.windows => struct {2541 builtin.Os.windows => struct {
2532 handle: windows.HANDLE,2542 handle: Thread.Id,
2533 alloc_start: *c_void,2543 alloc_start: *c_void,
2534 heap_handle: windows.HANDLE,2544 heap_handle: windows.HANDLE,
2535 },2545 },
2536 else => @compileError("Unsupported OS"),2546 else => @compileError("Unsupported OS"),
2537 };2547 };
25382548
2549 /// Returns the ID of the calling thread.
2550 pub fn currentId() Thread.Id {
2551 // TODO: As-is, this function is potentially expensive (making a
2552 // syscall on every call). Once we have support for thread-local
2553 // storage (https://github.com/ziglang/zig/issues/924), we could
2554 // memoize it.
2555 if (use_pthreads) {
2556 return c.pthread_self();
2557 } else return switch (builtin.os) {
2558 builtin.Os.linux => linux.getpid(),
2559 builtin.Os.windows => windows.GetCurrentThread(),
2560 else => @compileError("Unsupported OS"),
2561 };
2562 }
2563
2564 /// Returns the ID of this thread.
2565 pub fn id(self: *const Thread) Thread.Id {
2566 return self.data.handle;
2567 }
2568
2539 pub fn wait(self: *const Thread) void {2569 pub fn wait(self: *const Thread) void {
2540 if (use_pthreads) {2570 if (use_pthreads) {
2541 const err = c.pthread_join(self.data.handle, null);2571 const err = c.pthread_join(self.data.handle, null);
...@@ -2550,9 +2580,9 @@ pub const Thread = struct {...@@ -2550,9 +2580,9 @@ pub const Thread = struct {
2550 } else switch (builtin.os) {2580 } else switch (builtin.os) {
2551 builtin.Os.linux => {2581 builtin.Os.linux => {
2552 while (true) {2582 while (true) {
2553 const pid_value = @atomicLoad(i32, &self.data.pid, builtin.AtomicOrder.SeqCst);2583 const pid_value = @atomicLoad(i32, &self.data.handle, builtin.AtomicOrder.SeqCst);
2554 if (pid_value == 0) break;2584 if (pid_value == 0) break;
2555 const rc = linux.futex_wait(@ptrToInt(&self.data.pid), linux.FUTEX_WAIT, pid_value, null);2585 const rc = linux.futex_wait(@ptrToInt(&self.data.handle), linux.FUTEX_WAIT, pid_value, null);
2556 switch (linux.getErrno(rc)) {2586 switch (linux.getErrno(rc)) {
2557 0 => continue,2587 0 => continue,
2558 posix.EINTR => continue,2588 posix.EINTR => continue,
...@@ -2734,7 +2764,7 @@ pub fn spawnThread(context: var, comptime startFn: var) SpawnThreadError!*Thread...@@ -2734,7 +2764,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 correctly2764 // 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;2765 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;2766 const newtls: usize = 0;
2737 const rc = posix.clone(MainFuncs.linuxThreadMain, stack_end, flags, arg, &thread_ptr.data.pid, newtls, &thread_ptr.data.pid);2767 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);2768 const err = posix.getErrno(rc);
2739 switch (err) {2769 switch (err) {
2740 0 => return thread_ptr,2770 0 => return thread_ptr,
std/os/test.zig+12
...@@ -34,6 +34,18 @@ test "access file" {...@@ -34,6 +34,18 @@ test "access file" {
34 try os.deleteTree(a, "os_test_tmp");34 try os.deleteTree(a, "os_test_tmp");
35}35}
3636
37fn testThreadIdFn(threadId: *os.Thread.Id) void {
38 threadId.* = os.Thread.currentId();
39}
40
41test "std.os.Thread.currentId" {
42 var threadCurrentId: os.Thread.Id = undefined;
43 const thread = try os.spawnThread(&threadCurrentId, testThreadIdFn);
44 const threadId = thread.id();
45 thread.wait();
46 assert(threadCurrentId == threadId);
47}
48
37test "spawn threads" {49test "spawn threads" {
38 var shared_ctx: i32 = 1;50 var shared_ctx: i32 = 1;
3951
std/os/windows/kernel32.zig+2
...@@ -63,6 +63,8 @@ pub extern "kernel32" stdcallcc fn GetConsoleMode(in_hConsoleHandle: HANDLE, out...@@ -63,6 +63,8 @@ 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;
67
66pub extern "kernel32" stdcallcc fn GetEnvironmentStringsA() ?[*]u8;68pub extern "kernel32" stdcallcc fn GetEnvironmentStringsA() ?[*]u8;
6769
68pub extern "kernel32" stdcallcc fn GetEnvironmentVariableA(lpName: LPCSTR, lpBuffer: LPSTR, nSize: DWORD) DWORD;70pub extern "kernel32" stdcallcc fn GetEnvironmentVariableA(lpName: LPCSTR, lpBuffer: LPSTR, nSize: DWORD) DWORD;