Skip to content

Allow building a concurrent libSwiftConcurrency without libdispatch #39480

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

Merged
merged 1 commit into from
Sep 28, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions include/swift/Runtime/Concurrency.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,22 @@
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wreturn-type-c-linkage"

// Does the runtime use a cooperative global executor?
#if defined(SWIFT_STDLIB_SINGLE_THREADED_RUNTIME)
#define SWIFT_CONCURRENCY_COOPERATIVE_GLOBAL_EXECUTOR 1
#else
#define SWIFT_CONCURRENCY_COOPERATIVE_GLOBAL_EXECUTOR 0
#endif

// Does the runtime integrate with libdispatch?
#ifndef SWIFT_CONCURRENCY_ENABLE_DISPATCH
#if SWIFT_CONCURRENCY_COOPERATIVE_GLOBAL_EXECUTOR
#define SWIFT_CONCURRENCY_ENABLE_DISPATCH 0
#else
#define SWIFT_CONCURRENCY_ENABLE_DISPATCH 1
#endif
#endif

namespace swift {
class DefaultActor;
class TaskOptionRecord;
Expand Down Expand Up @@ -661,10 +677,14 @@ void swift_task_enqueueGlobalWithDelay(unsigned long long delay, Job *job);
SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift)
void swift_task_enqueueMainExecutor(Job *job);

#if SWIFT_CONCURRENCY_ENABLE_DISPATCH

/// Enqueue the given job on the main executor.
SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift)
void swift_task_enqueueOnDispatchQueue(Job *job, HeapObject *queue);

#endif

/// A hook to take over global enqueuing.
typedef SWIFT_CC(swift) void (*swift_task_enqueueGlobal_original)(Job *job);
SWIFT_EXPORT_FROM(swift_Concurrency)
Expand Down Expand Up @@ -806,6 +826,17 @@ void swift_task_reportUnexpectedExecutor(
SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift)
JobPriority swift_task_getCurrentThreadPriority(void);

#if SWIFT_CONCURRENCY_COOPERATIVE_GLOBAL_EXECUTOR

/// Donate this thread to the global executor until either the
/// given condition returns true or we've run out of cooperative
/// tasks to run.
SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift)
void swift_task_donateThreadToGlobalExecutorUntil(bool (*condition)(void*),
void *context);

#endif

#ifdef __APPLE__
/// A magic symbol whose address is the mask to apply to a frame pointer to
/// signal that it is an async frame. Do not try to read the actual value of
Expand Down
2 changes: 1 addition & 1 deletion stdlib/public/Concurrency/Actor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@
#include "TaskPrivate.h"
#include "VoucherSupport.h"

#if !SWIFT_CONCURRENCY_COOPERATIVE_GLOBAL_EXECUTOR
#if SWIFT_CONCURRENCY_ENABLE_DISPATCH
#include <dispatch/dispatch.h>
#endif

Expand Down
5 changes: 5 additions & 0 deletions stdlib/public/Concurrency/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,11 @@ endif()
set(SWIFT_RUNTIME_CONCURRENCY_C_FLAGS)
set(SWIFT_RUNTIME_CONCURRENCY_SWIFT_FLAGS)

if(NOT SWIFT_CONCURRENCY_USES_DISPATCH)
list(APPEND SWIFT_RUNTIME_CONCURRENCY_C_FLAGS
"-DSWIFT_CONCURRENCY_ENABLE_DISPATCH=0")
endif()

if(NOT swift_concurrency_async_fp_mode)
set(swift_concurrency_async_fp_mode "always")
endif()
Expand Down
29 changes: 23 additions & 6 deletions stdlib/public/Concurrency/GlobalExecutor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@
#include "TaskPrivate.h"
#include "Error.h"

#if !SWIFT_CONCURRENCY_COOPERATIVE_GLOBAL_EXECUTOR
#if SWIFT_CONCURRENCY_ENABLE_DISPATCH
#include <dispatch/dispatch.h>

#if !defined(_WIN32)
Expand Down Expand Up @@ -178,15 +178,21 @@ static Job *claimNextFromJobQueue() {
}
}

