SwiftCoroutine - Swift coroutines for iOS, macOS and Linux.

Overview

Swift Coroutine

macOS Ubuntu codecov codebeat badge

Many languages, such as Kotlin, Go, JavaScript, Python, Rust, C#, C++ and others, already have coroutines support that makes the async/await pattern implementation possible. This feature is not yet supported in Swift, but this can be improved by a framework without the need to change the language.

Main features

  • It is the first implementation of coroutines for Swift with iOS, macOS and Linux support.
  • It includes futures and channels that supplement coroutines for more flexibility.
  • It is completely lock-free and uses only atomic primitives for synchronizations.

Motivation

Asynchronous programming is usually associated with callbacks. It is quite convenient until there are too many of them and they start nesting. Then it's called a pyramid of doom or even callback hell.

Another problem of asynchronous programming is error handling, because Swift's natural error handling mechanism cannot be used.

What about Rx and other such frameworks?

There are many other frameworks that make it easy to use asynchronous code, such as Combine, RxSwift, PromiseKit and so on. They use other approaches that have some drawbacks:

  • Similar to callbacks, you also need to create chained calls, that’s why you can’t normally use loops, exception handling, etc.
  • Usually you need to learn a complex new API with hundreds of methods.
  • Instead of working with the actual data, you need to operate with some wrappers all the time.
  • Chaining of errors can be really complicated to handle.

Async/await

The async/await pattern is an alternative that allows an asynchronous, non-blocking function to be structured in a way similar to an ordinary synchronous function.

It is already well-established in other programming languages and is an evolution in asynchronous programming. The implementation of this pattern is possible thanks to coroutines.

Let’s have a look at the example with coroutine inside of which await() suspends it and resumes when the result is available without blocking the thread.

//executes coroutine on the main thread
DispatchQueue.main.startCoroutine {
    
    //extension that returns CoFuture<(data: Data, response: URLResponse)>
    let dataFuture = URLSession.shared.dataTaskFuture(for: imageURL)
    
    //await CoFuture result that suspends coroutine and doesn't block the thread
    let data: Data = try dataFuture.await().data

    //create UIImage from the data
    guard let image = UIImage(data: data) else { return }
    
    //execute heavy task on global queue and await the result without blocking the thread
    let thumbnail: UIImage = try DispatchQueue.global().await { image.makeThumbnail() }

    //set image in UIImageView on the main thread
    self.imageView.image = thumbnail
    
}

Documentation

API documentation

Requirements

  • Support only 64-bit architectures
  • iOS 10+ / macOS 10.12+ / Ubuntu
  • Xcode 10.4+
  • Swift 5.2+

Installation

Working with SwiftCoroutine

Coroutines

A coroutine is a computation that can be suspended and resumed at a later time without blocking a thread. Coroutines build upon regular functions and can be executed on any scheduler with a possibility to switch among them during execution.

Key benefits

  • Suspend instead of block. The main advantage of coroutines is the ability to suspend their execution at some point without blocking a thread and resuming later on.
  • Fast context switching. Switching between coroutines is much faster than switching between threads as it does not require the involvement of operating system.
  • Asynchronous code in synchronous manner. The use of coroutines allows an asynchronous, non-blocking function to be structured in a manner similar to an ordinary synchronous function. And even though coroutines can run in multiple threads, your code will still look consistent and therefore easy to understand.

Usage

The coroutines API design is as minimalistic as possible. It consists of the CoroutineScheduler protocol that describes how to schedule coroutines (DispatchQueue already conforms it), and the Coroutine structure with utility methods. This API is enough to do amazing things.

The following example shows the usage of await() inside a coroutine to wrap asynchronous calls.

//execute coroutine on the main thread
DispatchQueue.main.startCoroutine {
    
    //await URLSessionDataTask response without blocking the thread
    let (data, response, error) = try Coroutine.await { callback in
        URLSession.shared.dataTask(with: url, completionHandler: callback).resume()
    }
    
    . . . use response on the main thread . . . 
}

Here's how we can conform NSManagedObjectContext to CoroutineScheduler for launching coroutines on it.

extension NSManagedObjectContext: CoroutineScheduler {

    func scheduleTask(_ task: @escaping () -> Void) {
        perform(task)
    }
    
}

//execute coroutine on the main thread
DispatchQueue.main.startCoroutine {
    let context: NSManagedObjectContext //context with privateQueueConcurrencyType
    let request: NSFetchRequest //some complex request

    //execute request on the context without blocking the main thread
    let result: [NSDictionary] = try context.await { try context.fetch(request) }
}

Futures and Promises

A future is a read-only holder for a result that will be provided later and the promise is the provider of this result. They represent the eventual completion or failure of an asynchronous operation.

The futures and promises approach itself has become an industry standart. It is a convenient mechanism to synchronize asynchronous code. But together with coroutines, it takes the usage of asynchronous code to the next level and has become a part of the async/await pattern. If coroutines are a skeleton, then futures and promises are its muscles.

Main features

  • Performance. It is much faster than most of other futures and promises implementations.
  • Awaitable. You can await the result inside the coroutine.
  • Cancellable. You can cancel the whole chain as well as handle it and complete the related actions.

Usage

Futures and promises are represented by the corresponding CoFuture class and its CoPromise subclass.

//wraps some async func with CoFuture
func makeIntFuture() -> CoFuture<Int> {
    let promise = CoPromise<Int>()
    someAsyncFunc { int in
        promise.success(int)
    }
    return promise
}

It allows to start multiple tasks in parallel and synchronize them later with await().

//create CoFuture that takes 2 sec. from the example above 
let future1: CoFuture<Int> = makeIntFuture()

//execute coroutine on the global queue and returns CoFuture with future result
let future2: CoFuture<Int> = DispatchQueue.global().coroutineFuture {
    try Coroutine.delay(.seconds(3)) //some work that takes 3 sec.
    return 6
}

//execute coroutine on the main thread
DispatchQueue.main.startCoroutine {
    let sum: Int = try future1.await() + future2.await() //will await for 3 sec.
    self.label.text = "Sum is \(sum)"
}

It's very easy to transform or compose CoFutures into a new one.

let array: [CoFuture<Int>]

//create new CoFuture with sum of future results
let sum = CoFuture { try array.reduce(0) { try $0 + $1.await() } }

Channels

Futures and promises provide a convenient way to transfer a single value between coroutines. Channels provide a way to transfer a stream of values. Conceptually, a channel is similar to a queue that allows to suspend a coroutine on receive if it is empty, or on send if it is full.

This non-blocking primitive is widely used in such languages as Go and Kotlin, and it is another instrument that improves working with coroutines.

Usage

To create channels, use the CoChannel class.

//create a channel with a buffer which can store only one element
let channel = CoChannel<Int>(capacity: 1)

DispatchQueue.global().startCoroutine {
    for i in 0..<100 {
        //imitate some work
        try Coroutine.delay(.seconds(1))
        //sends a value to the channel and suspends coroutine if its buffer is full
        try channel.awaitSend(i)
    }
    
    //close channel when all values are sent
    channel.close()
}

DispatchQueue.global().startCoroutine {
    //receives values until closed and suspends a coroutine if it's empty
    for i in channel.makeIterator() {
        print("Receive", i)
    }
    
    print("Done")
}

Scope

All launched coroutines, CoFutures and CoChannels, usually do not need to be referenced. They are deinited after their execution. But often there is a need to complete them earlier, when they are no longer needed. For this, CoFuture and CoChannel have methods for canceling.

CoScope makes it easier to manage the life cycle of these objects. It allows you to keep weak references to them and cancel if necessary or on deinit.

Usage

You can add coroutines, CoFutures, CoChannels and other CoCancellable to CoScope to cancel them when they are no longer needed or on deinit.

class ViewController: UIViewController {

    let scope = CoScope() //will cancel all objects on `cancel()` or deinit
    
    func performSomeWork() {
        //create new `CoChannel` and add to `CoScope`
        let channel = makeSomeChannel().added(to: scope)
        
        //execute coroutine and add to `CoScope`
        DispatchQueue.main.startCoroutine(in: scope) { [weak self] in
            for item in channel.makeIterator() {
                try self?.performSomeWork(with: item)
            }
        }
    }
    
