forked from swiftlang/swift-corelibs-foundation
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathNSThread.swift
215 lines (187 loc) · 6.45 KB
/
NSThread.swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
#if os(OSX) || os(iOS)
import Darwin
#elseif os(Linux)
import Glibc
#endif
import CoreFoundation
// for some reason having this take a generic causes a crash...
private func _compiler_crash_fix(_ key: _CFThreadSpecificKey, _ value: AnyObject?) {
_CThreadSpecificSet(key, value)
}
internal class NSThreadSpecific<T: NSObject> {
private var key = _CFThreadSpecificKeyCreate()
internal func get(_ generator: (Void) -> T) -> T {
if let specific = _CFThreadSpecificGet(key) {
return specific as! T
} else {
let value = generator()
_compiler_crash_fix(key, value)
return value
}
}
internal func set(_ value: T) {
_compiler_crash_fix(key, value)
}
}
internal enum _NSThreadStatus {
case initialized
case starting
case executing
case finished
}
private func NSThreadStart(_ context: UnsafeMutableRawPointer?) -> UnsafeMutableRawPointer? {
let thread: Thread = NSObject.unretainedReference(context!)
Thread._currentThread.set(thread)
thread._status = .executing
thread.main()
thread._status = .finished
Thread.releaseReference(context!)
return nil
}
open class Thread: NSObject {
static internal var _currentThread = NSThreadSpecific<Thread>()
public static var current: Thread {
return Thread._currentThread.get() {
return Thread(thread: pthread_self())
}
}
/// Alternative API for detached thread creation
/// - Experiment: This is a draft API currently under consideration for official import into Foundation as a suitable alternative to creation via selector
/// - Note: Since this API is under consideration it may be either removed or revised in the near future
open class func detachNewThread(_ main: @escaping (Void) -> Void) {
let t = Thread(main)
t.start()
}
open class func isMultiThreaded() -> Bool {
return true
}
open class func sleepUntilDate(_ date: Date) {
let start_ut = CFGetSystemUptime()
let start_at = CFAbsoluteTimeGetCurrent()
let end_at = date.timeIntervalSinceReferenceDate
var ti = end_at - start_at
let end_ut = start_ut + ti
while (0.0 < ti) {
var __ts__ = timespec(tv_sec: LONG_MAX, tv_nsec: 0)
if ti < Double(LONG_MAX) {
var integ = 0.0
let frac: Double = withUnsafeMutablePointer(to: &integ) { integp in
return modf(ti, integp)
}
__ts__.tv_sec = Int(integ)
__ts__.tv_nsec = Int(frac * 1000000000.0)
}
let _ = withUnsafePointer(to: &__ts__) { ts in
nanosleep(ts, nil)
}
ti = end_ut - CFGetSystemUptime()
}
}
open class func sleepForTimeInterval(_ interval: TimeInterval) {
var ti = interval
let start_ut = CFGetSystemUptime()
let end_ut = start_ut + ti
while 0.0 < ti {
var __ts__ = timespec(tv_sec: LONG_MAX, tv_nsec: 0)
if ti < Double(LONG_MAX) {
var integ = 0.0
let frac: Double = withUnsafeMutablePointer(to: &integ) { integp in
return modf(ti, integp)
}
__ts__.tv_sec = Int(integ)
__ts__.tv_nsec = Int(frac * 1000000000.0)
}
let _ = withUnsafePointer(to: &__ts__) { ts in
nanosleep(ts, nil)
}
ti = end_ut - CFGetSystemUptime()
}
}
open class func exit() {
pthread_exit(nil)
}
internal var _main: (Void) -> Void = {}
#if os(OSX) || os(iOS)
private var _thread: pthread_t? = nil
#elseif os(Linux)
private var _thread = pthread_t()
#endif
internal var _attr = pthread_attr_t()
internal var _status = _NSThreadStatus.initialized
internal var _cancelled = false
/// - Note: this differs from the Darwin implementation in that the keys must be Strings
open var threadDictionary = [String:AnyObject]()
internal init(thread: pthread_t) {
// Note: even on Darwin this is a non-optional pthread_t; this is only used for valid threads, which are never null pointers.
_thread = thread
}
public init(_ main: @escaping (Void) -> Void) {
_main = main
let _ = withUnsafeMutablePointer(to: &_attr) { attr in
pthread_attr_init(attr)
pthread_attr_setscope(attr, Int32(PTHREAD_SCOPE_SYSTEM))
pthread_attr_setdetachstate(attr, Int32(PTHREAD_CREATE_DETACHED))
}
}
open func start() {
precondition(_status == .initialized, "attempting to start a thread that has already been started")
_status = .starting
if _cancelled {
_status = .finished
return
}
_thread = self.withRetainedReference {
return _CFThreadCreate(self._attr, NSThreadStart, $0)
}
}
open func main() {
_main()
}
open var stackSize: Int {
get {
var size: Int = 0
return withUnsafeMutablePointer(to: &_attr) { attr in
withUnsafeMutablePointer(to: &size) { sz in
pthread_attr_getstacksize(attr, sz)
return sz.pointee
}
}
}
set {
// just don't allow a stack size more than 1GB on any platform
var s = newValue
if (1 << 30) < s {
s = 1 << 30
}
let _ = withUnsafeMutablePointer(to: &_attr) { attr in
pthread_attr_setstacksize(attr, s)
}
}
}
open var executing: Bool {
return _status == .executing
}
open var finished: Bool {
return _status == .finished
}
open var cancelled: Bool {
return _cancelled
}
open func cancel() {
_cancelled = true
}
open class func callStackReturnAddresses() -> [NSNumber] {
NSUnimplemented()
}
open class func callStackSymbols() -> [String] {
NSUnimplemented()
}
}