Skip to content

Commit cf5009f

Browse files
authored
Merge pull request #10003 from viriuwu/nt-thread-name
std.Thread.getName/setName: rework windows implementation
2 parents 078aa5f + 0bde55e commit cf5009f

File tree

4 files changed

+126
-63
lines changed

4 files changed

+126
-63
lines changed

lib/std/Thread.zig

Lines changed: 39 additions & 23 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;
@@ -86,20 +87,28 @@ pub fn setName(self: Thread, name: []const u8) SetNameError!void {
8687
try file.writer().writeAll(name);
8788
return;
8889
},
89-
.windows => if (target.os.isAtLeast(.windows, .win10_rs1)) |res| {
90-
// SetThreadDescription is only available since version 1607, which is 10.0.14393.795
91-
// See https://en.wikipedia.org/wiki/Microsoft_Windows_SDK
92-
if (!res) return error.Unsupported;
93-
94-
var name_buf_w: [max_name_len:0]u16 = undefined;
95-
const length = try std.unicode.utf8ToUtf16Le(&name_buf_w, name);
96-
name_buf_w[length] = 0;
90+
.windows => {
91+
var buf: [max_name_len]u16 = undefined;
92+
const len = try std.unicode.utf8ToUtf16Le(&buf, name);
93+
const byte_len = math.cast(c_ushort, len * 2) catch return error.NameTooLong;
94+
95+
// Note: NT allocates its own copy, no use-after-free here.
96+
const unicode_string = os.windows.UNICODE_STRING{
97+
.Length = byte_len,
98+
.MaximumLength = byte_len,
99+
.Buffer = &buf,
100+
};
97101

98-
try os.windows.SetThreadDescription(
102+
switch (os.windows.ntdll.NtSetInformationThread(
99103
self.getHandle(),
100-
@ptrCast(os.windows.LPWSTR, &name_buf_w),
101-
);
102-
return;
104+
.ThreadNameInformation,
105+
&unicode_string,
106+
@sizeOf(os.windows.UNICODE_STRING),
107+
)) {
108+
.SUCCESS => return,
109+
.NOT_IMPLEMENTED => return error.Unsupported,
110+
else => |err| return os.windows.unexpectedStatus(err),
111+
}
103112
},
104113
.macos, .ios, .watchos, .tvos => if (use_pthreads) {
105114
// There doesn't seem to be a way to set the name for an arbitrary thread, only the current one.
@@ -189,18 +198,25 @@ pub fn getName(self: Thread, buffer_ptr: *[max_name_len:0]u8) GetNameError!?[]co
189198
// musl doesn't provide pthread_getname_np and there's no way to retrieve the thread id of an arbitrary thread.
190199
return error.Unsupported;
191200
},
192-
.windows => if (target.os.isAtLeast(.windows, .win10_rs1)) |res| {
193-
// GetThreadDescription is only available since version 1607, which is 10.0.14393.795
194-
// See https://en.wikipedia.org/wiki/Microsoft_Windows_SDK
195-
if (!res) return error.Unsupported;
196-
197-
var name_w: os.windows.LPWSTR = undefined;
198-
try os.windows.GetThreadDescription(self.getHandle(), &name_w);
199-
defer os.windows.LocalFree(name_w);
201+
.windows => {
202+
const buf_capacity = @sizeOf(os.windows.UNICODE_STRING) + (@sizeOf(u16) * max_name_len);
203+
var buf: [buf_capacity]u8 align(@alignOf(os.windows.UNICODE_STRING)) = undefined;
200204

201-
const data_len = try std.unicode.utf16leToUtf8(buffer, std.mem.sliceTo(name_w, 0));
202-
203-
return if (data_len >= 1) buffer[0..data_len] else null;
205+
switch (os.windows.ntdll.NtQueryInformationThread(
206+
self.getHandle(),
207+
.ThreadNameInformation,
208+
&buf,
209+
buf_capacity,
210+
null,
211+
)) {
212+
.SUCCESS => {
213+
const string = @ptrCast(*const os.windows.UNICODE_STRING, &buf);
214+
const len = try std.unicode.utf16leToUtf8(buffer, string.Buffer[0 .. string.Length / 2]);
215+
return if (len > 0) buffer[0..len] else null;
216+
},
217+
.NOT_IMPLEMENTED => return error.Unsupported,
218+
else => |err| return os.windows.unexpectedStatus(err),
219+
}
204220
},
205221
.macos, .ios, .watchos, .tvos => if (use_pthreads) {
206222
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
@@ -2042,21 +2042,6 @@ pub fn unexpectedStatus(status: NTSTATUS) std.os.UnexpectedError {
20422042
return error.Unexpected;
20432043
}
20442044

2045-
pub fn SetThreadDescription(hThread: HANDLE, lpThreadDescription: LPCWSTR) !void {
2046-
if (kernel32.SetThreadDescription(hThread, lpThreadDescription) == 0) {
2047-
switch (kernel32.GetLastError()) {
2048-
else => |err| return unexpectedError(err),
2049-
}
2050-
}
2051-
}
2052-
pub fn GetThreadDescription(hThread: HANDLE, ppszThreadDescription: *LPWSTR) !void {
2053-
if (kernel32.GetThreadDescription(hThread, ppszThreadDescription) == 0) {
2054-
switch (kernel32.GetLastError()) {
2055-
else => |err| return unexpectedError(err),
2056-
}
2057-
}
2058-
}
2059-
20602045
pub const Win32Error = @import("windows/win32error.zig").Win32Error;
20612046
pub const NTSTATUS = @import("windows/ntstatus.zig").NTSTATUS;
20622047
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
@@ -402,6 +402,3 @@ pub extern "kernel32" fn SleepConditionVariableSRW(
402402
pub extern "kernel32" fn TryAcquireSRWLockExclusive(s: *SRWLOCK) callconv(WINAPI) BOOLEAN;
403403
pub extern "kernel32" fn AcquireSRWLockExclusive(s: *SRWLOCK) callconv(WINAPI) void;
404404
pub extern "kernel32" fn ReleaseSRWLockExclusive(s: *SRWLOCK) callconv(WINAPI) void;
405-
406-
pub extern "kernel32" fn SetThreadDescription(hThread: HANDLE, lpThreadDescription: LPCWSTR) callconv(WINAPI) HRESULT;
407-
pub extern "kernel32" fn GetThreadDescription(hThread: HANDLE, ppszThreadDescription: *LPWSTR) callconv(WINAPI) HRESULT;

lib/std/os/windows/ntdll.zig

Lines changed: 87 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -23,36 +23,101 @@ const FILE_BASIC_INFORMATION = windows.FILE_BASIC_INFORMATION;
2323
const SIZE_T = windows.SIZE_T;
2424
const CURDIR = windows.CURDIR;
2525

26-
pub extern "NtDll" fn RtlGetVersion(
26+
pub const THREADINFOCLASS = enum(c_int) {
27+
ThreadBasicInformation,
28+
ThreadTimes,
29+
ThreadPriority,
30+
ThreadBasePriority,
31+
ThreadAffinityMask,
32+
ThreadImpersonationToken,
33+
ThreadDescriptorTableEntry,
34+
ThreadEnableAlignmentFaultFixup,
35+
ThreadEventPair_Reusable,
36+
ThreadQuerySetWin32StartAddress,
37+
ThreadZeroTlsCell,
38+
ThreadPerformanceCount,
39+
ThreadAmILastThread,
40+
ThreadIdealProcessor,
41+
ThreadPriorityBoost,
42+
ThreadSetTlsArrayAddress,
43+
ThreadIsIoPending,
44+
// Windows 2000+ from here
45+
ThreadHideFromDebugger,
46+
// Windows XP+ from here
47+
ThreadBreakOnTermination,
48+
ThreadSwitchLegacyState,
49+
ThreadIsTerminated,
50+
// Windows Vista+ from here
51+
ThreadLastSystemCall,
52+
ThreadIoPriority,
53+
ThreadCycleTime,
54+
ThreadPagePriority,
55+
ThreadActualBasePriority,
56+
ThreadTebInformation,
57+
ThreadCSwitchMon,
58+
// Windows 7+ from here
59+
ThreadCSwitchPmu,
60+
ThreadWow64Context,
61+
ThreadGroupInformation,
62+
ThreadUmsInformation,
63+
ThreadCounterProfiling,
64+
ThreadIdealProcessorEx,
65+
// Windows 8+ from here
66+
ThreadCpuAccountingInformation,
67+
// Windows 8.1+ from here
68+
ThreadSuspendCount,
69+
// Windows 10+ from here
70+
ThreadHeterogeneousCpuPolicy,
71+
ThreadContainerId,
72+
ThreadNameInformation,
73+
ThreadSelectedCpuSets,
74+
ThreadSystemThreadInformation,
75+
ThreadActualGroupAffinity,
76+
};
77+
pub extern "ntdll" fn NtQueryInformationThread(
78+
ThreadHandle: HANDLE,
79+
ThreadInformationClass: THREADINFOCLASS,
80+
ThreadInformation: *anyopaque,
81+
ThreadInformationLength: ULONG,
82+
ReturnLength: ?*ULONG,
83+
) callconv(WINAPI) NTSTATUS;
84+
pub extern "ntdll" fn NtSetInformationThread(
85+
ThreadHandle: HANDLE,
86+
ThreadInformationClass: THREADINFOCLASS,
87+
ThreadInformation: *const anyopaque,
88+
ThreadInformationLength: ULONG,
89+
) callconv(WINAPI) NTSTATUS;
90+
91+
pub extern "ntdll" fn RtlGetVersion(
2792
lpVersionInformation: *RTL_OSVERSIONINFOW,
2893
) callconv(WINAPI) NTSTATUS;
29-
pub extern "NtDll" fn RtlCaptureStackBackTrace(
94+
pub extern "ntdll" fn RtlCaptureStackBackTrace(
3095
FramesToSkip: DWORD,
3196
FramesToCapture: DWORD,
3297
BackTrace: **anyopaque,
3398
BackTraceHash: ?*DWORD,
3499
) callconv(WINAPI) WORD;
35-
pub extern "NtDll" fn NtQueryInformationFile(
100+
pub extern "ntdll" fn NtQueryInformationFile(
36101
FileHandle: HANDLE,
37102
IoStatusBlock: *IO_STATUS_BLOCK,
38103
FileInformation: *anyopaque,
39104
Length: ULONG,
40105
FileInformationClass: FILE_INFORMATION_CLASS,
41106
) callconv(WINAPI) NTSTATUS;
42-
pub extern "NtDll" fn NtSetInformationFile(
107+
pub extern "ntdll" fn NtSetInformationFile(
43108
FileHandle: HANDLE,
44109
IoStatusBlock: *IO_STATUS_BLOCK,
45110
FileInformation: PVOID,
46111
Length: ULONG,
47112
FileInformationClass: FILE_INFORMATION_CLASS,
48113
) callconv(WINAPI) NTSTATUS;
49114

50-
pub extern "NtDll" fn NtQueryAttributesFile(
115+
pub extern "ntdll" fn NtQueryAttributesFile(
51116
ObjectAttributes: *OBJECT_ATTRIBUTES,
52117
FileAttributes: *FILE_BASIC_INFORMATION,
53118
) callconv(WINAPI) NTSTATUS;
54119

55-
pub extern "NtDll" fn NtCreateFile(
120+
pub extern "ntdll" fn NtCreateFile(
56121
FileHandle: *HANDLE,
57122
DesiredAccess: ACCESS_MASK,
58123
ObjectAttributes: *OBJECT_ATTRIBUTES,
@@ -65,7 +130,7 @@ pub extern "NtDll" fn NtCreateFile(
65130
EaBuffer: ?*anyopaque,
66131
EaLength: ULONG,
67132
) callconv(WINAPI) NTSTATUS;
68-
pub extern "NtDll" fn NtDeviceIoControlFile(
133+
pub extern "ntdll" fn NtDeviceIoControlFile(
69134
FileHandle: HANDLE,
70135
Event: ?HANDLE,
71136
ApcRoutine: ?IO_APC_ROUTINE,
@@ -77,7 +142,7 @@ pub extern "NtDll" fn NtDeviceIoControlFile(
77142
OutputBuffer: ?PVOID,
78143
OutputBufferLength: ULONG,
79144
) callconv(WINAPI) NTSTATUS;
80-
pub extern "NtDll" fn NtFsControlFile(
145+
pub extern "ntdll" fn NtFsControlFile(
81146
FileHandle: HANDLE,
82147
Event: ?HANDLE,
83148
ApcRoutine: ?IO_APC_ROUTINE,
@@ -89,16 +154,16 @@ pub extern "NtDll" fn NtFsControlFile(
89154
OutputBuffer: ?PVOID,
90155
OutputBufferLength: ULONG,
91156
) callconv(WINAPI) NTSTATUS;
92-
pub extern "NtDll" fn NtClose(Handle: HANDLE) callconv(WINAPI) NTSTATUS;
93-
pub extern "NtDll" fn RtlDosPathNameToNtPathName_U(
157+
pub extern "ntdll" fn NtClose(Handle: HANDLE) callconv(WINAPI) NTSTATUS;
158+
pub extern "ntdll" fn RtlDosPathNameToNtPathName_U(
94159
DosPathName: [*:0]const u16,
95160
NtPathName: *UNICODE_STRING,
96161
NtFileNamePart: ?*?[*:0]const u16,
97162
DirectoryInfo: ?*CURDIR,
98163
) callconv(WINAPI) BOOL;
99-
pub extern "NtDll" fn RtlFreeUnicodeString(UnicodeString: *UNICODE_STRING) callconv(WINAPI) void;
164+
pub extern "ntdll" fn RtlFreeUnicodeString(UnicodeString: *UNICODE_STRING) callconv(WINAPI) void;
100165

101-
pub extern "NtDll" fn NtQueryDirectoryFile(
166+
pub extern "ntdll" fn NtQueryDirectoryFile(
102167
FileHandle: HANDLE,
103168
Event: ?HANDLE,
104169
ApcRoutine: ?IO_APC_ROUTINE,
@@ -112,53 +177,53 @@ pub extern "NtDll" fn NtQueryDirectoryFile(
112177
RestartScan: BOOLEAN,
113178
) callconv(WINAPI) NTSTATUS;
114179

115-
pub extern "NtDll" fn NtCreateKeyedEvent(
180+
pub extern "ntdll" fn NtCreateKeyedEvent(
116181
KeyedEventHandle: *HANDLE,
117182
DesiredAccess: ACCESS_MASK,
118183
ObjectAttributes: ?PVOID,
119184
Flags: ULONG,
120185
) callconv(WINAPI) NTSTATUS;
121186

122-
pub extern "NtDll" fn NtReleaseKeyedEvent(
187+
pub extern "ntdll" fn NtReleaseKeyedEvent(
123188
EventHandle: ?HANDLE,
124189
Key: ?*const anyopaque,
125190
Alertable: BOOLEAN,
126191
Timeout: ?*const LARGE_INTEGER,
127192
) callconv(WINAPI) NTSTATUS;
128193

129-
pub extern "NtDll" fn NtWaitForKeyedEvent(
194+
pub extern "ntdll" fn NtWaitForKeyedEvent(
130195
EventHandle: ?HANDLE,
131196
Key: ?*const anyopaque,
132197
Alertable: BOOLEAN,
133198
Timeout: ?*const LARGE_INTEGER,
134199
) callconv(WINAPI) NTSTATUS;
135200

136-
pub extern "NtDll" fn RtlSetCurrentDirectory_U(PathName: *UNICODE_STRING) callconv(WINAPI) NTSTATUS;
201+
pub extern "ntdll" fn RtlSetCurrentDirectory_U(PathName: *UNICODE_STRING) callconv(WINAPI) NTSTATUS;
137202

138-
pub extern "NtDll" fn NtQueryObject(
203+
pub extern "ntdll" fn NtQueryObject(
139204
Handle: HANDLE,
140205
ObjectInformationClass: OBJECT_INFORMATION_CLASS,
141206
ObjectInformation: PVOID,
142207
ObjectInformationLength: ULONG,
143208
ReturnLength: ?*ULONG,
144209
) callconv(WINAPI) NTSTATUS;
145210

146-
pub extern "NtDll" fn RtlWakeAddressAll(
211+
pub extern "ntdll" fn RtlWakeAddressAll(
147212
Address: ?*const anyopaque,
148213
) callconv(WINAPI) void;
149214

150-
pub extern "NtDll" fn RtlWakeAddressSingle(
215+
pub extern "ntdll" fn RtlWakeAddressSingle(
151216
Address: ?*const anyopaque,
152217
) callconv(WINAPI) void;
153218

154-
pub extern "NtDll" fn RtlWaitOnAddress(
219+
pub extern "ntdll" fn RtlWaitOnAddress(
155220
Address: ?*const anyopaque,
156221
CompareAddress: ?*const anyopaque,
157222
AddressSize: SIZE_T,
158223
Timeout: ?*const LARGE_INTEGER,
159224
) callconv(WINAPI) NTSTATUS;
160225

161-
pub extern "NtDll" fn NtLockFile(
226+
pub extern "ntdll" fn NtLockFile(
162227
FileHandle: HANDLE,
163228
Event: ?HANDLE,
164229
ApcRoutine: ?*IO_APC_ROUTINE,
@@ -171,7 +236,7 @@ pub extern "NtDll" fn NtLockFile(
171236
ExclusiveLock: BOOLEAN,
172237
) callconv(WINAPI) NTSTATUS;
173238

174-
pub extern "NtDll" fn NtUnlockFile(
239+
pub extern "ntdll" fn NtUnlockFile(
175240
FileHandle: HANDLE,
176241
IoStatusBlock: *IO_STATUS_BLOCK,
177242
ByteOffset: *const LARGE_INTEGER,

0 commit comments

Comments
 (0)