blob: 455b19454c90317c0b13ce064987b479a5438e11 [file] [log] [blame]
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2015 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
private func disposeTLS(ctx: UnsafeMutablePointer<Void>) -> Void {
Unmanaged<AnyObject>.fromOpaque(OpaquePointer(ctx)).release()
}
internal class NSThreadSpecific<T: AnyObject> {
private var NSThreadSpecificKeySet = false
private var NSThreadSpecificKeyLock = NSLock()
private var NSThreadSpecificKey = pthread_key_t()
private var key: pthread_key_t {
NSThreadSpecificKeyLock.lock()
if !NSThreadSpecificKeySet {
withUnsafeMutablePointer(&NSThreadSpecificKey) { key in
NSThreadSpecificKeySet = pthread_key_create(key, disposeTLS) == 0
}
}
NSThreadSpecificKeyLock.unlock()
return NSThreadSpecificKey
}
internal func get(generator: (Void) -> T) -> T {
let specific = pthread_getspecific(self.key)
if specific != nil {
return Unmanaged<T>.fromOpaque(OpaquePointer(specific)).takeUnretainedValue()
} else {
let value = generator()
pthread_setspecific(self.key, UnsafePointer<Void>(OpaquePointer(bitPattern: Unmanaged<AnyObject>.passRetained(value))))
return value
}
}
internal func set(value: T) {
let specific = pthread_getspecific(self.key)
var previous: Unmanaged<T>?
if specific != nil {
previous = Unmanaged<T>.fromOpaque(OpaquePointer(specific))
}
if let prev = previous {
if prev.takeUnretainedValue() === value {
return
}
}
pthread_setspecific(self.key, UnsafePointer<Void>(OpaquePointer(bitPattern: Unmanaged<AnyObject>.passRetained(value))))
if let prev = previous {
prev.release()
}
}
}
internal enum _NSThreadStatus {
case Initialized
case Starting
case Executing
case Finished
}
private func NSThreadStart(context: UnsafeMutablePointer<Void>) -> UnsafeMutablePointer<Void> {
let unmanaged: Unmanaged<NSThread> = Unmanaged.fromOpaque(OpaquePointer(context))
let thread = unmanaged.takeUnretainedValue()
NSThread._currentThread.set(thread)
thread._status = _NSThreadStatus.Executing
thread.main()
thread._status = _NSThreadStatus.Finished
unmanaged.release()
return nil
}
public class NSThread : NSObject {
static internal var _currentThread = NSThreadSpecific<NSThread>()
public static func currentThread() -> NSThread {
return NSThread._currentThread.get() {
return NSThread(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
public class func detachNewThread(main: (Void) -> Void) {
let t = NSThread(main)
t.start()
}
public class func isMultiThreaded() -> Bool {
return true
}
public class func sleepUntilDate(date: NSDate) {
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(&integ) { integp in
return modf(ti, integp)
}
__ts__.tv_sec = Int(integ)
__ts__.tv_nsec = Int(frac * 1000000000.0)
}
withUnsafePointer(&__ts__) { ts in
nanosleep(ts, nil)
}
ti = end_ut - CFGetSystemUptime()
}
}
public class func sleepForTimeInterval(interval: NSTimeInterval) {
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(&integ) { integp in
return modf(ti, integp)
}
__ts__.tv_sec = Int(integ)
__ts__.tv_nsec = Int(frac * 1000000000.0)
}
withUnsafePointer(&__ts__) { ts in
nanosleep(ts, nil)
}
ti = end_ut - CFGetSystemUptime()
}
}
public 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
public var threadDictionary = [String:AnyObject]()
internal init(thread: pthread_t) {
_thread = thread
}
public init(_ main: (Void) -> Void) {
_main = main
withUnsafeMutablePointer(&_attr) { attr in
pthread_attr_init(attr)
}
}
public func start() {
precondition(_status == .Initialized, "attempting to start a thread that has already been started")
_status = .Starting
if _cancelled {
_status = .Finished
return
}
withUnsafeMutablePointers(&_thread, &_attr) { thread, attr in
let ptr = Unmanaged.passRetained(self)
pthread_create(thread, attr, NSThreadStart, UnsafeMutablePointer(OpaquePointer(bitPattern: ptr)))
}
}
public func main() {
_main()
}
public var stackSize: Int {
get {
var size: Int = 0
return withUnsafeMutablePointers(&_attr, &size) { attr, 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
}
withUnsafeMutablePointer(&_attr) { attr in
pthread_attr_setstacksize(attr, s)
}
}
}
public var executing: Bool {
return _status == .Executing
}
public var finished: Bool {
return _status == .Finished
}
public var cancelled: Bool {
return _cancelled
}
public func cancel() {
_cancelled = true
}
public class func callStackReturnAddresses() -> [NSNumber] {
NSUnimplemented()
}
public class func callStackSymbols() -> [String] {
NSUnimplemented()
}
}