    func performSomeWork(with item: Item) throws {
        //create new `CoFuture` and add to `CoScope`
        let future = makeSomeFuture(item).added(to: scope)
        
        let result = try future.await()
        . . . do some work using result . . .
    }

}
Comments
  • setjmp/longjmp are Undefined Behavior in Swift

    setjmp/longjmp are Undefined Behavior in Swift

    I was ecstatic when I saw this repo. Unfortunately, I was informed that the basis of the coroutines defined in this project are unsafe:

    setjmp and longjmp aren't safe to use in Swift (or ARC ObjC)—retain counts will leak, and weak refs may corrupt memory. - Joe Groff

    Further references:

    https://twitter.com/search?q=from%3Ajckarter%20setjmp&src=typed_query

    Unless this information is incorrect, there should probably at least be a warning in the README on this.

    opened by calebkleveter 9
  • Xcode 13 error compilation

    Xcode 13 error compilation

    Hi,

    The word await make a compilation error because apple have deployed his concurrency async await.

    Can you fix this issues simple refactored methods name func await() to func `await`() Capture d’écran 2021-09-23 à 17 45 13

    opened by emoonadev 7
  • UnitTest `CoFutureAwaitTests testNestetAwaits`   fail.

    UnitTest `CoFutureAwaitTests testNestetAwaits` fail.

    Hello dev:

    UnitTest CoFutureAwaitTests testNestetAwaits fail when swift test for this project on macOS 10.14.6. Thanks.

    
    >  swift test
    
    // …
    
    Test Case '-[SwiftCoroutineTests.CoFutureAwaitTests testConcurrency]' started.
    Test Case '-[SwiftCoroutineTests.CoFutureAwaitTests testConcurrency]' passed (1.900 seconds).
    Test Case '-[SwiftCoroutineTests.CoFutureAwaitTests testNestetAwaits]' started.
    Exited with signal code 11
    
    
    opened by Guang1234567 7
  • Issues with receiving with CoChannel (and possibly CoScope)

    Issues with receiving with CoChannel (and possibly CoScope)

    I noticed some weird behavior in my projects concerning CoChannels, and I wasn't sure if I was using it wrong or there was something buggy going on.

    I have a scoped coroutine running and

    1. The coroutine crashes when self is captured with unowned.
    2. The receiving end slows down as new coroutines are launched using the same channel.

    Not sure if I'm explaining the situation correctly, so I have a demo target here.

    I also noticed that all the CoScopes are kepts around when the memory graph debugger is run like so: Screen Shot 2021-01-31 at 3 49 41 PM

    The objects that own the CoScope instances are deallocated as expected.

    The slowing down (or rather the skipping values) corresponds to the number of zombie CoScope instances. So when there are four CoScope instances lying around, the log prints like so

    9122080394873498997
    showInt(_:) 9122080394873498997
    4655395568503796474
    432049987236061310
    1887288328159798314
    1946205301628222178
    showInt(_:) 1946205301628222178
    

    (I also noticed other weird behavior with my real project like objects captured by the SwiftCoroutine and not deallocating, but I'm not sure if it's in any way related to the issue demonstrated by the sample project. I can provide further information if you're interested.)

    Sorry about the haphazard reporting, but it was hard to determine if they all pointed to the same cause or if they were all separate, so I decided to just lay it out.

    opened by funct7 4
  • Add finally block feature

    Add finally block feature

    Hi,

    I developed a feature that I found missing.

    The problem is that I want to continue the execution of a coroutine block even if there is an error, for example a loader must disappear after the request whether there is an error or not.

    With current framework:

    DispatchQueue.main.startCoroutine(in: self.scope) {
    
    isLoading = true 
    
        do {
            try self.service.getAll().await()
            try self.service.getAll().await() // Error occurred go to catch block
            try self.service.getAll().await()
    
            isLoading = false
        } catch {
            // Error occurred
             isLoading = false
        }
    }
    

    With this version as soon as there is an error we do not continue the block we go into the catch block. But the problem is that isLoading = false is written twice

    I know I can also do this which will not stop the block but it is not what I reach, if there is an error I want the block to be stopped

    DispatchQueue.main.startCoroutine(in: self.scope) {
    
    isLoading = true 
    
            try? self.service.getAll().await()
            try? self.service.getAll().await() // Error occurred but I dont want continue to the next request, I want hide the loader
            try? self.service.getAll().await()
    
            isLoading = false
    }
    

    So my solution is as follows, I wrap the coroutine block to make it clearer, Async / Await. And I added 2 blocks to catch the error, and a finally block which will be executed even if we get an error.

    isLoading = true
    
    async {
        try self.service.getAll().await()
        try self.service.getAll().await() // Error go to catch
        try self.service.getAll().await()
    }.catch { error in
        Log.s("Error occurred:  \(error.localizedDescription)")
    }.finally {
       // This block will be executed at the end of the block even if there is an error
       isLoading = false
     }
    

    I already wrote this wrapper, if you are interested in integrating it into the framework I can make a pull request. This way will not replace the old way, it will just be a new possibility way

    opened by mickaelhero 4
  • Complete Linux Compatibility

    Complete Linux Compatibility

    • [x] Add GitHub CI workflow to always check Linux (Ubuntu Bionic) support
    • [x] Compile on Linux
    • [ ] All tests pass on Linux

    Currently, the issue that we are running into right now is the CoFutureAwaitTests.testAwait test case is exiting with a signal code 6 and literally no other information.

    opened by calebkleveter 4
  • `Coroutine.await` crashes for iOS

    `Coroutine.await` crashes for iOS

    Calling the below code crashes with Fatal error: Unexpectedly found nil while implicitly unwrapping an Optional value: file SwiftCoroutine/SharedCoroutine.swift, line 112.

    The crashing version:

    let scheduler = DispatchQueue.main
    let repo = SomeRepository()
    
    class SomeRepository {
        func getSomethingAsync() throws -> [String] {
            return try Coroutine.await { (continuation) in
                try! Coroutine.delay(.seconds(2))
                continuation(["foo", "bar", "baz",])
            }
    
        }
    }
    
    func foo() {
        scheduler.startCoroutine {
            do {
                let something = try repo.getSomethingAsync()
                print(something)
            } catch {
                #warning("TODO: handle error")
            }
        }
    }
    

    However, this is fine:

    class SomeRepository {
        func getSomethingAsync() throws -> [String] {
            // getSomethingAsync is guaranteed to be called inside a coroutine
            try! Coroutine.delay(.seconds(2))
            return ["foo", "bar", "baz",]
        }
    }
    

    Not sure if this is expected behavior. If it is, I think it might be a good idea to mention dos and don'ts in the documentation.

    opened by funct7 3
  • Swift race access & stack buffer overflow

    Swift race access & stack buffer overflow

    Used memory sanitizer in xcode, and got crash:

    Crashed Thread: 13 Dispatch queue: com.apple.root.default-qos

    abort() called CoreSimulator 732.17 - Device: iPhone 8 (88037FF6-637E-4827-B62A-4BD2AD70CCE6) - Runtime: iOS 12.2 (16E226) - DeviceType: iPhone 8

    Exception Type: EXC_CRASH (SIGABRT) Exception Codes: 0x0000000000000000, 0x0000000000000000 Exception Note: EXC_CORPSE_NOTIFY

    Application Specific Information: ==49420==WARNING: ASan is ignoring requested __asan_handle_no_return: stack top: 0x700004312000; bottom 0x10013c25e000; size: 0x5ffec80b4000 (105547882512384) False positive error reports may follow

    SUMMARY: AddressSanitizer: stack-buffer-overflow (/Users/admin/Library/Developer/CoreSimulator/Devices/88037FF6-637E-4827-B62A-4BD2AD70CCE6/data/Containers/Bundle/Application/F8151562-99F5-44CC-8239-92715B85CBED/MyApp.app/Frameworks/libclang_rt.asan_iossim_dynamic.dylib:x86_64+0x17e70) in wrap_memcpy+0x3a0 Shadow bytes around the buggy address: 0x020155643f40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x020155643f50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x020155643f60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x020155643f70: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x020155643f80: 00 00 00 00 00 00 00 00 00 00 00 00 f1 f1 f1 f1 =>0x020155643f90:[01]f3 f3 f3 00 00 00 00 00 00 00 00 00 00 00 00 0x020155643fa0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x020155643fb0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x020155643fc0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x020155643fd0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x020155643fe0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 Shadow byte legend (one shadow byte represents 8 application bytes): Addressable: 00 Partially addressable: 01 02 03 04 05 06 07 Heap left redzone: fa Freed heap region: fd Stack left redzone: f1 Stack mid redzone: f2 Stack right redzone: f3 Stack after return: f5 Stack use after scope: f8 Global redzone: f9 Global init order: f6 Poisoned by user: f7 Container overflow: fc Array cookie: ac Intra object redzone: bb ASan internal: fe Left alloca redzone: ca Right alloca redzone: cb Shadow gap: cc ==49420==ABORTING

    Thread 13 Crashed:: Dispatch queue: com.apple.root.default-qos 0 libsystem_kernel.dylib 0x000000011029b33a __pthread_kill + 10 1 libsystem_pthread.dylib 0x00000001102f8e60 pthread_kill + 430 2 libsystem_c.dylib 0x000000011005e0bc __abort + 144 3 libsystem_c.dylib 0x000000011005e02c abort + 142 4 libclang_rt.asan_iossim_dynamic.dylib 0x0000000104024d06 __sanitizer::Abort() + 70 5 libclang_rt.asan_iossim_dynamic.dylib 0x00000001040246f4 __sanitizer::Die() + 196 6 libclang_rt.asan_iossim_dynamic.dylib 0x000000010400c374 __asan::ScopedInErrorReport::~ScopedInErrorReport() + 420 7 libclang_rt.asan_iossim_dynamic.dylib 0x000000010400bc0e __asan::ReportGenericError(unsigned long, unsigned long, unsigned long, unsigned long, bool, unsigned long, unsigned int, bool) + 1198 8 libclang_rt.asan_iossim_dynamic.dylib 0x0000000103fdbe90 wrap_memcpy + 960 9 org.cocoapods.SwiftCoroutine 0x000000010b657f45 SharedCoroutine.saveStack() + 2053 (SharedCoroutine.swift:78) 10 org.cocoapods.SwiftCoroutine 0x000000010b65fb97 SharedCoroutineQueue.start(dispatcher:scheduler:task:) + 1143 (SharedCoroutineQueue.swift:38) 11 org.cocoapods.SwiftCoroutine 0x000000010b65cba3 closure #1 in SharedCoroutineDispatcher.execute(on:task:) + 579 (SharedCoroutineDispatcher.swift:27) 12 org.cocoapods.SwiftCoroutine 0x000000010b623821 thunk for @escaping @callee_guaranteed () -> () + 145 13 libclang_rt.asan_iossim_dynamic.dylib 0x00000001040049cb __wrap_dispatch_async_block_invoke + 203 14 libdispatch.dylib 0x000000010ff02d7f _dispatch_call_block_and_release + 12 15 libdispatch.dylib 0x000000010ff03db5 _dispatch_client_callout + 8 16 libdispatch.dylib 0x000000010ff067b9 _dispatch_queue_override_invoke + 1022 17 libdispatch.dylib 0x000000010ff14632 _dispatch_root_queue_drain + 351 18 libdispatch.dylib 0x000000010ff14fca _dispatch_worker_thread2 + 130 19 libsystem_pthread.dylib 0x00000001102f59f7 _pthread_wqthread + 220 20 libsystem_pthread.dylib 0x00000001102f4b77 start_wqthread + 15

    WARNING: ThreadSanitizer: Swift access race (pid=51212) Modifying access of Swift variable at 0x7b1000453c18 by thread T19: #0 $s14SwiftCoroutine8CoFutureC11addCallbackyyys6ResultOyxs5Error_pGcF (SwiftCoroutine:x86_64+0x2bf68) #1 $s14SwiftCoroutine8CoFutureC12whenCanceledyyyycF (SwiftCoroutine:x86_64+0x33b15) #2 $s14SwiftCoroutine0B9SchedulerPAAE15coroutineFutureyAA02CoE0Cyqd__Gqd__yKclFyycfU_ (SwiftCoroutine:x86_64+0x4108d) #3 $s14SwiftCoroutine0B9SchedulerPAAE15coroutineFutureyAA02CoE0Cyqd__Gqd__yKclFyycfU_TA (SwiftCoroutine:x86_64+0x41445) #4 $s14SwiftCoroutine0B7ContextC12performBlock33_474932A1564BFE56FB9333EE19D4C48CLLSvyF (SwiftCoroutine:x86_64+0x3d172) #5 $s14SwiftCoroutine0B7ContextC5startSbyFySVSgcfU_ (SwiftCoroutine:x86_64+0x3d010) #6 $s14SwiftCoroutine0B7ContextC5startSbyFySVSgcfU_To (SwiftCoroutine:x86_64+0x3d330) #7 start (SwiftCoroutine:x86_64+0x3ffa) #8 $s14SwiftCoroutine0B7ContextC5startSbyF (SwiftCoroutine:x86_64+0x3ce5e) #9 $s14SwiftCoroutine06SharedB0C5startAA0cB5QueueC15CompletionStateOyFAHyXEfU_SbycAA0B7ContextCcfu_Sbycfu0 (SwiftCoroutine:x86_64+0x4b17d) #10 $s14SwiftCoroutine06SharedB0C5startAA0cB5QueueC15CompletionStateOyFAHyXEfU_SbycAA0B7ContextCcfu_Sbycfu0_TA (SwiftCoroutine:x86_64+0x4ea9d) #11 $s14SwiftCoroutine06SharedB0C7perform33_5CCAB8CB89EE233ADAF37DFE55B1ABD1LLyAA0cB5QueueC15CompletionStateOSbyXEF (SwiftCoroutine:x86_64+0x4b21f) #12 $s14SwiftCoroutine06SharedB0C5startAA0cB5QueueC15CompletionStateOyFAHyXEfU (SwiftCoroutine:x86_64+0x4b046) #13 $s14SwiftCoroutine06SharedB0C5startAA0cB5QueueC15CompletionStateOyFAHyXEfU_TA (SwiftCoroutine:x86_64+0x4b0ad) #14 $s14SwiftCoroutine06SharedB5QueueC15CompletionStateOIgd_AEIegr_TR (SwiftCoroutine:x86_64+0x4b4bb) #15 $s14SwiftCoroutine06SharedB5QueueC15CompletionStateOIgd_AEIegr_TRTA (SwiftCoroutine:x86_64+0x4b52d) #16 $s14SwiftCoroutine0B8ProtocolPAAE16performAsCurrentyqd__qd__yXElF (SwiftCoroutine:x86_64+0x3eae7) #17 $s14SwiftCoroutine06SharedB0C5startAA0cB5QueueC15CompletionStateOyF (SwiftCoroutine:x86_64+0x4af55) #18 $s14SwiftCoroutine06SharedB5QueueC5start10dispatcher9scheduler4taskyAA0cB10DispatcherC_AA0B9Scheduler_pyyctF (SwiftCoroutine:x86_64+0x510e0) #19 $s14SwiftCoroutine06SharedB10DispatcherC7execute2on4taskyAA0B9Scheduler_p_yyctFyycfU_ (SwiftCoroutine:x86_64+0x4f33b) #20 $s14SwiftCoroutine06SharedB10DispatcherC7execute2on4taskyAA0B9Scheduler_p_yyctFyycfU_TA (SwiftCoroutine:x86_64+0x4f414) #21 $sIeg_IeyB_TR (SwiftCoroutine:x86_64+0x2eec3) #22 __tsan::invoke_and_release_block(void*) (libclang_rt.tsan_iossim_dynamic.dylib:x86_64+0x70f1b) #23 _dispatch_client_callout (libdispatch.dylib:x86_64+0x3db4)

    Previous read of size 8 at 0x7b1000453c18 by thread T18: #0 $s14SwiftCoroutine13CallbackStackV6appendySbyxcF (SwiftCoroutine:x86_64+0x1e035) #1 $s14SwiftCoroutine8CoFutureC11addCallbackyyys6ResultOyxs5Error_pGcF (SwiftCoroutine:x86_64+0x2bfc4) #2 $s14SwiftCoroutine8CoFutureC5awaitxyKFs6ResultOyxs5Error_pGyKXEfu_yyAHccACyxGcfu0_yyAHccfu1_ (SwiftCoroutine:x86_64+0x2d7a6) #3 $s14SwiftCoroutine8CoFutureC5awaitxyKFs6ResultOyxs5Error_pGyKXEfu_yyAHccACyxGcfu0_yyAHccfu1_TA (SwiftCoroutine:x86_64+0x2f800) #4 $ss6ResultOyxs5Error_pGlyxIsegn_Igg_xlyADIsegn_Iegg_lTR (SwiftCoroutine:x86_64+0x2d814) #5 $ss6ResultOyxs5Error_pGlyxIsegn_Igg_xlyADIsegn_Iegg_lTRTA.1 (SwiftCoroutine:x86_64+0x2f7a6) #6 $s14SwiftCoroutine06SharedB0C5awaityxyyxcXEKlF (SwiftCoroutine:x86_64+0x4d200) #7 $s14SwiftCoroutine06SharedB0CAA0B8ProtocolA2aDP5awaityqd__yyqd__cXEKlFTW (SwiftCoroutine:x86_64+0x4e53a) #8 $s14SwiftCoroutine8CoFutureC5awaitxyKFs6ResultOyxs5Error_pGyKXEfu_ (SwiftCoroutine:x86_64+0x2d4e5) #9 $s14SwiftCoroutine8CoFutureC5awaitxyKFs6ResultOyxs5Error_pGyKXEfu_TA (SwiftCoroutine:x86_64+0x2d62f) #10 $s14SwiftCoroutine8CoFutureC5awaitxyKF (SwiftCoroutine:x86_64+0x2d0f9) #11 $s5MyApp19EntitiesServiceImplC4boot13launchOptions10completionySDySo019UIApplicationLaunchG3KeyaypGSg_y13ViperServices0lC10BootResultOctFyycfU_ (MyApp:x86_64+0x1004a07be) #12 $s5MyApp19EntitiesServiceImplC4boot13launchOptions10completionySDySo019UIApplicationLaunchG3KeyaypGSg_y13ViperServices0lC10BootResultOctFyycfU_TA (MyApp:x86_64+0x1004a1449) #13 $s14SwiftCoroutine0B9SchedulerPAAE05startB02in4taskyAA7CoScopeCSg_yyKctFyycfU_ (SwiftCoroutine:x86_64+0x3ffe6) #14 $s14SwiftCoroutine0B9SchedulerPAAE05startB02in4taskyAA7CoScopeCSg_yyKctFyycfU_TA (SwiftCoroutine:x86_64+0x400f5) #15 $s14SwiftCoroutine0B7ContextC12performBlock33_474932A1564BFE56FB9333EE19D4C48CLLSvyF (SwiftCoroutine:x86_64+0x3d172) #16 $s14SwiftCoroutine0B7ContextC5startSbyFySVSgcfU_ (SwiftCoroutine:x86_64+0x3d010) #17 $s14SwiftCoroutine0B7ContextC5startSbyFySVSgcfU_To (SwiftCoroutine:x86_64+0x3d330) #18 start (SwiftCoroutine:x86_64+0x3ffa) #19 $s14SwiftCoroutine0B7ContextC5startSbyF (SwiftCoroutine:x86_64+0x3ce5e) #20 $s14SwiftCoroutine06SharedB0C5startAA0cB5QueueC15CompletionStateOyFAHyXEfU_SbycAA0B7ContextCcfu_Sbycfu0 (SwiftCoroutine:x86_64+0x4b17d) #21 $s14SwiftCoroutine06SharedB0C5startAA0cB5QueueC15CompletionStateOyFAHyXEfU_SbycAA0B7ContextCcfu_Sbycfu0_TA (SwiftCoroutine:x86_64+0x4ea9d) #22 $s14SwiftCoroutine06SharedB0C7perform33_5CCAB8CB89EE233ADAF37DFE55B1ABD1LLyAA0cB5QueueC15CompletionStateOSbyXEF (SwiftCoroutine:x86_64+0x4b21f) #23 $s14SwiftCoroutine06SharedB0C5startAA0cB5QueueC15CompletionStateOyFAHyXEfU (SwiftCoroutine:x86_64+0x4b046) #24 $s14SwiftCoroutine06SharedB0C5startAA0cB5QueueC15CompletionStateOyFAHyXEfU_TA (SwiftCoroutine:x86_64+0x4b0ad) #25 $s14SwiftCoroutine06SharedB5QueueC15CompletionStateOIgd_AEIegr_TR (SwiftCoroutine:x86_64+0x4b4bb) #26 $s14SwiftCoroutine06SharedB5QueueC15CompletionStateOIgd_AEIegr_TRTA (SwiftCoroutine:x86_64+0x4b52d) #27 $s14SwiftCoroutine0B8ProtocolPAAE16performAsCurrentyqd__qd__yXElF (SwiftCoroutine:x86_64+0x3eae7) #28 $s14SwiftCoroutine06SharedB0C5startAA0cB5QueueC15CompletionStateOyF (SwiftCoroutine:x86_64+0x4af55) #29 $s14SwiftCoroutine06SharedB5QueueC5start10dispatcher9scheduler4taskyAA0cB10DispatcherC_AA0B9Scheduler_pyyctF (SwiftCoroutine:x86_64+0x510e0) #30 $s14SwiftCoroutine06SharedB10DispatcherC7execute2on4taskyAA0B9Scheduler_p_yyctFyycfU_ (SwiftCoroutine:x86_64+0x4f33b) ThreadSanitizer report breakpoint hit. Use 'thread info -s' to get extended information about the report. A 0 #31 $s14SwiftCoroutine06SharedB10DispatcherC7execute2on4taskyAA0B9Scheduler_p_yyctFyycfU_TA (SwiftCoroutine:x86_64+0x4f414) #32 $sIeg_IeyB_TR (SwiftCoroutine:x86_64+0x2eec3) #33 __tsan::invoke_and_release_block(void*) (libclang_rt.tsan_iossim_dynamic.dylib:x86_64+0x70f1b) #34 _dispatch_client_callout (libdispatch.dylib:x86_64+0x3db4)

    Location is heap block of size 64 at 0x7b1000453c00 allocated by thread T18: #0 malloc (libclang_rt.tsan_iossim_dynamic.dylib:x86_64+0x4ef1a) #1 swift_slowAlloc (libswiftCore.dylib:x86_64+0x2ce3c8) #2 $s14SwiftCoroutine9CoPromiseCACyxGycfC (SwiftCoroutine:x86_64+0x3784f) #3 $s14SwiftCoroutine0B9SchedulerPAAE15coroutineFutureyAA02CoE0Cyqd__Gqd__yKclF (SwiftCoroutine:x86_64+0x40bb6) #4 $s5MyApp19EntitiesServiceImplC16loadStoryEffects33_CF1F1424D0659537F27DBA3EFCD861E7LL14SwiftCoroutine8CoFutureCyytGyF (MyApp:x86_64+0x1004d8677) #5 $s5MyApp19EntitiesServiceImplC4boot13launchOpt[DefaultViperServicesContainer]: Still booting ["StateService", "ApphudService", "AnalyticsService", "ExtensionService", "GdprService", "PremiumService", "SmartNewsService", "PushNotificationsService"]ions10completionySDySo019UIApplicationLaunchG3KeyaypGSg_y13ViperServices0lC10BootResultOctFyycfU_ (MyApp:x86_64+0x1004a0791) #6 $s5MyApp19EntitiesServiceImplC4boot13launchOptions10completionySDySo019UIApplicationLaunchG3KeyaypGSg_y13ViperServices0lC10BootResultOctFyycfU_TA (MyApp:x86_64+0x1004a1449) #7 $s14SwiftCoroutine0B9SchedulerPAAE05startB02in4taskyAA7CoScopeCSg_yyKctFyycfU_ (SwiftCoroutine:x86_64+0x3ffe6) #8 $s14SwiftCoroutine0B9SchedulerPAAE05startB02in4taskyAA7CoScopeCSg_yyKctFyycfU_TA (SwiftCoroutine:x86_64+0x400f5) #9 $s14SwiftCoroutine0B7ContextC12performBlock33_474932A1564BFE56FB9333EE19D4C48CLLSvyF (SwiftCoroutine:x86_64+0x3d172) #10 $s14SwiftCoroutine0B7ContextC5startSbyFySVSgcfU_ (SwiftCoroutine:x86_64+0x3d010) #11 $s14SwiftCoroutin e0B7ContextC5startSbyFySVSgcfU_To (SwiftCoroutine:x86_64+0x3d330) #12 start (SwiftCoroutine:x86_64+0x3ffa) #13 $s14SwiftCoroutine0B7ContextC5startSbyF (SwiftCoroutine:x86_64+0x3ce5e) #14 $s14SwiftCoroutine06SharedB0C5startAA0cB5QueueC15CompletionStateOyFAHyXEfU_SbycAA0B7ContextCcfu_Sbycfu0 (SwiftCoroutine:x86_64+0x4b17d) #15 $s14SwiftCoroutine06SharedB0C5startAA0cB5QueueC15CompletionStateOyFAHyXEfU_SbycAA0B7ContextCcfu_Sbycfu0_TA (SwiftCoroutine:x86_64+0x4ea9d) #16 $s14SwiftCoroutine06SharedB0C7perform33_5CCAB8CB89EE233ADAF37DFE55B1ABD1LLyAA0cB5QueueC15CompletionStateOSbyXEF (SwiftCoroutine:x86_64+0x4b21f) #17 $s14SwiftCoroutine06SharedB0C5startAA0cB5QueueC15CompletionStateOyFAHyXEfU (SwiftCoroutine:x86_64+0x4b046) #18 $s14SwiftCoroutine06SharedB0C5startAA0cB5QueueC15CompletionStateOyFAHyXEfU_TA (SwiftCoroutine:x86_64+0x4b0ad) #19 $s14SwiftCoroutine06SharedB5QueueC15CompletionStateOIgd_AEIegr_TR (SwiftCoroutine:x86_64+0x4b4bb) #20 $s14SwiftCoroutine06SharedB5QueueC15CompletionStateOIgd_AEIegr_TRTA (SwiftCoroutine:x86_64+0x4b52d) #21 $s14SwiftCoroutine0B8ProtocolPAAE16performAsCurrentyqd__qd__yXElF (SwiftCoroutine:x86_64+0x3eae7) #22 $s14SwiftCoroutine06SharedB0C5startAA0cB5QueueC15CompletionStateOyF (SwiftCoroutine:x86_64+0x4af55) #23 $s14SwiftCoroutine06SharedB5QueueC5start10dispatcher9scheduler4taskyAA0cB10DispatcherC_AA0B9Scheduler_pyyctF (SwiftCoroutine:x86_64+0x510e0) #24 $s14SwiftCoroutine06SharedB10DispatcherC7execute2on4taskyAA0B9Scheduler_p_yyctFyycfU_ (SwiftCoroutine:x86_64+0x4f33b) #25 $s14SwiftCoroutine06SharedB10DispatcherC7execute2on4taskyAA0B9Scheduler_p_yyctFyycfU_TA (SwiftCoroutine:x86_64+0x4f414) #26 $sIeg_IeyB_TR (SwiftCoroutine:x86_64+0x2eec3) #27 __tsan::invoke_and_release_block(void*) (libclang_rt.tsan_iossim_dynamic.dylib:x86_64+0x70f1b) #28 _dispatch_client_callout (libdispatch.dylib:x86_64+0x3db4)

    Thread T19 (tid=5147481, running) is a GCD worker thread

    Thread T18 (tid=5147475, running) is a GCD worker thread

    SUMMARY: ThreadSanitizer: Swift access race (/Users/admin/Library/Developer/CoreSimulator/Devices/88037FF6-637E-4827-B62A-4BD2AD70CCE6/data/Containers/Bundle/Application/89A141C1-2DC8-4A6C-B3DB-65CC1E2A08F7/MyApp.app/Frameworks/SwiftCoroutine.framework/SwiftCoroutine:x86_64+0x2bf68) in $s14SwiftCoroutine8CoFutureC11addCallbackyyys6ResultOyxs5Error_pGcF+0x1f8

    ThreadSanitizer report breakpoint hit. Use 'thread info -s' to get extended information about the report.

    WARNING: ThreadSanitizer: Swift access race (pid=51212) Modifying access of Swift variable at 0x7b140011cb70 by thread T18: #0 $s14SwiftCoroutine06SharedB10DispatcherC4pushyyAA0cB5QueueCF (SwiftCoroutine:x86_64+0x4f912) #1 $s14SwiftCoroutine06SharedB5QueueC11performNext022_8C5C69B88B6EDEB22EAD6G9DF7AA0AADLL3foryAA0cB10DispatcherC_tF (SwiftCoroutine:x86_64+0x522d2) #2 $s14SwiftCoroutine06SharedB5QueueC8complete022_8C5C69B88B6EDEB22EAD6F9DF7AA0AADLL4withyAC15CompletionStateO_tF (SwiftCoroutine:x86_64+0x5160c) #3 $s14SwiftCoroutine06SharedB5QueueC5start10dispatcher9scheduler4taskyAA0cB10DispatcherC_AA0B9Scheduler_pyyctF (SwiftCoroutine:x86_64+0x51109) #4 $s14SwiftCoroutine0B7ContextC12performBlock33_474932A1564BFE56FB9333EE19D4C48CLLSvyF (SwiftCoroutine:x86_64+0x3d172) #5 $s14SwiftCoroutine0B7ContextC5startSbyFySVSgcfU_ (SwiftCoroutine:x86_64+0x3d010) #6 $s14SwiftCoroutine0B7ContextC5startSbyFySVSgcfU_To (SwiftCoroutine:x86_64+0x3d330) #7 start (SwiftCoroutine:x86_64+0x3ffa) #8 $s14SwiftCoroutine0B7ContextC5startSbyF (SwiftCoroutine:x86_64+0x3ce5e) #9 $s14SwiftCoroutine06SharedB0C5startAA0cB5QueueC15CompletionStateOyFAHyXEfU_SbycAA0B7ContextCcfu_Sbycfu0 (SwiftCoroutine:x86_64+0x4b17d) #10 $s14SwiftCoroutine06SharedB0C5startAA0cB5QueueC15CompletionStateOyFAHyXEfU_SbycAA0B7ContextCcfu_Sbycfu0_TA (SwiftCoroutine:x86_64+0x4ea9d) #11 $s14SwiftCoroutine06SharedB0C7perform33_5CCAB8CB89EE233ADAF37DFE55B1ABD1LLyAA0cB5QueueC15CompletionStateOSbyXEF (SwiftCoroutine:x86_64+0x4b21f) #12 $s14SwiftCoroutine06SharedB0C5startAA0cB5QueueC15CompletionStateOyFAHyXEfU (SwiftCoroutine:x86_64+0x4b046) #13 $s14SwiftCoroutine06SharedB0C5startAA0cB5QueueC15CompletionStateOyFAHyXEfU_TA (SwiftCoroutine:x86_64+0x4b0ad) #14 $s14SwiftCoroutine06SharedB5QueueC15CompletionStateOIgd_AEIegr_TR (SwiftCoroutine:x86_64+0x4b4bb) #15 $s14SwiftCoroutine06SharedB5QueueC15CompletionStateOIgd_AEIegr_TRTA (SwiftCoroutine:x86_64+0x4b52d) #16 $s14SwiftCoroutine0B8ProtocolPAAE16performAsCurrentyqd__qd__yXElF (SwiftCoroutine:x86_64+0x3eae7) #17 $s14SwiftCoroutine06SharedB0C5startAA0cB5QueueC15CompletionStateOyF (SwiftCoroutine:x86_64+0x4af55) #18 $s14SwiftCoroutine06SharedB5QueueC5start10dispatcher9scheduler4taskyAA0cB10DispatcherC_AA0B9Scheduler_pyyctF (SwiftCoroutine:x86_64+0x510e0) #19 $s14SwiftCoroutine06SharedB10DispatcherC7execute2on4taskyAA0B9Scheduler_p_yyctFyycfU_ (SwiftCoroutine:x86_64+0x4f33b) #20 $s14SwiftCoroutine06SharedB10DispatcherC7execute2on4taskyAA0B9Scheduler_p_yyctFyycfU_TA (SwiftCoroutine:x86_64+0x4f414) #21 $sIeg_IeyB_TR (SwiftCoroutine:x86_64+0x2eec3) #22 __tsan::invoke_and_release_block(void*) (libclang_rt.tsan_iossim_dynamic.dylib:x86_64+0x70f1b) #23 _dispatch_client_callout (libdispatch.dylib:x86_64+0x3db4)

    Previous modifying access of Swift variable at 0x7b140011cb70 by thread T19: #0 $s14SwiftCoroutine9FifoQueueV3popxSgyF (SwiftCoroutine:x86_64+0x474bf) #1 $s14SwiftCoroutine06SharedB10DispatcherC12getFreeQueue33_1A5FB05E2411224CDC4772F9B26581BDLLAA0cbG0CyF (SwiftCoroutine:x86_64+0x4f50d) #2 $s14SwiftCoroutine06SharedB10DispatcherC7execute2on4taskyAA0B9Scheduler_p_yyctFyycfU_ (SwiftCoroutine:x86_64+0x4f31c) #3 $s14SwiftCoroutine06SharedB10DispatcherC7execute2on4taskyAA0B9Scheduler_p_yyctFyycfU_TA (SwiftCoroutine:x86_64+0x4f414) #4 $sIeg_IeyB_TR (SwiftCoroutine:x86_64+0x2eec3) #5 __tsan::invoke_and_release_block(void*) (libclang_rt.tsan_iossim_dynamic.dylib:x86_64+0x70f1b) #6 _dispatch_client_callout (libdispatch.dylib:x86_64+0x3db4)

    Location is heap block of size 72 at 0x7b140011cb50 allocated by main thread: #0 malloc (libclang_rt.tsan_iossim_dynamic.dylib:x86_64+0x4ef1a) #1 swift_slowAlloc (libswiftCore.dylib:x86_64+0x2ce3c8) #2 globalinit_33_1A5FB05E2411224CDC4772F9B26581BD_func0 (SwiftCoroutine:x86_64+0x4eb5b) #3 dispatch_once (libclang_rt.tsan_iossim_dynamic.dylib:x86_64+0x71794) #4 dispatch_once_f (libclang_rt.tsan_iossim_dynamic.dylib:x86_64+0x71880) #5 swift_once (libswiftCore.dylib:x86_64+0x2f0578) #6 $s14SwiftCoroutine0B9SchedulerPAAE06_startB0yyyycF (SwiftCoroutine:x86_64+0x3fb20) #7 $s14SwiftCoroutine0B9SchedulerPAAE05startB02in4taskyAA7CoScopeCSg_yyKctF (SwiftCoroutine:x86_64+0x3ff2c) #8 $s5MyApp19EntitiesServiceImplC4boot13launchOptions10completionySDySo019UIApplicationLaunchG3KeyaypGSg_y13ViperServices0lC10BootResultOctF (MyApp:x86_64+0x1004a04ca) #9 $s5MyApp19EntitiesServiceImplC13ViperServices0eC0AadEP4boot13launchOptions10completionySDySo019UIApplicationLaunchI3KeyaypGSg_yAD0eC10BootResultOctFTW (MyApp:x86_64+0x1004e3e88) #10 $s13ViperServices07DefaultaB9ContainerC4boot13launchOptions10completionySDySo019UIApplicationLaunchG3KeyaypGSg_yAA0abD10BootResultOctFyyyccfU_0E4NextL_yyFyycfU3_ (ViperServices:x86_64+0xff28) #11 $s13ViperServices07DefaultaB9ContainerC4boot13launchOptions10completionySDySo019UIApplicationLaunchG3KeyaypGSg_yAA0abD10BootResultOctFyyyccfU_0E4NextL_yyFyycfU3_TA (ViperServices:x86_64+0x1c58c) #12 $s13ViperServices07DefaultaB9ContainerC4boot13launchOptions10completionySDySo019UIApplicationLaunchG3KeyaypGSg_yAA0abD10BootResultOctFyyyccfU_0E4NextL_yyFyycfU4_ (ViperServices:x86_64+0x112f7) #13 $s13ViperServices07DefaultaB9ContainerC4boot13launchOptions10completionySDySo019UIApplicationLaunchG3KeyaypGSg_yAA0abD10BootResultOctFyyyccfU_0E4NextL_yyFyycfU4_TA (ViperServices:x86_64+0x1c625) #14 $sIeg_IeyB_TR (ViperServices:x86_64+0x11393) #15 __tsan::invoke_and_release_block(void*) (libclang_rt.tsan_iossim_dynamic.dylib:x86_64+0x70f1b) #16 _dispatch_client_callout (libdispatch.dylib:x86_64+0x3db4) #17 start (libdyld.dylib:x86_64+0x1540)

    Thread T18 (tid=5147475, running) is a GCD worker thread

    Thread T19 (tid=5147481, running) is a GCD worker thread

    SUMMARY: ThreadSanitizer: Swift access race (/Users/admin/Library/Developer/CoreSimulator/Devices/88037FF6-637E-4827-B62A-4BD2AD70CCE6/data/Containers/Bundle/Application/89A141C1-2DC8-4A6C-B3DB-65CC1E2A08F7/MyApp.app/Frameworks/SwiftCoroutine.framework/SwiftCoroutine:x86_64+0x4f912) in $s14SwiftCoroutine06SharedB10DispatcherC4pushyyAA0cB5QueueCF+0x222

    ThreadSanitizer report breakpoint hit. Use 'thread info -s' to get extended information about the report.

    WARNING: ThreadSanitizer: Swift access race (pid=51212) Modifying access of Swift variable at 0x7b140011cb80 by thread T18: #0 $s14SwiftCoroutine9FifoQueueV4pushyyxF (SwiftCoroutine:x86_64+0x45dff) #1 $s14SwiftCoroutine06SharedB10DispatcherC4pushyyAA0cB5QueueCF (SwiftCoroutine:x86_64+0x4f934) #2 $s14SwiftCoroutine06SharedB5QueueC11performNext022_8C5C69B88B6EDEB22EAD6G9DF7AA0AADLL3foryAA0cB10DispatcherC_tF (SwiftCoroutine:x86_64+0x522d2) #3 $s14SwiftCoroutine06SharedB5QueueC8complete022_8C5C69B88B6EDEB22EAD6F9DF7AA0AADLL4withyAC15CompletionStateO_tF (SwiftCoroutine:x86_64+0x5160c) #4 $s14SwiftCoroutine06SharedB5QueueC5start10dispatcher9scheduler4taskyAA0cB10DispatcherC_AA0B9Scheduler_pyyctF (SwiftCoroutine:x86_64+0x51109) #5 $s14SwiftCoroutine0B7ContextC12performBlock33_474932A1564BFE56FB9333EE19D4C48CLLSvyF (SwiftCoroutine:x86_64+0x3d172) #6 $s14SwiftCoroutine0B7ContextC5startSbyFySVSgcfU_ (SwiftCoroutine:x86_64+0x3d010) #7 $s14SwiftCoroutine0B7ContextC5startSbyFySVSgcfU_To (SwiftCoroutine:x86_64+0x3d330) #8 start (SwiftCoroutine:x86_64+0x3ffa) #9 $s14SwiftCoroutine0B7ContextC5startSbyF (SwiftCoroutine:x86_64+0x3ce5e) #10 $s14SwiftCoroutine06SharedB0C5startAA0cB5QueueC15CompletionStateOyFAHyXEfU_SbycAA0B7ContextCcfu_Sbycfu0 (SwiftCoroutine:x86_64+0x4b17d) #11 $s14SwiftCoroutine06SharedB0C5startAA0cB5QueueC15CompletionStateOyFAHyXEfU_SbycAA0B7ContextCcfu_Sbycfu0_TA (SwiftCoroutine:x86_64+0x4ea9d) #12 $s14SwiftCoroutine06SharedB0C7perform33_5CCAB8CB89EE233ADAF37DFE55B1ABD1LLyAA0cB5QueueC15CompletionStateOSbyXEF (SwiftCoroutine:x86_64+0x4b21f) #13 $s14SwiftCoroutine06SharedB0C5startAA0cB5QueueC15CompletionStateOyFAHyXEfU (SwiftCoroutine:x86_64+0x4b046) #14 $s14SwiftCoroutine06SharedB0C5startAA0cB5QueueC15CompletionStateOyFAHyXEfU_TA (SwiftCoroutine:x86_64+0x4b0ad) #15 $s14SwiftCoroutine06SharedB5QueueC15CompletionStateOIgd_AEIegr_TR (SwiftCoroutine:x86_64+0x4b4bb) #16 $s14SwiftCoroutine06SharedB5QueueC15CompletionStateOIgd_AEIegr_TRTA (SwiftCoroutine:x86_64+0x4b52d) #17 $s14SwiftCoroutine0B8ProtocolPAAE16performAsCurrentyqd__qd__yXElF (SwiftCoroutine:x86_64+0x3eae7) #18 $s14SwiftCoroutine06SharedB0C5startAA0cB5QueueC15CompletionStateOyF (SwiftCoroutine:x86_64+0x4af55) #19 $s14SwiftCoroutine06SharedB5QueueC5start10dispatcher9scheduler4taskyAA0cB10DispatcherC_AA0B9Scheduler_pyyctF (SwiftCoroutine:x86_64+0x510e0) #20 $s14SwiftCoroutine06SharedB10DispatcherC7execute2on4taskyAA0B9Scheduler_p_yyctFyycfU_ (SwiftCoroutine:x86_64+0x4f33b) #21 $s14SwiftCoroutine06SharedB10DispatcherC7execute2on4taskyAA0B9Scheduler_p_yyctFyycfU_TA (SwiftCoroutine:x86_64+0x4f414) #22 $sIeg_IeyB_TR (SwiftCoroutine:x86_64+0x2eec3) #23 __tsan::invoke_and_release_block(void*) (libclang_rt.tsan_iossim_dynamic.dylib:x86_64+0x70f1b) #24 _dispatch_client_callout (libdispatch.dylib:x86_64+0x3db4)

    Previous write of size 1 at 0x7b140011cb80 by thread T19: [failed to restore the stack]

    Location is heap block of size 72 at 0x7b140011cb50 allocated by main thread: #0 malloc (libclang_rt.tsan_iossim_dynamic.dylib:x86_64+0x4ef1a) #1 swift_slowAlloc (libswiftCore.dylib:x86_64+0x2ce3c8) #2 globalinit_33_1A5FB05E2411224CDC4772F9B26581BD_func0 (SwiftCoroutine:x86_64+0x4eb5b) #3 dispatch_once (libclang_rt.tsan_iossim_dynamic.dylib:x86_64+0x71794) #4 dispatch_once_f (libclang_rt.tsan_iossim_dynamic.dylib:x86_64+0x71880) #5 swift_once (libswiftCore.dylib:x86_64+0x2f0578) #6 $s14SwiftCoroutine0B9SchedulerPAAE06_startB0yyyycF (SwiftCoroutine:x86_64+0x3fb20) #7 $s14SwiftCoroutine0B9SchedulerPAAE05startB02in4taskyAA7CoScopeCSg_yyKctF (SwiftCoroutine:x86_64+0x3ff2c) #8 $s5MyApp19EntitiesServiceImplC4boot13launchOptions10completionySDySo019UIApplicationLaunchG3KeyaypGSg_y13ViperServices0lC10BootResultOctF (MyApp:x86_64+0x1004a04ca) #9 $s5MyApp19EntitiesServiceImplC13ViperServices0eC0AadEP4boot13launchOptions10completionySDySo019UIApplicationLaunchI3KeyaypGSg_yAD0eC10BootResultOctFTW (MyApp:x86_64+0x1004e3e88) #10 $s13ViperServices07DefaultaB9ContainerC4boot13launchOptions10completionySDySo019UIApplicationLaunchG3KeyaypGSg_yAA0abD10BootResultOctFyyyccfU_0E4NextL_yyFyycfU3_ (ViperServices:x86_64+0xff28) #11 $s13ViperServices07DefaultaB9ContainerC4boot13launchOptions10completionySDySo019UIApplicationLaunchG3KeyaypGSg_yAA0abD10BootResultOctFyyyccfU_0E4NextL_yyFyycfU3_TA (ViperServices:x86_64+0x1c58c) #12 $s13ViperServices07DefaultaB9ContainerC4boot13launchOptions10completionySDySo019UIApplicationLaunchG3KeyaypGSg_yAA0abD10BootResultOctFyyyccfU_0E4NextL_yyFyycfU4_ (ViperServices:x86_64+0x112f7) #13 $s13ViperServices07DefaultaB9ContainerC4boot13launchOptions10completionySDySo019UIApplicationLaunchG3KeyaypGSg_yAA0abD10BootResultOctFyyyccfU_0E4NextL_yyFyycfU4_TA (ViperServices:x86_64+0x1c625) #14 $sIeg_IeyB_TR (ViperServices:x86_64+0x11393) #15 __tsan::invoke_and_release_block(void*) (libclang_rt.tsan_iossim_dynamic.dylib:x86_64+0x70f1b) #16 _dispatch_client_callout (libdispatch.dylib:x86_64+0x3db4) #17 start (libdyld.dylib:x86_64+0x1540)

    Thread T18 (tid=5147475, running) is a GCD worker thread

    Thread T19 (tid=5147481, running) is a GCD worker thread

    SUMMARY: ThreadSanitizer: Swift access race (/Users/admin/Library/Developer/CoreSimulator/Devices/88037FF6-637E-4827-B62A-4BD2AD70CCE6/data/Containers/Bundle/Application/89A141C1-2DC8-4A6C-B3DB-65CC1E2A08F7/MyApp.app/Frameworks/SwiftCoroutine.framework/SwiftCoroutine:x86_64+0x45dff) in $s14SwiftCoroutine9FifoQueueV4pushyyxF+0x38f

    opened by ladeiko 3
  • Crash using recursion inside a coroutine

    Crash using recursion inside a coroutine

    Hi, I am experiencing crashes in our code when using intense recursion (lots of recursive calls) inside a coroutine block. I have been able to reproduce it in a test inside the project. This is the code:

        func testRecursive() {
            let exp = expectation(description: "testRecursive")
            exp.expectedFulfillmentCount = 1
            DispatchQueue.global().startCoroutine {
                try self.recursiveFunction(count: 0)
                exp.fulfill()
            }
            wait(for: [exp], timeout: 3)
        }
        
        private func recursiveFunction(count: Int) throws {
            let _ = try Coroutine.await { callback in
                DispatchQueue.global().async {
                    callback("random_response")
                }
            }
            print(count)
            if count < 10000 {
                try recursiveFunction(count: count + 1)
            }
        }
    

    The number of iterations that made the code crash depends on the size of the returned result in the callback function; a more complex object will make the code crash before.

    I've tried using Coroutine.await as in this sample code, but also using CoFuture but it'll always crash eventually. Is it a memory issue? Am I doing something conceptually wrong here?

    Thank you!

    opened by roisg 3
  • Pure Swift Possible?

    Pure Swift Possible?

    This library looks great. I have been trying to integrate it in an XCFramework I have. There is an issue, I am having, because it defines a C module, it turns on "Defines Module" if you turn on "Defines Module" and BUILD_LIBRARIES_FOR_DISTRIBUTION then the SwiftInterface files are not generated for that module. Not sure if this is correct behavior but it is the behavior, none the less.

    See this project for an example of the issue (turning off Defines Module lets it generate the swiftinterface files). https://github.com/possen/HostApp. Turning it off, means it won't import in Application because the swiftintface files are missing.

    The question becomes is there a way to either not enable "defines module" for the whole project, just that one C module, or do a pure Swift implementation?

    opened by possen 3
  • Can a `CoChannel` have multiple receivers?

    Can a `CoChannel` have multiple receivers?

    I have two objects that call makeIterator() on the same instance of a CoChannel, and only the first caller is receiving values:

    class SomeClass {
        func observe(channel: CoChannel<SomeData?>) {
            scheduler.startCoroutine(in: scope) { [weak self] in
                for item in channel.makeIterator() {
                    self?.item = item
                }
            }
        }
    }
    
    let obj1 = SomeClass()
    let obj2 = SomeClass()
    
    obj1.observe(channel: someChannel) // this one receives
    obj2.observe(channel: someChannel) // this one doesn't
    
    

    It seems like all the methods on a CoChannel only allow consuming the value (remove and return), and I'm guessing that may be the reason the second observer never receives anything.

    Is it possible to just peek, and therefore allow have multiple observers, like Observable of Rx or SharedFlow of Kotlin coroutine?

    opened by funct7 2
  • Is there an equivalent to

    Is there an equivalent to "onError" for `CoChannel`s?

    Looking at the documentation and test codes, it doesn't seem like there is a way to signal the cause of the cancellation of the channel. I think it would be nice to know why the channel was aborted.

    opened by funct7 0
  • Inline assembly unavailable on watchOS and tvOS

    Inline assembly unavailable on watchOS and tvOS

    opened by palle-k 0
  • A certain nested coroutines causes LLDB RPC Server crash on a breakpoint

    A certain nested coroutines causes LLDB RPC Server crash on a breakpoint

    For the following code, if I put a breakpoint on line where let a is in Xcode, LLDB debug server will crash.

    If I start the initial coroutine on main queue instead of global, or if I remove the middle CoFuture, no crashes would happen when the breakpoint hits.

    import UIKit
    import SwiftCoroutine
    
    class ViewController: UIViewController {
    
        override func viewDidLoad() {
            super.viewDidLoad()
            
            DispatchQueue.global().startCoroutine {
                try CoFuture<Void> {
                    try DispatchQueue.main.await {
                        let a = 1 /* SET BREAKPOINT ON THIS LINE*/
                    }
                }.await()
            }
        }
    
    }
    
    Message from debugger: The LLDB RPC server has crashed. The crash log is located in ~/Library/Logs/DiagnosticReports and has a prefix 'lldb-rpc-server'. Please file a bug and attach the most recent crash log.
    

    Unfortunately, when this crash happens, no actual diagnostic files are actually generated.

    opened by heshuimu 4
  • An equivalent of Go's `select` statement?

    An equivalent of Go's `select` statement?

    Another feature request: Go has a select statement that facilitates the use of multiple channels simultaneously for timers, out-of-band control, etc.

    Are you planning to add something similar?

    https://tour.golang.org/concurrency/5

    opened by ckornher 5
Releases(2.1.11)
Tools for using Swift Concurrency on macOS 10.15 Catalina, iOS 13, tvOS 13, and watchOS 6.

ConcurrencyCompatibility Tools for using Swift Concurrency on macOS 10.15 Catalina, iOS 13, tvOS 13, and watchOS 6. Xcode 13.2 adds backwards deployme

Zachary Waldowski 9 Jan 3, 2023
Pomodoro is a macOS status bar application written in SwiftUI, which allows you to control your work and break time, exploiting the pomodoro-technique.

Pomodoro Pomodoro is a macOS status bar application which allows you to control your work and break time. Through this application you will be able to

Cristian Turetta 7 Dec 28, 2022
THORChain vault churn countdown timer for macOS tray

ChurnCountdown Useful macOS tray app to show THORChain churn countdown. On start

null 0 Jan 5, 2022
Async and concurrent versions of Swift’s forEach, map, flatMap, and compactMap APIs.

CollectionConcurrencyKit Welcome to CollectionConcurrencyKit, a lightweight Swift package that adds asynchronous and concurrent versions of the standa

John Sundell 684 Jan 9, 2023
Slack message generator and API client, written in Swift with Result Builders and Concurrency

Slack Message Client This package provides a Swift object model for a Slack Block Kit message, as well as a Result Builder convenience interface for e

Mike Lewis 2 Jul 30, 2022
Automatically generate GraphQL queries and decode results into Swift objects, and also interact with arbitrary GitHub API endpoints

GitHub API and GraphQL Client This package provides a generic GitHub API client (GithubApiClient) as well as Codable-like GitHub GraphQL querying and

Mike Lewis 4 Aug 6, 2022
Make your logic flow and data flow clean and human readable

Flow What's Flow Flow is an utility/ design pattern that help developers to write simple and readable code. There are two main concerns: Flow of opera

null 18 Jun 17, 2022
Extensions and additions to AsyncSequence, AsyncStream and AsyncThrowingStream.

Asynchone Extensions and additions to AsyncSequence, AsyncStream and AsyncThrowingStream. Requirements iOS 15.0+ macOS 12.0+ Installation Swift Packag

Red Davis 101 Jan 6, 2023
straightforward networking and error handling with async-await and URLSession

AsyncAwaitNetworkingPlayground How To Run Just clone the project, open it and run. Some notes about AsyncAwaitNetworkingPlayground It's a straightforw

Fırat Yenidünya 17 Dec 11, 2022
Job Scheduler for IOS with Concurrent run, failure/retry, persistence, repeat, delay and more

SwiftQueue Schedule tasks with constraints made easy. SwiftQueue is a job scheduler for iOS inspired by popular android libraries like android-priorit

Lucas Nelaupe 367 Dec 24, 2022
iOS 13-compatible backports of commonly used async/await-based system APIs that are only available from iOS 15 by default.

AsyncCompatibilityKit Welcome to AsyncCompatibilityKit, a lightweight Swift package that adds iOS 13-compatible backports of commonly used async/await

John Sundell 367 Jan 5, 2023
A complete set of primitives for concurrency and reactive programming on Swift

A complete set of primitives for concurrency and reactive programming on Swift 1.4.0 is the latest and greatest, but only for Swift 4.2 and 5.0 use 1.

AsyncNinja 156 Aug 31, 2022
GroupWork is an easy to use Swift framework that helps you orchestrate your concurrent, asynchronous functions in a clean and organized way

GroupWork is an easy to use Swift framework that helps you orchestrate your concurrent, asynchronous functions in a clean and organized way. This help

Quan Vo 42 Oct 5, 2022
Queues, timers, and task groups in Swift

Dispatcher eases the pain of using Grand Central Dispatch by introducing 4 new Swift classes. Dispatcher Queue Group Timer Requirements Swift 2.0+ Ins

Alec Larson 109 Jan 29, 2022
Syntactic sugar in Swift for asynchronous dispatches in Grand Central Dispatch (iOS7+ and OS X 10.9+ compatible)

Async.legacy Syntactic sugar in Swift for asynchronous dispatches in Grand Central Dispatch (GCD) Async rewritten for iOS7 and OS X 10.9 Compatibility

Joseph Lord 31 Jul 1, 2019
A Swift DSL that allows concise and effective concurrency manipulation

NOTE Brisk is being mothballed due to general incompatibilities with modern version of Swift. I recommend checking out ReactiveSwift, which solves man

Jason Fieldman 25 May 24, 2019
⚡️ Fast async task based Swift framework with focus on type safety, concurrency and multi threading

Our apps constantly do work. The faster you react to user input and produce an output, the more likely is that the user will continue to use your appl

Said Sikira 814 Oct 30, 2022
A lightweight swift network layer with Combine, Async-Await, and a traditional completion block.

CombineNetwork A simple light-weight network library to make network requesting simpler. It supports newer techonology such as async/await as well as

Dushant Singh 4 Jan 3, 2022
The projects and materials that accompany the Modern Concurrency in Swift book

Modern Concurrency in Swift: Materials This repo contains all the downloadable materials and projects associated with the Modern Concurrency in Swift

raywenderlich 137 Dec 16, 2022