Skip to content

feat: Initial implementation of many GCD API's using Swift Concurrency #1

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 39 commits into
base: main
Choose a base branch
from

Conversation

scottmarchant
Copy link
Collaborator

@scottmarchant scottmarchant commented Jun 27, 2025

Summary

Initial implementation of common GCD API's using Swift Concurrency. The goal of this implementation is to enable wasm compilation for many repositories that currently use GCD.

Note this is a critical part of larger effort to compile several open source Swift repositories to wasm

Details

DispatchAsync is a temporary experimental repository aimed at implementing missing Dispatch support in the SwiftWasm toolchain.
Currently, SwiftWasm doesn't include Dispatch.
But, SwiftWasm does support Swift Concurrency. DispatchAsync implements a number of common Dispatch API's using Swift Concurrency under the hood.

Refer to the README updates in this PR for more details.

@scottmarchant scottmarchant marked this pull request as draft June 27, 2025 20:28
@scottmarchant scottmarchant marked this pull request as ready for review June 30, 2025 18:48
@@ -0,0 +1,42 @@
name: Pull request
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a note, I plan to add much more extensive testing in my next PR for this repo coming the in the next week or two. I did add some basic tests just for sanity, though.

I've also tested this manually in consumption from several different repositories, and in the browser runtime in a wasm build.

It works.

# dispatch-async
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would probably be a good idea to read this readme first, before reviewing the rest of the code in this PR. I explain a bit here.


public var uptimeNanoseconds: UInt64 {
let beginning = uptimeBeginning
let rightNow = DispatchTime.now()
Copy link
Collaborator Author

@scottmarchant scottmarchant Jul 3, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oops. I wrote a bad bug here. Just found it with some new test code I'm writing. For some reason I was thinking of this function as a static variable, but it's not, it's a member variable. So we should NOT be calling DispatchTime.now() in here.

Working on a fix now.

I'll put up relevant tests in a follow on PR, as this PR is already a bit too big.

}
}
} else {
Task {
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Found another bug with a new test I'm writing. This works if the attribute is .concurrent. But queues are supposed to be serial by default. And this is definitely NOT serial. 😅

Will fix this as well.

@@ -0,0 +1,20 @@
// swift-tools-version: 6.1

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: Consider reducing the swift-tools-version if not using 6.1 features to support a wider swath of environments. GitLab in particular doesn't have a macOS SaaS runner that uses Swift 6.1 yet.


/// Provides a semaphore implantation in `async` context, with a safe wait method. Provides easy safer replacement
/// for DispatchSemaphore usage.
@available(macOS 10.15, *)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since so many of the APIs are gated behind macOS >= 10.15, should we just pin macOS 10.15 as the minimum version in Package.swift?

#else

@available(macOS 10.15, *)
typealias DispatchSemaphore = AsyncSemaphore

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this need to be public to be usable for non-WASI compilation targets?

return value
}

public func wait() {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be marked async to match AsyncSemaphore even if it calls no await?

//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2025 Apple Inc. and the Swift.org project authors

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe all the headers should be copywrite "PassiveLogic", not "Apple Inc.".

What do you think about removing this large header until it gets adoption into the Swift project itself?

@available(macOS 10.15, *)
public class DispatchGroup: @unchecked Sendable {
/// Used to ensure FIFO access to the enter and leave calls
@globalActor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How does forcing this onto the global actor impact separately instantiated DispatchGroups? It seems like it would force all of them to execute sequentially, interleaving the results. i.e. Not only is this FIFO within the group, it looks like it's globally FIFO.

If this is the intended behavior, given that WASM is single-threaded, could we enforce or document that to avoid any expectation that this would operate in a multithreaded swift-concurrency environment?

}
}

// NOTE: The following was copied from swift-nio/Source/NIOCore/TimeAmount+Duration on June 27, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: A GitHub permalink might be a nicer way to reference the source of this code.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants