Skip to content

Commit c9cf8fc

Browse files
authored
Merge pull request #20719 from compnerd/threading-extras
port SwiftPrivatePthreadExtras to Windows
2 parents 792a50e + 0aec837 commit c9cf8fc

File tree

11 files changed

+182
-99
lines changed

11 files changed

+182
-99
lines changed

stdlib/private/CMakeLists.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,14 @@ if(SWIFT_BUILD_STDLIB OR SWIFT_BUILD_SDK_OVERLAY)
33
endif()
44

55
if(SWIFT_BUILD_SDK_OVERLAY)
6-
# SwiftPrivatePthreadExtras makes use of Darwin/Glibc, which is part of the
6+
# SwiftPrivateThreadExtras makes use of Darwin/Glibc, which is part of the
77
# SDK overlay. It can't be built separately from the SDK overlay.
88
add_subdirectory(RuntimeUnittest)
99
add_subdirectory(StdlibUnittest)
1010
add_subdirectory(StdlibUnicodeUnittest)
1111
add_subdirectory(StdlibCollectionUnittest)
1212
add_subdirectory(SwiftPrivateLibcExtras)
13-
add_subdirectory(SwiftPrivatePthreadExtras)
13+
add_subdirectory(SwiftPrivateThreadExtras)
1414

1515
if(CMAKE_SYSTEM_NAME STREQUAL "Darwin")
1616
add_subdirectory(StdlibUnittestFoundationExtras)

