I'm trying to implment SerialExecutor based on RunLoop. So I can manage old non GCD models to the actor world. ( such as CoreLocation )
What I've found is that sometimes. my RunLoop thead jumps to the strange stack point and lose all of my TaskLocals.
I have my thread's main like below. Which I expect TaskLocal is always available inside my runLoop.
// This is the main of runloop thread
//ExecutorContext contains JobQueue and RunLoopSource
static func controlRunLoop(context:ExecutorContext) {
guard Self.myLocal == nil,
RunLoop.current.currentMode == nil,
RunLoop.current != RunLoop.main
else { return }
defer {
while true {
let (exchanged, _ ) = context.queue.sanityCheck.compareExchange(expected: false, desired: true, ordering: .releasing)
if exchanged {
break
}
}
// last safety check
Self.$myLocal.withValue(context) {
Self.processEvents()
}
}
Self.$myLocal.withValue(context) {
CFRunLoopAddSource(CFRunLoopGetCurrent(), context.source, .commonModes)
while CFRunLoopSourceIsValid(context.source) {
let passed = RunLoop.current.run(mode: .default, before: .distantFuture)
if !passed {
break
}
}
}
}
However when I actaully use this as a SerialExecutor. where actual Task exist, my TaskLocal is loosed.
This is the stack when I access my RunLoop from traditional RunLoop API
Thread 10#0 0x00000001039ccb08 in closure #1 in static RunLoopPriorityExecutor.controlRunLoop(context:) at /Users/bagbyeong-gwan/IDE/XcodeWorkSpace/Tetra/Sources/CriticalSection/PriorityRunLoop.swift:308
#1 0x00000001039cf968 in partial apply for closure #1 in static RunLoopPriorityExecutor.controlRunLoop(context:) ()
#2 0x0000000265252264 in TaskLocal.withValue<τ_0_0>(_:operation:file:line:) ()
#3 0x00000001039cc780 in static RunLoopPriorityExecutor.controlRunLoop(context:) at /Users/bagbyeong-gwan/IDE/XcodeWorkSpace/Tetra/Sources/CriticalSection/PriorityRunLoop.swift:305
#4 0x00000001039ce358 in executeRunloop(setupHandle:) at /Users/bagbyeong-gwan/IDE/XcodeWorkSpace/Tetra/Sources/CriticalSection/PriorityRunLoop.swift:478
#5 0x000000010392c090 in closure #1 in closure #1 in RunLoopActor.init(qos:) at /Users/bagbyeong-gwan/IDE/XcodeWorkSpace/Tetra/Tests/TetraTests/TetraTests.swift:166
#6 0x000000010392d1fc in thunk for @escaping @callee_guaranteed @Sendable () -> () ()
#7 0x000000018e17ede8 in __NSThread__start__ ()
#8 0x000000018cee02e4 in _pthread_start ()
And This is the stacktrace, when my RunLoop is servicing the actor. Strange ... Same Thread but different StackTrace.
Thread 10#0 0x000000010392d33c in RunLoopActor.spawn2() at /Users/bagbyeong-gwan/IDE/XcodeWorkSpace/Tetra/Tests/TetraTests/TetraTests.swift:231
#1 0x000000010392a610 in TetraTests.sfasdfasdfasdfasf() at /Users/bagbyeong-gwan/IDE/XcodeWorkSpace/Tetra/Tests/TetraTests/TetraTests.swift:36
#2 0x000000010392a2cc in static TetraTests.$s10TetraTestsAAV17sfasdfasdfasdfasf4TestfMp_28funcsfasdfasdfasdfasf__asyncfMu0_@Sendable () at /Users/bagbyeong-gwan/IDE/XcodeWorkSpace/Tetra/.swiftpm/xcode/@__swiftmacro_10TetraTestsAAV17sfasdfasdfasdfasf4TestfMp_.swift:4
#3 0x000000010392a9e0 in implicit closure #1 in static TetraTests.$s10TetraTestsAAV17sfasdfasdfasdfasf4TestfMp_58__🟠$test_container__function__funcsfasdfasdfasdfasf__asyncfMu_.__tests.getter at /Users/bagbyeong-gwan/IDE/XcodeWorkSpace/Tetra/.swiftpm/xcode/@__swiftmacro_10TetraTestsAAV17sfasdfasdfasdfasf4TestfMp_.swift:18
#4 0x00000001033c393c in ___lldb_unnamed_symbol5952 ()
#5 0x00000001032ff978 in ___lldb_unnamed_symbol2777 ()
#6 0x00000001032feaa8 in ___lldb_unnamed_symbol2748 ()
#7 0x00000001033c2e40 in ___lldb_unnamed_symbol5947 ()
#8 0x00000001032ff978 in ___lldb_unnamed_symbol2777 ()
#9 0x0000000265251f68 in TaskLocal.withValueImpl<τ_0_0>(_:operation:file:line:) ()
#10 0x0000000265225db0 in TaskLocal.withValue<τ_0_0>(_:operation:file:line:) ()
#11 0x00000001033babf8 in ___lldb_unnamed_symbol5859 ()
#12 0x00000001033c28d0 in ___lldb_unnamed_symbol5942 ()
#13 0x00000001033c235c in ___lldb_unnamed_symbol5938 ()
#14 0x00000001032ff978 in ___lldb_unnamed_symbol2777 ()
#15 0x00000001033be924 in ___lldb_unnamed_symbol5903 ()
#16 0x00000001033c1b1c in ___lldb_unnamed_symbol5928 ()
#17 0x00000001033c1274 in ___lldb_unnamed_symbol5919 ()
#18 0x00000001032ff978 in ___lldb_unnamed_symbol2777 ()
#19 0x00000001032feaa8 in ___lldb_unnamed_symbol2748 ()
#20 0x00000001033c0ccc in ___lldb_unnamed_symbol5916 ()
#21 0x00000001032ff978 in ___lldb_unnamed_symbol2777 ()
#22 0x0000000265251f68 in TaskLocal.withValueImpl<τ_0_0>(_:operation:file:line:) ()
#23 0x0000000265225db0 in TaskLocal.withValue<τ_0_0>(_:operation:file:line:) ()
#24 0x00000001033ba2c0 in ___lldb_unnamed_symbol5852 ()
#25 0x00000001033bfe64 in ___lldb_unnamed_symbol5908 ()
#26 0x00000001033c1f1c in ___lldb_unnamed_symbol5933 ()
#27 0x00000001032ff978 in ___lldb_unnamed_symbol2777 ()
#28 0x00000001033bd48c in ___lldb_unnamed_symbol5891 ()
#29 0x00000001033c02f0 in ___lldb_unnamed_symbol5910 ()
#30 0x00000001033c1f1c in ___lldb_unnamed_symbol5933 ()
#31 0x00000001032ff978 in ___lldb_unnamed_symbol2777 ()
#32 0x00000001033bd48c in ___lldb_unnamed_symbol5891 ()
#33 0x00000001033c02f0 in ___lldb_unnamed_symbol5910 ()
#34 0x00000001033c1f1c in ___lldb_unnamed_symbol5933 ()
#35 0x00000001032ff978 in ___lldb_unnamed_symbol2777 ()
#36 0x00000001033bd48c in ___lldb_unnamed_symbol5891 ()
#37 0x00000001033c02f0 in ___lldb_unnamed_symbol5910 ()
#38 0x00000001033c1f1c in ___lldb_unnamed_symbol5933 ()
#39 0x00000001032ff978 in ___lldb_unnamed_symbol2777 ()
#40 0x00000001033bd48c in ___lldb_unnamed_symbol5891 ()
#41 0x00000001033c02f0 in ___lldb_unnamed_symbol5910 ()
#42 0x00000001033c6390 in ___lldb_unnamed_symbol5980 ()
#43 0x00000001032ff978 in ___lldb_unnamed_symbol2777 ()
#44 0x000000010336e9b8 in ___lldb_unnamed_symbol4919 ()
#45 0x00000001032ff978 in ___lldb_unnamed_symbol2777 ()
Here is the code that can reproduce this behavior link