//===--- SwiftPrivateThreadExtras.swift -----------------------------------===// // // This source file is part of the Swift.org open source project // // Copyright (c) 2014 - 2018 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// // // This file contains wrappers for pthread APIs that are less painful to use // than the C APIs. // //===----------------------------------------------------------------------===// #if os(macOS) || os(iOS) || os(watchOS) || os(tvOS) import Darwin #elseif os(Linux) || os(FreeBSD) || os(PS4) || os(Android) || os(Cygwin) || os(Haiku) import Glibc #elseif os(Windows) import MSVCRT import WinSDK #endif /// An abstract base class to encapsulate the context necessary to invoke /// a block from pthread_create. internal class ThreadBlockContext { /// Execute the block, and return an `UnsafeMutablePointer` to memory /// allocated with `UnsafeMutablePointer.alloc` containing the result of the /// block. func run() -> UnsafeMutableRawPointer { fatalError("abstract") } } internal class ThreadBlockContextImpl: ThreadBlockContext { let block: (Argument) -> Result let arg: Argument init(block: @escaping (Argument) -> Result, arg: Argument) { self.block = block self.arg = arg super.init() } override func run() -> UnsafeMutableRawPointer { let result = UnsafeMutablePointer.allocate(capacity: 1) result.initialize(to: block(arg)) return UnsafeMutableRawPointer(result) } } /// Entry point for `pthread_create` that invokes a block context. internal func invokeBlockContext( _ contextAsVoidPointer: UnsafeMutableRawPointer? ) -> UnsafeMutableRawPointer! { // The context is passed in +1; we're responsible for releasing it. let context = Unmanaged .fromOpaque(contextAsVoidPointer!) .takeRetainedValue() return context.run() } #if os(Windows) public typealias ThreadHandle = HANDLE #else public typealias ThreadHandle = pthread_t #if os(Linux) || os(Android) internal func _make_pthread_t() -> pthread_t { return pthread_t() } #else internal func _make_pthread_t() -> pthread_t? { return nil } #endif #endif /// Block-based wrapper for `pthread_create`. public func _stdlib_thread_create_block( _ start_routine: @escaping (Argument) -> Result, _ arg: Argument ) -> (CInt, ThreadHandle?) { let context = ThreadBlockContextImpl(block: start_routine, arg: arg) // We hand ownership off to `invokeBlockContext` through its void context // argument. let contextAsVoidPointer = Unmanaged.passRetained(context).toOpaque() #if os(Windows) let threadID = _beginthreadex(nil, 0, { invokeBlockContext($0)! .assumingMemoryBound(to: UInt32.self).pointee }, contextAsVoidPointer, 0, nil) if threadID == 0 { return (errno, nil) } else { return (0, ThreadHandle(bitPattern: threadID)) } #else var threadID = _make_pthread_t() let result = pthread_create(&threadID, nil, { invokeBlockContext($0) }, contextAsVoidPointer) if result == 0 { return (result, threadID) } else { return (result, nil) } #endif } /// Block-based wrapper for `pthread_join`. public func _stdlib_thread_join( _ thread: ThreadHandle, _ resultType: Result.Type ) -> (CInt, Result?) { #if os(Windows) let result = WaitForSingleObject(thread, INFINITE) if result == WAIT_OBJECT_0 { var threadResult: DWORD = 0 GetExitCodeThread(thread, &threadResult) CloseHandle(thread) return (CInt(result), UnsafeMutablePointer(&threadResult) .withMemoryRebound(to: Result.self, capacity: 1){ $0.pointee }) } else { return (CInt(result), nil) } #else var threadResultRawPtr: UnsafeMutableRawPointer? let result = pthread_join(thread, &threadResultRawPtr) if result == 0 { let threadResultPtr = threadResultRawPtr!.assumingMemoryBound( to: Result.self) let threadResult = threadResultPtr.pointee threadResultPtr.deinitialize(count: 1) threadResultPtr.deallocate() return (result, threadResult) } else { return (result, nil) } #endif } public class _stdlib_Barrier { var _threadBarrier: _stdlib_thread_barrier_t var _threadBarrierPtr: UnsafeMutablePointer<_stdlib_thread_barrier_t> { return _getUnsafePointerToStoredProperties(self) .assumingMemoryBound(to: _stdlib_thread_barrier_t.self) } public init(threadCount: Int) { self._threadBarrier = _stdlib_thread_barrier_t() let ret = _stdlib_thread_barrier_init( _threadBarrierPtr, CUnsignedInt(threadCount)) if ret != 0 { fatalError("_stdlib_thread_barrier_init() failed") } } deinit { let ret = _stdlib_thread_barrier_destroy(_threadBarrierPtr) if ret != 0 { fatalError("_stdlib_thread_barrier_destroy() failed") } } public func wait() { let ret = _stdlib_thread_barrier_wait(_threadBarrierPtr) if !(ret == 0 || ret == _stdlib_THREAD_BARRIER_SERIAL_THREAD) { fatalError("_stdlib_thread_barrier_wait() failed") } } }