stdlib/private/StdlibUnittest/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ add_swift_target_library(swiftStdlibUnittest ${SWIFT_STDLIB_LIBRARY_BUILD_TYPES}
3333
TypeIndexed.swift
3434
GetOSVersion.mm
3535

36-
SWIFT_MODULE_DEPENDS SwiftPrivate SwiftPrivatePthreadExtras SwiftPrivateLibcExtras
36+
SWIFT_MODULE_DEPENDS SwiftPrivate SwiftPrivateThreadExtras SwiftPrivateLibcExtras
3737
SWIFT_MODULE_DEPENDS_IOS Darwin Foundation
3838
SWIFT_MODULE_DEPENDS_OSX Darwin Foundation
3939
SWIFT_MODULE_DEPENDS_TVOS Darwin Foundation

stdlib/private/StdlibUnittest/RaceTest.swift

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@
3838

3939
import SwiftPrivate
4040
import SwiftPrivateLibcExtras
41-
import SwiftPrivatePthreadExtras
41+
import SwiftPrivateThreadExtras
4242
#if os(macOS) || os(iOS)
4343
import Darwin
4444
#elseif os(Linux) || os(FreeBSD) || os(PS4) || os(Android) || os(Cygwin) || os(Haiku)
@@ -605,38 +605,35 @@ public func runRaceTest<RT : RaceTestWithPerTrialData>(
605605

606606
// Create the master thread.
607607
do {
608-
let (ret, tid) = _stdlib_pthread_create_block(
609-
nil, masterThreadBody, ())
608+
let (ret, tid) = _stdlib_thread_create_block(masterThreadBody, ())
610609
expectEqual(0, ret)
611610
testTids.append(tid!)
612611
}
613612

614613
// Create racing threads.
615614
for i in 0..<racingThreadCount {
616-
let (ret, tid) = _stdlib_pthread_create_block(
617-
nil, racingThreadBody, i)
615+
let (ret, tid) = _stdlib_thread_create_block(racingThreadBody, i)
618616
expectEqual(0, ret)
619617
testTids.append(tid!)
620618
}
621619

622620
// Create the alarm thread that enforces the timeout.
623621
do {
624-
let (ret, tid) = _stdlib_pthread_create_block(
625-
nil, alarmThreadBody, ())
622+
let (ret, tid) = _stdlib_thread_create_block(alarmThreadBody, ())
626623
expectEqual(0, ret)
627624
alarmTid = tid!
628625
}
629626

630627
// Join all testing threads.
631628
for tid in testTids {
632-
let (ret, _) = _stdlib_pthread_join(tid, Void.self)
629+
let (ret, _) = _stdlib_thread_join(tid, Void.self)
633630
expectEqual(0, ret)
634631
}
635632

636633
// Tell the alarm thread to stop if it hasn't already, then join it.
637634
do {
638635
alarmTimer.wake()
639-
let (ret, _) = _stdlib_pthread_join(alarmTid, Void.self)
636+
let (ret, _) = _stdlib_thread_join(alarmTid, Void.self)
640637
expectEqual(0, ret)
641638
}
642639

stdlib/private/StdlibUnittest/StdlibUnittest.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212

1313

1414
import SwiftPrivate
15-
import SwiftPrivatePthreadExtras
15+
import SwiftPrivateThreadExtras
1616
import SwiftPrivateLibcExtras
1717

1818
#if os(macOS) || os(iOS) || os(watchOS) || os(tvOS)
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
add_swift_target_library(swiftSwiftPrivatePthreadExtras ${SWIFT_STDLIB_LIBRARY_BUILD_TYPES} IS_STDLIB
1+
add_swift_target_library(swiftSwiftPrivateThreadExtras ${SWIFT_STDLIB_LIBRARY_BUILD_TYPES} IS_STDLIB
22
# This file should be listed the first. Module name is inferred from the
33
# filename.
4-
SwiftPrivatePthreadExtras.swift
5-
PthreadBarriers.swift
4+
SwiftPrivateThreadExtras.swift
5+
ThreadBarriers.swift
66

77
SWIFT_MODULE_DEPENDS_IOS Darwin
88
SWIFT_MODULE_DEPENDS_OSX Darwin
@@ -13,6 +13,5 @@ add_swift_target_library(swiftSwiftPrivatePthreadExtras ${SWIFT_STDLIB_LIBRARY_B
1313
SWIFT_MODULE_DEPENDS_CYGWIN Glibc
1414
SWIFT_MODULE_DEPENDS_HAIKU Glibc
1515
SWIFT_COMPILE_FLAGS
16-
TARGET_SDKS ALL_POSIX_PLATFORMS
1716
INSTALL_IN_COMPONENT stdlib-experimental)
1817

Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
//===--- SwiftPrivatePthreadExtras.swift ----------------------------------===//
1+
//===--- SwiftPrivateThreadExtras.swift ----------------------------------===//
22
//
33
// This source file is part of the Swift.org open source project
44
//
@@ -19,18 +19,21 @@
1919
import Darwin
2020
#elseif os(Linux) || os(FreeBSD) || os(PS4) || os(Android) || os(Cygwin) || os(Haiku)
2121
import Glibc
22+
#elseif os(Windows)
23+
import MSVCRT
24+
import WinSDK
2225
#endif
2326

2427
/// An abstract base class to encapsulate the context necessary to invoke
2528
/// a block from pthread_create.
26-
internal class PthreadBlockContext {
29+
internal class ThreadBlockContext {
2730
/// Execute the block, and return an `UnsafeMutablePointer` to memory
2831
/// allocated with `UnsafeMutablePointer.alloc` containing the result of the
2932
/// block.
3033
func run() -> UnsafeMutableRawPointer { fatalError("abstract") }
3134
}
3235

33-
internal class PthreadBlockContextImpl<Argument, Result>: PthreadBlockContext {
36+
internal class ThreadBlockContextImpl<Argument, Result>: ThreadBlockContext {
3437
let block: (Argument) -> Result
3538
let arg: Argument
3639

@@ -52,55 +55,82 @@ internal func invokeBlockContext(
5255
_ contextAsVoidPointer: UnsafeMutableRawPointer?
5356
) -> UnsafeMutableRawPointer! {
5457
// The context is passed in +1; we're responsible for releasing it.
55-
let context = Unmanaged<PthreadBlockContext>
58+
let context = Unmanaged<ThreadBlockContext>
5659
.fromOpaque(contextAsVoidPointer!)
5760
.takeRetainedValue()
5861

5962
return context.run()
6063
}
6164

62-
#if os(Cygwin) || os(FreeBSD) || os(Haiku)
63-
public typealias _stdlib_pthread_attr_t = UnsafePointer<pthread_attr_t?>
65+
#if os(Windows)
66+
public typealias ThreadHandle = HANDLE
6467
#else
65-
public typealias _stdlib_pthread_attr_t = UnsafePointer<pthread_attr_t>
68+
public typealias ThreadHandle = pthread_t
69+
70+
#if os(Linux) || os(Android)
71+
internal func _make_pthread_t() -> pthread_t {
72+
return pthread_t()
73+
}
74+
#else
75+
internal func _make_pthread_t() -> pthread_t? {
76+
return nil
77+
}
78+
#endif
6679
#endif
6780

6881
/// Block-based wrapper for `pthread_create`.
69-
public func _stdlib_pthread_create_block<Argument, Result>(
70-
_ attr: _stdlib_pthread_attr_t?,
82+
public func _stdlib_thread_create_block<Argument, Result>(
7183
_ start_routine: @escaping (Argument) -> Result,
7284
_ arg: Argument
73-
) -> (CInt, pthread_t?) {
74-
let context = PthreadBlockContextImpl(block: start_routine, arg: arg)
85+
) -> (CInt, ThreadHandle?) {
86+
let context = ThreadBlockContextImpl(block: start_routine, arg: arg)
7587
// We hand ownership off to `invokeBlockContext` through its void context
7688
// argument.
7789
let contextAsVoidPointer = Unmanaged.passRetained(context).toOpaque()
7890

91+
#if os(Windows)
92+
var threadID =
93+
_beginthreadex(nil, 0, { invokeBlockContext($0)!
94+
.assumingMemoryBound(to: UInt32.self).pointee },
95+
contextAsVoidPointer, 0, nil)
96+
if threadID == 0 {
97+
return (errno, nil)
98+
} else {
99+
return (0, UnsafeMutablePointer<ThreadHandle>(&threadID).pointee)
100+
}
101+
#else
79102
var threadID = _make_pthread_t()
80-
let result = pthread_create(&threadID, attr,
103+
let result = pthread_create(&threadID, nil,
81104
{ invokeBlockContext($0) }, contextAsVoidPointer)
82105
if result == 0 {
83106
return (result, threadID)
84107
} else {
85108
return (result, nil)
86109
}
87-
}
88-
89-
#if os(Linux) || os(Android)
90-
internal func _make_pthread_t() -> pthread_t {
91-
return pthread_t()
92-
}
93-
#else
94-
internal func _make_pthread_t() -> pthread_t? {
95-
return nil
96-
}
97110
#endif
111+
}
98112

99113
/// Block-based wrapper for `pthread_join`.
100-
public func _stdlib_pthread_join<Result>(
101-
_ thread: pthread_t,
114+
public func _stdlib_thread_join<Result>(
115+
_ thread: ThreadHandle,
102116
_ resultType: Result.Type
103117
) -> (CInt, Result?) {
118+
#if os(Windows)
119+
// TODO(compnerd) modularize rpc.h for INFINITE (0xffffffff)
120+
let result = WaitForSingleObject(thread, 0xffffffff);
121+
// TODO(compnerd) modularize WinBase.h for WAIT_OBJECT_0 (0)
122+
if result == 0 {
123+
let threadResult: DWORD = 0
124+
GetExitCodeThread(thread, &threadResult)
125+
CloseHandle(thread)
126+
127+
return (result,
128+
UnsafeMutablePointer<DWORD>(&threadResult)
129+
.withMemoryRebound(to: Result.self, capacity: 1){ $0.pointee })
130+
} else {
131+
return (result, nil)
132+
}
133+
#else
104134
var threadResultRawPtr: UnsafeMutableRawPointer?
105135
let result = pthread_join(thread, &threadResultRawPtr)
106136
if result == 0 {
@@ -113,36 +143,37 @@ public func _stdlib_pthread_join<Result>(
113143
} else {
114144
return (result, nil)
115145
}
146+
#endif
116147
}
117148

118149
public class _stdlib_Barrier {
119-
var _pthreadBarrier: _stdlib_pthread_barrier_t
150+
var _threadBarrier: _stdlib_thread_barrier_t
120151

121-
var _pthreadBarrierPtr: UnsafeMutablePointer<_stdlib_pthread_barrier_t> {
152+
var _threadBarrierPtr: UnsafeMutablePointer<_stdlib_thread_barrier_t> {
122153
return _getUnsafePointerToStoredProperties(self)
123-
.assumingMemoryBound(to: _stdlib_pthread_barrier_t.self)
154+
.assumingMemoryBound(to: _stdlib_thread_barrier_t.self)
124155
}
125156

126157
public init(threadCount: Int) {
127-
self._pthreadBarrier = _stdlib_pthread_barrier_t()
128-
let ret = _stdlib_pthread_barrier_init(
129-
_pthreadBarrierPtr, nil, CUnsignedInt(threadCount))
158+
self._threadBarrier = _stdlib_thread_barrier_t()
159+
let ret = _stdlib_thread_barrier_init(
160+
_threadBarrierPtr, CUnsignedInt(threadCount))
130161
if ret != 0 {
131-
fatalError("_stdlib_pthread_barrier_init() failed")
162+
fatalError("_stdlib_thread_barrier_init() failed")
132163
}
133164
}
134165

135166
deinit {
136-
let ret = _stdlib_pthread_barrier_destroy(_pthreadBarrierPtr)
167+
let ret = _stdlib_thread_barrier_destroy(_threadBarrierPtr)
137168
if ret != 0 {
138-
fatalError("_stdlib_pthread_barrier_destroy() failed")
169+
fatalError("_stdlib_thread_barrier_destroy() failed")
139170
}
140171
}
141172

142173
public func wait() {
143-
let ret = _stdlib_pthread_barrier_wait(_pthreadBarrierPtr)
144-
if !(ret == 0 || ret == _stdlib_PTHREAD_BARRIER_SERIAL_THREAD) {
145-
fatalError("_stdlib_pthread_barrier_wait() failed")
174+
let ret = _stdlib_thread_barrier_wait(_threadBarrierPtr)
175+
if !(ret == 0 || ret == _stdlib_THREAD_BARRIER_SERIAL_THREAD) {
176+
fatalError("_stdlib_thread_barrier_wait() failed")
146177
}
147178
}
148179
}

0 commit comments

Comments
 (0)