diff --git a/Sources/SwiftCoroutine/Coroutine/Coroutine/Coroutine.swift b/Sources/SwiftCoroutine/Coroutine/Coroutine/Coroutine.swift index b35143e..23a2d82 100644 --- a/Sources/SwiftCoroutine/Coroutine/Coroutine/Coroutine.swift +++ b/Sources/SwiftCoroutine/Coroutine/Coroutine/Coroutine.swift @@ -15,16 +15,6 @@ import Dispatch /// public struct Coroutine { - @inlinable static func current() throws -> CoroutineProtocol { - if let coroutine = ThreadCoroutineWrapper.current.coroutine { return coroutine } - throw CoroutineError.mustBeCalledInsideCoroutine - } - - /// Returns `true` if this property is called inside a coroutine. - @inlinable public static var isInsideCoroutine: Bool { - ThreadCoroutineWrapper.current.coroutine != nil - } - // MARK: - await /// Suspends a coroutine поки не буде викликаний callback. diff --git a/Sources/SwiftCoroutine/Coroutine/CoroutineProtocol/CoroutineProtocol.swift b/Sources/SwiftCoroutine/Coroutine/CoroutineProtocol/CoroutineProtocol.swift index e33d235..b3d1adc 100644 --- a/Sources/SwiftCoroutine/Coroutine/CoroutineProtocol/CoroutineProtocol.swift +++ b/Sources/SwiftCoroutine/Coroutine/CoroutineProtocol/CoroutineProtocol.swift @@ -6,6 +6,12 @@ // Copyright © 2020 Alex Belozierov. All rights reserved. // +#if os(Linux) +import Glibc +#else +import Darwin +#endif + @usableFromInline protocol CoroutineProtocol: class { typealias StackSize = Coroutine.StackSize @@ -17,12 +23,46 @@ extension CoroutineProtocol { - @inlinable func performAsCurrent(_ block: () -> T) -> T { - let wrapper = ThreadCoroutineWrapper.current - let caller = wrapper.coroutine - wrapper.coroutine = self - defer { wrapper.coroutine = caller } - return block() + @inlinable internal func performAsCurrent(_ block: () -> T) -> T { + let unmanaged = Unmanaged.passRetained(self) + defer { unmanaged.release() } + if let caller = pthread_getspecific(.coroutine) { + pthread_setspecific(.coroutine, unmanaged.toOpaque()) + defer { pthread_setspecific(.coroutine, caller) } + return block() + } else { + pthread_setspecific(.coroutine, unmanaged.toOpaque()) + defer { pthread_setspecific(.coroutine, nil) } + return block() + } + } + +} + +extension Coroutine { + + /// Returns `true` if this property is called inside a coroutine. + @inlinable public static var isInsideCoroutine: Bool { + pthread_getspecific(.coroutine) != nil + } + + @inlinable static func current() throws -> CoroutineProtocol { + guard let pointer = pthread_getspecific(.coroutine) + else { throw CoroutineError.mustBeCalledInsideCoroutine } + return Unmanaged.fromOpaque(pointer).takeUnretainedValue() as! CoroutineProtocol } } + +extension pthread_key_t { + + @usableFromInline internal static let coroutine: pthread_key_t = { + let key = UnsafeMutablePointer.allocate(capacity: 1) + pthread_key_create(key, nil) + defer { key.deallocate() } + return key.pointee + }() + +} + + diff --git a/Sources/SwiftCoroutine/Coroutine/CoroutineProtocol/ThreadCoroutineWrapper.swift b/Sources/SwiftCoroutine/Coroutine/CoroutineProtocol/ThreadCoroutineWrapper.swift deleted file mode 100644 index b3ce570..0000000 --- a/Sources/SwiftCoroutine/Coroutine/CoroutineProtocol/ThreadCoroutineWrapper.swift +++ /dev/null @@ -1,35 +0,0 @@ -// -// ThreadCoroutineWrapper.swift -// SwiftCoroutine -// -// Created by Alex Belozierov on 07.03.2020. -// Copyright © 2020 Alex Belozierov. All rights reserved. -// - -#if os(Linux) -import Glibc -#else -import Darwin -#endif - -@usableFromInline final class ThreadCoroutineWrapper { - - @usableFromInline var coroutine: CoroutineProtocol? - - @usableFromInline static var current: ThreadCoroutineWrapper { - if let pointer = pthread_getspecific(key) { - return Unmanaged.fromOpaque(pointer).takeUnretainedValue() - } - let wrapper = Unmanaged.passRetained(ThreadCoroutineWrapper()) - pthread_setspecific(key, wrapper.toOpaque()) - return wrapper.takeUnretainedValue() - } - - private static let key: pthread_key_t = { - let key = UnsafeMutablePointer.allocate(capacity: 1) - pthread_key_create(key, nil) - defer { key.deallocate() } - return key.pointee - }() - -} diff --git a/SwiftCoroutine.xcodeproj/project.pbxproj b/SwiftCoroutine.xcodeproj/project.pbxproj index f8b4ac8..4e7d970 100644 --- a/SwiftCoroutine.xcodeproj/project.pbxproj +++ b/SwiftCoroutine.xcodeproj/project.pbxproj @@ -27,8 +27,6 @@ 1A363CBD2413D004000CF996 /* StackfullCoroutine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A363CBB2413D004000CF996 /* StackfullCoroutine.swift */; }; 1A363CBF2413D03B000CF996 /* CoroutineProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A363CBE2413D03B000CF996 /* CoroutineProtocol.swift */; }; 1A363CC02413D03B000CF996 /* CoroutineProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A363CBE2413D03B000CF996 /* CoroutineProtocol.swift */; }; - 1A363CC22413D077000CF996 /* ThreadCoroutineWrapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A363CC12413D077000CF996 /* ThreadCoroutineWrapper.swift */; }; - 1A363CC32413D077000CF996 /* ThreadCoroutineWrapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A363CC12413D077000CF996 /* ThreadCoroutineWrapper.swift */; }; 1A43084523C094EC001A89EA /* DispatchSourceTimer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A43084423C094EC001A89EA /* DispatchSourceTimer.swift */; }; 1A43084623C094EC001A89EA /* DispatchSourceTimer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A43084423C094EC001A89EA /* DispatchSourceTimer.swift */; }; 1A47C25023D73D3F004CC7B1 /* CoroutineTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A47C24F23D73D3F004CC7B1 /* CoroutineTests.swift */; }; @@ -135,7 +133,6 @@ 1A3583FE23DD796A0086A6E6 /* CoFuture1+whenComplete.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CoFuture1+whenComplete.swift"; sourceTree = ""; }; 1A363CBB2413D004000CF996 /* StackfullCoroutine.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StackfullCoroutine.swift; sourceTree = ""; }; 1A363CBE2413D03B000CF996 /* CoroutineProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CoroutineProtocol.swift; sourceTree = ""; }; - 1A363CC12413D077000CF996 /* ThreadCoroutineWrapper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThreadCoroutineWrapper.swift; sourceTree = ""; }; 1A43084423C094EC001A89EA /* DispatchSourceTimer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DispatchSourceTimer.swift; sourceTree = ""; }; 1A47C24F23D73D3F004CC7B1 /* CoroutineTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CoroutineTests.swift; sourceTree = ""; }; 1A4C6DAC2416AB2C00EF2974 /* FifoQueue.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FifoQueue.swift; sourceTree = ""; }; @@ -294,7 +291,6 @@ 1A599E51241ACD7B007E744F /* CoroutineProtocol */ = { isa = PBXGroup; children = ( - 1A363CC12413D077000CF996 /* ThreadCoroutineWrapper.swift */, 1A363CBE2413D03B000CF996 /* CoroutineProtocol.swift */, ); path = CoroutineProtocol; @@ -694,7 +690,6 @@ 1AFFF6ED23C8BDEA0079FF73 /* CoFutureError.swift in Sources */, 1A8129A52417D49900AE061C /* CoroutineDispatcher.swift in Sources */, F8CD25E92019A01600952299 /* CCoroutine.c in Sources */, - 1A363CC22413D077000CF996 /* ThreadCoroutineWrapper.swift in Sources */, 1A43084523C094EC001A89EA /* DispatchSourceTimer.swift in Sources */, 1A790E8423E5D7A9007056EC /* Coroutine.swift in Sources */, 1A65BABB239CE05D004C1716 /* CoroutineContext.swift in Sources */, @@ -755,7 +750,6 @@ 1A65BAC2239CEFED004C1716 /* CoroutineContext.swift in Sources */, 1A8129A62417D49900AE061C /* CoroutineDispatcher.swift in Sources */, F8CD25ED2019A0F800952299 /* CCoroutine.c in Sources */, - 1A363CC32413D077000CF996 /* ThreadCoroutineWrapper.swift in Sources */, 1A790E8523E5D7A9007056EC /* Coroutine.swift in Sources */, 1A43084623C094EC001A89EA /* DispatchSourceTimer.swift in Sources */, 1A9C14DF23BB824400E13203 /* CoFuture2+await.swift in Sources */,