void swift::donateThreadToGlobalExecutorUntil(bool (*condition)(void *),
void *conditionContext) {
void swift::
swift_task_donateThreadToGlobalExecutorUntil(bool (*condition)(void *),
void *conditionContext) {
while (!condition(conditionContext)) {
auto job = claimNextFromJobQueue();
if (!job) return;
swift_job_run(job, ExecutorRef::generic());
}
}

#elif !SWIFT_CONCURRENCY_ENABLE_DISPATCH

// No implementation. The expectation is that integrators in this
// configuration will hook all the appropriate functions.

#else

// Ensure that Job's layout is compatible with what Dispatch expects.
Expand Down Expand Up @@ -330,6 +336,9 @@ static void swift_task_enqueueGlobalImpl(Job *job) {

#if SWIFT_CONCURRENCY_COOPERATIVE_GLOBAL_EXECUTOR
insertIntoJobQueue(job);
#elif !SWIFT_CONCURRENCY_ENABLE_DISPATCH
swift_reportError(0, "operation unsupported without libdispatch: "
"swift_task_enqueueGlobal");
#else
// We really want four things from the global execution service:
// - Enqueuing work should have minimal runtime and memory overhead.
Expand Down Expand Up @@ -385,6 +394,9 @@ static void swift_task_enqueueGlobalWithDelayImpl(unsigned long long delay,

#if SWIFT_CONCURRENCY_COOPERATIVE_GLOBAL_EXECUTOR
insertIntoDelayedJobQueue(delay, job);
#elif !SWIFT_CONCURRENCY_ENABLE_DISPATCH
swift_reportError(0, "operation unsupported without libdispatch: "
"swift_task_enqueueGlobalWithDelay");
#else

dispatch_function_t dispatchFunction = &__swift_run_job;
Expand Down Expand Up @@ -419,6 +431,9 @@ static void swift_task_enqueueMainExecutorImpl(Job *job) {

#if SWIFT_CONCURRENCY_COOPERATIVE_GLOBAL_EXECUTOR
insertIntoJobQueue(job);
#elif !SWIFT_CONCURRENCY_ENABLE_DISPATCH
swift_reportError(0, "operation unsupported without libdispatch: "
"swift_task_enqueueMainExecutor");
#else

JobPriority priority = job->getPriority();
Expand All @@ -439,7 +454,7 @@ void swift::swift_task_enqueueMainExecutor(Job *job) {
swift_task_enqueueMainExecutorImpl(job);
}

#if !SWIFT_CONCURRENCY_COOPERATIVE_GLOBAL_EXECUTOR
#if SWIFT_CONCURRENCY_ENABLE_DISPATCH
void swift::swift_task_enqueueOnDispatchQueue(Job *job,
HeapObject *_queue) {
JobPriority priority = job->getPriority();
Expand All @@ -449,7 +464,8 @@ void swift::swift_task_enqueueOnDispatchQueue(Job *job,
#endif

ExecutorRef swift::swift_task_getMainExecutor() {
#if SWIFT_CONCURRENCY_COOPERATIVE_GLOBAL_EXECUTOR
#if !SWIFT_CONCURRENCY_ENABLE_DISPATCH
// FIXME: this isn't right for the non-cooperative environment
return ExecutorRef::generic();
#else
return ExecutorRef::forOrdinary(
Expand All @@ -459,7 +475,8 @@ ExecutorRef swift::swift_task_getMainExecutor() {
}

bool ExecutorRef::isMainExecutor() const {
#if SWIFT_CONCURRENCY_COOPERATIVE_GLOBAL_EXECUTOR
#if !SWIFT_CONCURRENCY_ENABLE_DISPATCH
// FIXME: this isn't right for the non-cooperative environment
return isGeneric();
#else
return Identity == reinterpret_cast<HeapObject*>(&_dispatch_main_q);
Expand Down
12 changes: 9 additions & 3 deletions stdlib/public/Concurrency/Task.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
#include "Debug.h"
#include "Error.h"

#if !SWIFT_CONCURRENCY_COOPERATIVE_GLOBAL_EXECUTOR
#if SWIFT_CONCURRENCY_ENABLE_DISPATCH
#include <dispatch/dispatch.h>
#endif

Expand Down Expand Up @@ -248,7 +248,7 @@ static void destroyTask(SWIFT_CONTEXT HeapObject *obj) {
}

static ExecutorRef executorForEnqueuedJob(Job *job) {
#if SWIFT_CONCURRENCY_COOPERATIVE_GLOBAL_EXECUTOR
#if !SWIFT_CONCURRENCY_ENABLE_DISPATCH
return ExecutorRef::generic();
#else
void *jobQueue = job->SchedulerPrivate[Job::DispatchQueueIndex];
Expand Down Expand Up @@ -1065,13 +1065,19 @@ void swift::swift_continuation_logFailedCheck(const char *message) {
swift_reportError(0, message);
}

SWIFT_RUNTIME_ATTRIBUTE_NORETURN
SWIFT_CC(swift)
static void swift_task_asyncMainDrainQueueImpl() {
#if SWIFT_CONCURRENCY_COOPERATIVE_GLOBAL_EXECUTOR
bool Finished = false;
donateThreadToGlobalExecutorUntil([](void *context) {
swift_task_donateThreadToGlobalExecutorUntil([](void *context) {
return *reinterpret_cast<bool*>(context);
}, &Finished);
#elif !SWIFT_CONCURRENCY_ENABLE_DISPATCH
// FIXME: consider implementing a concurrent global main queue for
// these environments?
swift_reportError(0, "operation unsupported without libdispatch: "
"swift_task_asyncMainDrainQueue");
#else
#if defined(_WIN32)
static void(FAR *pfndispatch_main)(void) = NULL;
Expand Down
2 changes: 1 addition & 1 deletion stdlib/public/Concurrency/TaskGroup.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
#include "queue" // TODO: remove and replace with usage of our mpsc queue
#include <atomic>
#include <assert.h>
#if !SWIFT_CONCURRENCY_COOPERATIVE_GLOBAL_EXECUTOR
#if SWIFT_CONCURRENCY_ENABLE_DISPATCH
#include <dispatch/dispatch.h>
#endif

Expand Down
14 changes: 0 additions & 14 deletions stdlib/public/Concurrency/TaskPrivate.h
Original file line number Diff line number Diff line change
Expand Up @@ -100,20 +100,6 @@ void asyncLet_addImpl(AsyncTask *task, AsyncLet *asyncLet,
/// Clear the active task reference for the current thread.
AsyncTask *_swift_task_clearCurrent();

#if defined(SWIFT_STDLIB_SINGLE_THREADED_RUNTIME)
#define SWIFT_CONCURRENCY_COOPERATIVE_GLOBAL_EXECUTOR 1
#else
#define SWIFT_CONCURRENCY_COOPERATIVE_GLOBAL_EXECUTOR 0
#endif

#if SWIFT_CONCURRENCY_COOPERATIVE_GLOBAL_EXECUTOR
/// Donate this thread to the global executor until either the
/// given condition returns true or we've run out of cooperative
/// tasks to run.
void donateThreadToGlobalExecutorUntil(bool (*condition)(void*),
void *context);
#endif

/// release() establishes a happens-before relation with a preceding acquire()
/// on the same address.
void _swift_tsan_acquire(void *addr);
Expand Down