Skip to content

Commit 536f4b8

Browse files
authored
Merge pull request #1856 from compnerd/thread-the-needle
2 parents 5515b06 + f5fb8fe commit 536f4b8

File tree

4 files changed

+126
-9
lines changed

4 files changed

+126
-9
lines changed

CoreFoundation/Base.subproj/CFPlatform.c

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1359,9 +1359,20 @@ void _CFThreadSpecificSet(_CFThreadSpecificKey key, CFTypeRef _Nullable value) {
13591359

13601360
_CFThreadRef _CFThreadCreate(const _CFThreadAttributes attrs, void *_Nullable (* _Nonnull startfn)(void *_Nullable), void *_CF_RESTRICT _Nullable context) {
13611361
#if DEPLOYMENT_TARGET_WINDOWS
1362-
return (_CFThreadRef)_beginthreadex(NULL, 0,
1362+
DWORD dwCreationFlags = 0;
1363+
DWORD dwStackSize = 0;
1364+
if (attrs.dwSizeOfAttributes >=
1365+
offsetof(struct _CFThreadAttributes,
1366+
dwThreadStackReservation) + sizeof(dwStackSize)) {
1367+
dwStackSize = attrs.dwThreadStackReservation;
1368+
if (dwStackSize) {
1369+
dwCreationFlags |= STACK_SIZE_PARAM_IS_A_RESERVATION;
1370+
}
1371+
}
1372+
1373+
return (_CFThreadRef)_beginthreadex(NULL, dwStackSize,
13631374
(_beginthreadex_proc_type)startfn,
1364-
context, 0, NULL);
1375+
context, dwCreationFlags, NULL);
13651376
#else
13661377
_CFThreadRef thread;
13671378
pthread_create(&thread, &attrs, startfn, context);

CoreFoundation/Base.subproj/ForSwiftFoundationOnly.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -347,7 +347,10 @@ CF_EXPORT void CFLog1(CFLogLevel lev, CFStringRef message);
347347

348348
#if DEPLOYMENT_TARGET_WINDOWS
349349
typedef HANDLE _CFThreadRef;
350-
typedef DWORD _CFThreadAttributes;
350+
typedef struct _CFThreadAttributes {
351+
DWORD dwSizeOfAttributes;
352+
DWORD dwThreadStackReservation;
353+
} _CFThreadAttributes;
351354
typedef DWORD _CFThreadSpecificKey;
352355
#elif _POSIX_THREADS
353356
typedef pthread_t _CFThreadRef;

Foundation/NSLock.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ extension NSLock {
133133
open class NSConditionLock : NSObject, NSLocking {
134134
internal var _cond = NSCondition()
135135
internal var _value: Int
136-
internal var _thread: _CFThreadRef?
136+
internal var _thread: _swift_CFThreadRef?
137137

138138
public convenience override init() {
139139
self.init(condition: 0)

Foundation/Thread.swift

Lines changed: 108 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,13 @@
99

1010
import CoreFoundation
1111

12+
// WORKAROUND_SR9811
13+
#if os(Windows)
14+
internal typealias _swift_CFThreadRef = HANDLE
15+
#else
16+
internal typealias _swift_CFThreadRef = pthread_t
17+
#endif
18+
1219
internal class NSThreadSpecific<T: NSObject> {
1320
private var key = _CFThreadSpecificKeyCreate()
1421

@@ -38,7 +45,11 @@ private func NSThreadStart(_ context: UnsafeMutableRawPointer?) -> UnsafeMutable
3845
let thread: Thread = NSObject.unretainedReference(context!)
3946
Thread._currentThread.set(thread)
4047
if let name = thread.name {
48+
#if os(Windows)
49+
_CFThreadSetName(GetCurrentThread(), name)
50+
#else
4151
_CFThreadSetName(pthread_self(), name)
52+
#endif
4253
}
4354
thread._status = .executing
4455
thread.main()
@@ -55,7 +66,11 @@ open class Thread : NSObject {
5566
if Thread.isMainThread {
5667
return mainThread
5768
} else {
69+
#if os(Windows)
70+
return Thread(thread: GetCurrentThread())
71+
#else
5872
return Thread(thread: pthread_self())
73+
#endif
5974
}
6075
}
6176
}
@@ -89,6 +104,19 @@ open class Thread : NSObject {
89104
}
90105

91106
open class func sleep(until date: Date) {
107+
#if os(Windows)
108+
var hTimer: HANDLE = CreateWaitableTimerW(nil, TRUE, nil)
109+
// FIXME(compnerd) how to check that hTimer is not NULL?
110+
defer { CloseHandle(hTimer) }
111+
112+
// the timeout is in 100ns units
113+
var liTimeout: LARGE_INTEGER =
114+
LARGE_INTEGER(QuadPart: LONGLONG(date.timeIntervalSinceReferenceDate) * -10000000)
115+
if SetWaitableTimer(hTimer, &liTimeout, 0, nil, nil, FALSE) == FALSE {
116+
return
117+
}
118+
WaitForSingleObject(hTimer, WinSDK.INFINITE)
119+
#else
92120
let start_ut = CFGetSystemUptime()
93121
let start_at = CFAbsoluteTimeGetCurrent()
94122
let end_at = date.timeIntervalSinceReferenceDate
@@ -109,9 +137,23 @@ open class Thread : NSObject {
109137
}
110138
ti = end_ut - CFGetSystemUptime()
111139
}
140+
#endif
112141
}
113142

114143
open class func sleep(forTimeInterval interval: TimeInterval) {
144+
#if os(Windows)
145+
var hTimer: HANDLE = CreateWaitableTimerW(nil, TRUE, nil)
146+
// FIXME(compnerd) how to check that hTimer is not NULL?
147+
defer { CloseHandle(hTimer) }
148+
149+
// the timeout is in 100ns units
150+
var liTimeout: LARGE_INTEGER =
151+
LARGE_INTEGER(QuadPart: LONGLONG(interval) * -10000000)
152+
if SetWaitableTimer(hTimer, &liTimeout, 0, nil, nil, FALSE) == FALSE {
153+
return
154+
}
155+
WaitForSingleObject(hTimer, WinSDK.INFINITE)
156+
#else
115157
var ti = interval
116158
let start_ut = CFGetSystemUptime()
117159
let end_ut = start_ut + ti
@@ -130,37 +172,48 @@ open class Thread : NSObject {
130172
}
131173
ti = end_ut - CFGetSystemUptime()
132174
}
175+
#endif
133176
}
134177

135178
open class func exit() {
136179
Thread.current._status = .finished
180+
#if os(Windows)
181+
ExitThread(0)
182+
#else
137183
pthread_exit(nil)
184+
#endif
138185
}
139186

140187
internal var _main: () -> Void = {}
141-
private var _thread: pthread_t? = nil
188+
private var _thread: _swift_CFThreadRef? = nil
142189

143-
#if CYGWIN
190+
#if os(Windows) && !CYGWIN
191+
internal var _attr: _CFThreadAttributes =
192+
_CFThreadAttributes(dwSizeOfAttributes: MemoryLayout<_CFThreadAttributes>.size,
193+
dwThreadStackReservation: 0)
194+
#elseif CYGWIN
144195
internal var _attr : pthread_attr_t? = nil
145196
#else
146197
internal var _attr = pthread_attr_t()
147198
#endif
148199
internal var _status = _NSThreadStatus.initialized
149200
internal var _cancelled = false
150-
201+
151202
open private(set) var threadDictionary: NSMutableDictionary = NSMutableDictionary()
152203

153-
internal init(thread: pthread_t) {
154-
// Note: even on Darwin this is a non-optional pthread_t; this is only used for valid threads, which are never null pointers.
204+
internal init(thread: _swift_CFThreadRef) {
205+
// Note: even on Darwin this is a non-optional _CFThreadRef; this is only used for valid threads, which are never null pointers.
155206
_thread = thread
156207
}
157208

158209
public override init() {
210+
#if !os(Windows)
159211
let _ = withUnsafeMutablePointer(to: &_attr) { attr in
160212
pthread_attr_init(attr)
161213
pthread_attr_setscope(attr, Int32(PTHREAD_SCOPE_SYSTEM))
162214
pthread_attr_setdetachstate(attr, Int32(PTHREAD_CREATE_DETACHED))
163215
}
216+
#endif
164217
}
165218

166219
public convenience init(block: @escaping () -> Swift.Void) {
@@ -202,6 +255,19 @@ open class Thread : NSObject {
202255
}
203256
}
204257

258+
#if os(Windows)
259+
open var stackSize: Int {
260+
get {
261+
var ulLowLimit: ULONG_PTR = 0
262+
var ulHighLimit: ULONG_PTR = 0
263+
GetCurrentThreadStackLimits(&ulLowLimit, &ulHighLimit)
264+
return Int(ulLowLimit)
265+
}
266+
set {
267+
_attr.dwThreadStackReservation = newValue
268+
}
269+
}
270+
#else
205271
open var stackSize: Int {
206272
get {
207273
var size: Int = 0
@@ -223,6 +289,7 @@ open class Thread : NSObject {
223289
}
224290
}
225291
}
292+
#endif
226293

227294
open var isExecuting: Bool {
228295
return _status == .executing
@@ -252,6 +319,9 @@ open class Thread : NSObject {
252319
defer { addrs.deallocate() }
253320
#if os(Android)
254321
let count = 0
322+
#elseif os(Windows)
323+
let count = RtlCaptureStackBackTrace(0, DWORD(maxSupportedStackDepth),
324+
addrs, nil)
255325
#else
256326
let count = backtrace(addrs, Int32(maxSupportedStackDepth))
257327
#endif
@@ -270,6 +340,39 @@ open class Thread : NSObject {
270340
open class var callStackSymbols: [String] {
271341
#if os(Android)
272342
return []
343+
#elseif os(Windows)
344+
let hProcess: HANDLE = GetCurrentProcess()
345+
SymSetOptions(DWORD(SYMOPT_UNDNAME | SYMOPT_DEFERRED_LOADS))
346+
if SymInitializeW(hProcess, nil, TRUE) == FALSE {
347+
return []
348+
}
349+
return backtraceAddresses { (addresses, count) in
350+
var symbols: [String] = []
351+
352+
var buffer: UnsafeMutablePointer<Int8> =
353+
UnsafeMutablePointer<Int8>
354+
.allocate(capacity: MemoryLayout<SYMBOL_INFO>.size + 128)
355+
defer { buffer.deallocate() }
356+
357+
buffer.withMemoryRebound(to: SYMBOL_INFO.self, capacity: 1) {
358+
$0.pointee.SizeOfStruct = ULONG(MemoryLayout<SYMBOL_INFO>.size)
359+
$0.pointee.MaxNameLen = 128
360+
361+
var address = addresses
362+
for _ in 1...count {
363+
var dwDisplacement: DWORD64 = 0
364+
if SymFromAddr(hProcess, unsafeBitCast(address.pointee,
365+
to: DWORD64.self),
366+
&dwDisplacement, $0) == FALSE {
367+
symbols.append("\($0.pointee)")
368+
} else {
369+
symbols.append(String(cString: &$0.pointee.Name))
370+
}
371+
address = address.successor()
372+
}
373+
}
374+
return symbols
375+
}
273376
#else
274377
return backtraceAddresses({ (addrs, count) in
275378
var symbols: [String] = []

0 commit comments

Comments
 (0)