Commit 86d1cc8e2f

Matthew D. Steele <mdsteele@alum.mit.edu>
2018-08-02 23:44:20
Add thread ID support to std.os.Thread (fixes #1316)
1 parent 9bd8b01
Changed files (4)
std/c/index.zig
@@ -58,6 +58,7 @@ pub extern "pthread" fn pthread_create(noalias newthread: *pthread_t, noalias at
 pub extern "pthread" fn pthread_attr_init(attr: *pthread_attr_t) c_int;
 pub extern "pthread" fn pthread_attr_setstack(attr: *pthread_attr_t, stackaddr: *c_void, stacksize: usize) c_int;
 pub extern "pthread" fn pthread_attr_destroy(attr: *pthread_attr_t) c_int;
+pub extern "pthread" fn pthread_self() pthread_t;
 pub extern "pthread" fn pthread_join(thread: pthread_t, arg_return: ?*?*c_void) c_int;
 
 pub const pthread_t = *@OpaqueType();
std/os/windows/kernel32.zig
@@ -63,6 +63,8 @@ pub extern "kernel32" stdcallcc fn GetConsoleMode(in_hConsoleHandle: HANDLE, out
 
 pub extern "kernel32" stdcallcc fn GetCurrentDirectoryA(nBufferLength: WORD, lpBuffer: ?LPSTR) DWORD;
 
+pub extern "kernel32" stdcallcc fn GetCurrentThread() HANDLE;
+
 pub extern "kernel32" stdcallcc fn GetEnvironmentStringsA() ?[*]u8;
 
 pub extern "kernel32" stdcallcc fn GetEnvironmentVariableA(lpName: LPCSTR, lpBuffer: LPSTR, nSize: DWORD) DWORD;
std/os/index.zig
@@ -2516,6 +2516,10 @@ pub const Thread = struct {
     data: Data,
 
     pub const use_pthreads = is_posix and builtin.link_libc;
+
+    /// An opaque type representing a kernel thread ID.
+    pub const Id = *@OpaqueType();
+
     pub const Data = if (use_pthreads)
         struct {
             handle: c.pthread_t,
@@ -2536,6 +2540,35 @@ pub const Thread = struct {
         else => @compileError("Unsupported OS"),
     };
 
+    /// Returns the ID of the calling thread.
+    pub fn currentId() Thread.Id {
+        // TODO: As-is, this function is potentially expensive (making a
+        // syscall on every call).  Once we have support for thread-local
+        // storage (https://github.com/ziglang/zig/issues/924), we could
+        // memoize it.
+        if (use_pthreads) {
+            return @ptrCast(Thread.Id, c.pthread_self());
+        } else return switch (builtin.os) {
+            builtin.Os.linux =>
+                @intToPtr(Thread.Id, @bitCast(u32, linux.getpid())),
+            builtin.Os.windows =>
+                @ptrCast(Thread.Id, windows.GetCurrentThread()),
+            else => @compileError("Unsupported OS"),
+        };
+    }
+
+    /// Returns the ID of this thread object.
+    pub fn id(self: *const Thread) Thread.Id {
+        if (use_pthreads) {
+            return @ptrCast(Thread.Id, self.data.handle);
+        } else return switch (builtin.os) {
+            builtin.Os.linux =>
+                @intToPtr(Thread.Id, @bitCast(u32, self.data.pid)),
+            builtin.Os.windows => @ptrCast(Thread.Id, self.data.handle),
+            else => @compileError("Unsupported OS"),
+        };
+    }
+
     pub fn wait(self: *const Thread) void {
         if (use_pthreads) {
             const err = c.pthread_join(self.data.handle, null);
std/os/test.zig
@@ -34,6 +34,18 @@ test "access file" {
     try os.deleteTree(a, "os_test_tmp");
 }
 
+fn testThreadIdFn(threadId: *?os.Thread.Id) void {
+    threadId.* = os.Thread.currentId();
+}
+
+test "std.os.Thread.currentId" {
+    var threadCurrentId: ?os.Thread.Id = null;
+    const thread = try os.spawnThread(&threadCurrentId, testThreadIdFn);
+    const threadId = thread.id();
+    thread.wait();
+    assert(threadCurrentId == threadId);
+}
+
 test "spawn threads" {
     var shared_ctx: i32 = 1;