Skip to content

Commit b42a332

Browse files
committed
std.Thread(windows): use NT internals for name
1 parent ac26cc8 commit b42a332

File tree

3 files changed

+39
-48
lines changed

3 files changed

+39
-48
lines changed

lib/std/Thread.zig

Lines changed: 39 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
const std = @import("std.zig");
66
const builtin = @import("builtin");
7+
const math = std.math;
78
const os = std.os;
89
const assert = std.debug.assert;
910
const target = builtin.target;
@@ -85,23 +86,28 @@ pub fn setName(self: Thread, name: []const u8) SetNameError!void {
8586

8687
try file.writer().writeAll(name);
8788
},
88-
.windows => if (target.os.isAtLeast(.windows, .win10_rs1)) |res| {
89-
// SetThreadDescription is only available since version 1607, which is 10.0.14393.795
90-
// See https://en.wikipedia.org/wiki/Microsoft_Windows_SDK
91-
if (!res) {
92-
return error.Unsupported;
93-
}
94-
95-
var name_buf_w: [max_name_len:0]u16 = undefined;
96-
const length = try std.unicode.utf8ToUtf16Le(&name_buf_w, name);
97-
name_buf_w[length] = 0;
89+
.windows => {
90+
var buf: [max_name_len]u16 = undefined;
91+
const len = try std.unicode.utf8ToUtf16Le(&buf, name);
92+
const byte_len = math.cast(c_ushort, len * 2) catch return error.NameTooLong;
93+
94+
// Note: The kernel allocates its own copy, no use-after-free here.
95+
const unicode_string = os.windows.UNICODE_STRING{
96+
.Length = byte_len,
97+
.MaximumLength = byte_len,
98+
.Buffer = &buf,
99+
};
98100

99-
try os.windows.SetThreadDescription(
101+
switch (os.windows.ntdll.NtSetInformationThread(
100102
self.getHandle(),
101-
@ptrCast(os.windows.LPWSTR, &name_buf_w),
102-
);
103-
} else {
104-
return error.Unsupported;
103+
.ThreadNameInformation,
104+
&unicode_string,
105+
@sizeOf(os.windows.UNICODE_STRING),
106+
)) {
107+
.SUCCESS => {},
108+
.NOT_IMPLEMENTED => return error.Unsupported,
109+
else => |err| return os.windows.unexpectedStatus(err),
110+
}
105111
},
106112
.macos, .ios, .watchos, .tvos => if (use_pthreads) {
107113
// There doesn't seem to be a way to set the name for an arbitrary thread, only the current one.
@@ -178,22 +184,25 @@ pub fn getName(self: Thread, buffer_ptr: *[max_name_len:0]u8) GetNameError!?[]co
178184
// musl doesn't provide pthread_getname_np and there's no way to retrieve the thread id of an arbitrary thread.
179185
return error.Unsupported;
180186
},
181-
.windows => if (target.os.isAtLeast(.windows, .win10_rs1)) |res| {
182-
// GetThreadDescription is only available since version 1607, which is 10.0.14393.795
183-
// See https://en.wikipedia.org/wiki/Microsoft_Windows_SDK
184-
if (!res) {
185-
return error.Unsupported;
186-
}
187-
188-
var name_w: os.windows.LPWSTR = undefined;
189-
try os.windows.GetThreadDescription(self.getHandle(), &name_w);
190-
defer os.windows.LocalFree(name_w);
187+
.windows => {
188+
const buf_capacity = @sizeOf(os.windows.UNICODE_STRING) + (@sizeOf(u16) * max_name_len);
189+
var buf: [buf_capacity]u8 align(@alignOf(os.windows.UNICODE_STRING)) = undefined;
191190

192-
const data_len = try std.unicode.utf16leToUtf8(buffer, std.mem.sliceTo(name_w, 0));
193-
194-
return if (data_len >= 1) buffer[0..data_len] else null;
195-
} else {
196-
return error.Unsupported;
191+
switch (os.windows.ntdll.NtQueryInformationThread(
192+
self.getHandle(),
193+
.ThreadNameInformation,
194+
&buf,
195+
buf_capacity,
196+
null,
197+
)) {
198+
.SUCCESS => {
199+
const string = @ptrCast(*const os.windows.UNICODE_STRING, &buf);
200+
const len = try std.unicode.utf16leToUtf8(buffer, string.Buffer[0 .. string.Length / 2]);
201+
return if (len > 0) buffer[0..len] else null;
202+
},
203+
.NOT_IMPLEMENTED => return error.Unsupported,
204+
else => |err| return os.windows.unexpectedStatus(err),
205+
}
197206
},
198207
.macos, .ios, .watchos, .tvos => if (use_pthreads) {
199208
const err = std.c.pthread_getname_np(self.getHandle(), buffer.ptr, max_name_len + 1);

lib/std/os/windows.zig

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2015,21 +2015,6 @@ pub fn unexpectedStatus(status: NTSTATUS) std.os.UnexpectedError {
20152015
return error.Unexpected;
20162016
}
20172017

2018-
pub fn SetThreadDescription(hThread: HANDLE, lpThreadDescription: LPCWSTR) !void {
2019-
if (kernel32.SetThreadDescription(hThread, lpThreadDescription) == 0) {
2020-
switch (kernel32.GetLastError()) {
2021-
else => |err| return unexpectedError(err),
2022-
}
2023-
}
2024-
}
2025-
pub fn GetThreadDescription(hThread: HANDLE, ppszThreadDescription: *LPWSTR) !void {
2026-
if (kernel32.GetThreadDescription(hThread, ppszThreadDescription) == 0) {
2027-
switch (kernel32.GetLastError()) {
2028-
else => |err| return unexpectedError(err),
2029-
}
2030-
}
2031-
}
2032-
20332018
pub const Win32Error = @import("windows/win32error.zig").Win32Error;
20342019
pub const NTSTATUS = @import("windows/ntstatus.zig").NTSTATUS;
20352020
pub const LANG = @import("windows/lang.zig");

lib/std/os/windows/kernel32.zig

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -400,6 +400,3 @@ pub extern "kernel32" fn SleepConditionVariableSRW(
400400
pub extern "kernel32" fn TryAcquireSRWLockExclusive(s: *SRWLOCK) callconv(WINAPI) BOOLEAN;
401401
pub extern "kernel32" fn AcquireSRWLockExclusive(s: *SRWLOCK) callconv(WINAPI) void;
402402
pub extern "kernel32" fn ReleaseSRWLockExclusive(s: *SRWLOCK) callconv(WINAPI) void;
403-
404-
pub extern "kernel32" fn SetThreadDescription(hThread: HANDLE, lpThreadDescription: LPCWSTR) callconv(WINAPI) HRESULT;
405-
pub extern "kernel32" fn GetThreadDescription(hThread: HANDLE, ppszThreadDescription: *LPWSTR) callconv(WINAPI) HRESULT;

0 commit comments

Comments
 (0)