mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
[Concurrency] Rename ExecutorHooks.h, tidy up the interface.
`ExecutorHooks.h` is now nothing to do with hooks, so rename it. Also there are some additional functions it should declare, and a couple of places where we've slightly messed up the boundary, for instance `swift_task_asyncMainDrainQueue` was defined in `Task.cpp` rather than in the executor implementations, which is wrong, so fix that too. `CooperativeGlobalExecutor.cpp` now builds against the interface from `ExecutorImpl.h`, rather than including the all the concurrency headers. rdar://135380149
This commit is contained in:
@@ -15,10 +15,15 @@
|
||||
/// This file is included into GlobalExecutor.cpp only when Dispatch
|
||||
/// integration is enabled. It is expected to define the following
|
||||
/// functions:
|
||||
/// swift_task_asyncMainDrainQueueImpl
|
||||
/// swift_task_checkIsolatedImpl
|
||||
/// swift_task_donateThreadToGlobalExecutorUntilImpl
|
||||
/// swift_task_enqueueGlobalImpl
|
||||
/// swift_task_enqueueGlobalWithDeadlineImpl
|
||||
/// swift_task_enqueueGlobalWithDelayImpl
|
||||
/// swift_task_enqueueMainExecutorImpl
|
||||
/// swift_task_checkIsolatedImpl
|
||||
/// swift_task_getMainExecutorImpl
|
||||
/// swift_task_isMainExecutorImpl
|
||||
/// as well as any Dispatch-specific functions for the runtime.
|
||||
///
|
||||
///===------------------------------------------------------------------===///
|
||||
@@ -44,7 +49,7 @@
|
||||
#endif
|
||||
|
||||
#include "Error.h"
|
||||
#include "ExecutorHooks.h"
|
||||
#include "ExecutorImpl.h"
|
||||
#include "TaskPrivate.h"
|
||||
|
||||
using namespace swift;
|
||||
@@ -72,7 +77,7 @@ static_assert(offsetof(Job, SchedulerPrivate[Job::DispatchLinkageIndex]) ==
|
||||
|
||||
/// The function passed to dispatch_async_f to execute a job.
|
||||
static void __swift_run_job(void *_job) {
|
||||
Job *job = (Job*) _job;
|
||||
SwiftJob *job = (SwiftJob*) _job;
|
||||
auto metadata =
|
||||
reinterpret_cast<const DispatchClassMetadata *>(job->metadata);
|
||||
metadata->VTableInvoke(job, nullptr, 0);
|
||||
@@ -130,9 +135,9 @@ static void initializeDispatchEnqueueFunc(dispatch_queue_t queue, void *obj,
|
||||
}
|
||||
|
||||
/// Enqueue a Job onto a dispatch queue using dispatchEnqueueFunc.
|
||||
static void dispatchEnqueue(dispatch_queue_t queue, Job *job,
|
||||
static void dispatchEnqueue(dispatch_queue_t queue, SwiftJob *job,
|
||||
dispatch_qos_class_t qos, void *executorQueue) {
|
||||
job->SchedulerPrivate[Job::DispatchQueueIndex] = executorQueue;
|
||||
job->schedulerPrivate[Job::DispatchQueueIndex] = executorQueue;
|
||||
dispatchEnqueueFunc.load(std::memory_order_relaxed)(queue, job, qos);
|
||||
}
|
||||
|
||||
@@ -146,7 +151,7 @@ static constexpr size_t dispatchQueueCooperativeFlag = 4;
|
||||
extern "C" void dispatch_queue_set_width(dispatch_queue_t dq, long width);
|
||||
#endif
|
||||
|
||||
static dispatch_queue_t getGlobalQueue(JobPriority priority) {
|
||||
static dispatch_queue_t getGlobalQueue(SwiftJobPriority priority) {
|
||||
size_t numericPriority = static_cast<size_t>(priority);
|
||||
if (numericPriority >= globalQueueCacheCount)
|
||||
swift_Concurrency_fatalError(0, "invalid job priority %#zx", numericPriority);
|
||||
@@ -204,7 +209,7 @@ static dispatch_queue_t getGlobalQueue(JobPriority priority) {
|
||||
// Get a queue suitable for dispatch_after. Use the cooperative queues on OS
|
||||
// versions where they work with dispatch_after, and use a standard global
|
||||
// queue where cooperative queues don't work.
|
||||
static dispatch_queue_t getTimerQueue(JobPriority priority) {
|
||||
static dispatch_queue_t getTimerQueue(SwiftJobPriority priority) {
|
||||
// On newer OSes, we can use the cooperative queues.
|
||||
if (__builtin_available(macOS 12.3, iOS 15.4, tvOS 15.4, watchOS 8.5, *))
|
||||
return getGlobalQueue(priority);
|
||||
@@ -214,7 +219,7 @@ static dispatch_queue_t getTimerQueue(JobPriority priority) {
|
||||
}
|
||||
|
||||
SWIFT_CC(swift)
|
||||
void swift::swift_task_enqueueGlobalImpl(Job *job) {
|
||||
void swift_task_enqueueGlobalImpl(SwiftJob *job) {
|
||||
assert(job && "no job provided");
|
||||
// We really want four things from the global execution service:
|
||||
// - Enqueuing work should have minimal runtime and memory overhead.
|
||||
@@ -245,7 +250,7 @@ void swift::swift_task_enqueueGlobalImpl(Job *job) {
|
||||
// the priorities of work added to this queue using Dispatch's public
|
||||
// API, but as discussed above, that is less important than avoiding
|
||||
// performance problems.
|
||||
JobPriority priority = job->getPriority();
|
||||
SwiftJobPriority priority = swift_job_getPriority(job);
|
||||
|
||||
auto queue = getGlobalQueue(priority);
|
||||
|
||||
@@ -255,18 +260,18 @@ void swift::swift_task_enqueueGlobalImpl(Job *job) {
|
||||
|
||||
|
||||
SWIFT_CC(swift)
|
||||
void swift::swift_task_enqueueGlobalWithDelayImpl(JobDelay delay,
|
||||
Job *job) {
|
||||
void swift_task_enqueueGlobalWithDelayImpl(SwiftJobDelay delay,
|
||||
SwiftJob *job) {
|
||||
assert(job && "no job provided");
|
||||
|
||||
dispatch_function_t dispatchFunction = &__swift_run_job;
|
||||
void *dispatchContext = job;
|
||||
|
||||
JobPriority priority = job->getPriority();
|
||||
SwiftJobPriority priority = swift_job_getPriority(job);
|
||||
|
||||
auto queue = getTimerQueue(priority);
|
||||
|
||||
job->SchedulerPrivate[Job::DispatchQueueIndex] =
|
||||
job->schedulerPrivate[SwiftJobDispatchQueueIndex] =
|
||||
DISPATCH_QUEUE_GLOBAL_EXECUTOR;
|
||||
|
||||
dispatch_time_t when = dispatch_time(DISPATCH_TIME_NOW, delay);
|
||||
@@ -279,16 +284,14 @@ void swift::swift_task_enqueueGlobalWithDelayImpl(JobDelay delay,
|
||||
|
||||
struct __swift_job_source {
|
||||
dispatch_source_t source;
|
||||
Job *job;
|
||||
SwiftJob *job;
|
||||
};
|
||||
|
||||
static void _swift_run_job_leeway(struct __swift_job_source *jobSource) {
|
||||
dispatch_source_t source = jobSource->source;
|
||||
dispatch_release(source);
|
||||
Job *job = jobSource->job;
|
||||
auto task = dyn_cast<AsyncTask>(job);
|
||||
assert(task && "provided job must be a task");
|
||||
_swift_task_dealloc_specific(task, jobSource);
|
||||
SwiftJob *job = jobSource->job;
|
||||
swift_job_dealloc(job, jobSource);
|
||||
__swift_run_job(job);
|
||||
}
|
||||
|
||||
@@ -344,19 +347,18 @@ clock_and_value_to_time(int clock, long long deadline) {
|
||||
}
|
||||
|
||||
SWIFT_CC(swift)
|
||||
void swift::swift_task_enqueueGlobalWithDeadlineImpl(long long sec,
|
||||
long long nsec,
|
||||
long long tsec,
|
||||
long long tnsec,
|
||||
int clock, Job *job) {
|
||||
void swift_task_enqueueGlobalWithDeadlineImpl(long long sec,
|
||||
long long nsec,
|
||||
long long tsec,
|
||||
long long tnsec,
|
||||
int clock, SwiftJob *job) {
|
||||
assert(job && "no job provided");
|
||||
auto task = cast<AsyncTask>(job);
|
||||
|
||||
JobPriority priority = job->getPriority();
|
||||
SwiftJobPriority priority = swift_job_getPriority(job);
|
||||
|
||||
auto queue = getTimerQueue(priority);
|
||||
|
||||
job->SchedulerPrivate[Job::DispatchQueueIndex] =
|
||||
job->schedulerPrivate[SwiftJobDispatchQueueIndex] =
|
||||
DISPATCH_QUEUE_GLOBAL_EXECUTOR;
|
||||
|
||||
uint64_t deadline = sec * NSEC_PER_SEC + nsec;
|
||||
@@ -372,8 +374,8 @@ void swift::swift_task_enqueueGlobalWithDeadlineImpl(long long sec,
|
||||
size_t sz = sizeof(struct __swift_job_source);
|
||||
|
||||
struct __swift_job_source *jobSource =
|
||||
(struct __swift_job_source *)_swift_task_alloc_specific(task, sz);
|
||||
|
||||
(struct __swift_job_source *)swift_job_alloc(job, sz);
|
||||
|
||||
jobSource->job = job;
|
||||
jobSource->source = source;
|
||||
|
||||
@@ -389,10 +391,10 @@ void swift::swift_task_enqueueGlobalWithDeadlineImpl(long long sec,
|
||||
}
|
||||
|
||||
SWIFT_CC(swift)
|
||||
void swift::swift_task_enqueueMainExecutorImpl(Job *job) {
|
||||
void swift_task_enqueueMainExecutorImpl(SwiftJob *job) {
|
||||
assert(job && "no job provided");
|
||||
|
||||
JobPriority priority = job->getPriority();
|
||||
SwiftJobPriority priority = swift_job_getPriority(job);
|
||||
|
||||
// This is an inline function that compiles down to a pointer to a global.
|
||||
auto mainQueue = dispatch_get_main_queue();
|
||||
@@ -404,24 +406,25 @@ void swift::swift_task_enqueueOnDispatchQueue(Job *job,
|
||||
HeapObject *_queue) {
|
||||
JobPriority priority = job->getPriority();
|
||||
auto queue = reinterpret_cast<dispatch_queue_t>(_queue);
|
||||
dispatchEnqueue(queue, job, (dispatch_qos_class_t)priority, queue);
|
||||
dispatchEnqueue(queue, (SwiftJob *)job, (dispatch_qos_class_t)priority, queue);
|
||||
}
|
||||
|
||||
/// Recognize if the SerialExecutor is specifically a `DispatchSerialQueue`
|
||||
/// by comparing witness tables and return it if true.
|
||||
static dispatch_queue_s *getAsDispatchSerialQueue(SerialExecutorRef executor) {
|
||||
if (!executor.hasSerialExecutorWitnessTable()) {
|
||||
static dispatch_queue_s *getAsDispatchSerialQueue(SwiftExecutorRef executor) {
|
||||
if (!swift_executor_hasWitnessTable(executor)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto executorWitnessTable = reinterpret_cast<const WitnessTable *>(
|
||||
executor.getSerialExecutorWitnessTable());
|
||||
swift_executor_getWitnessTable(executor));
|
||||
auto serialQueueWitnessTable = reinterpret_cast<const WitnessTable *>(
|
||||
_swift_task_getDispatchQueueSerialExecutorWitnessTable());
|
||||
|
||||
if (swift_compareWitnessTables(executorWitnessTable,
|
||||
serialQueueWitnessTable)) {
|
||||
return reinterpret_cast<dispatch_queue_s *>(executor.getIdentity());
|
||||
auto identity = swift_executor_getIdentity(executor);
|
||||
return reinterpret_cast<dispatch_queue_s *>(identity);
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
@@ -433,15 +436,15 @@ static dispatch_queue_s *getAsDispatchSerialQueue(SerialExecutorRef executor) {
|
||||
/// to perform this assertion on earlier platforms, where the `checkIsolated`
|
||||
/// requirement/witness was not shipping yet.
|
||||
SWIFT_CC(swift)
|
||||
void swift::swift_task_checkIsolatedImpl(SerialExecutorRef executor) {
|
||||
void swift_task_checkIsolatedImpl(SwiftExecutorRef executor) {
|
||||
// If it is the main executor, compare with the Main queue
|
||||
if (executor.isMainExecutor()) {
|
||||
if (swift_executor_isMain(executor)) {
|
||||
dispatch_assert_queue(dispatch_get_main_queue());
|
||||
return;
|
||||
}
|
||||
|
||||
// if able to, use the checkIsolated implementation in Swift
|
||||
if (swift_task_invokeSwiftCheckIsolated(executor))
|
||||
if (swift_executor_invokeSwiftCheckIsolated(executor))
|
||||
return;
|
||||
|
||||
if (auto queue = getAsDispatchSerialQueue(executor)) {
|
||||
@@ -457,14 +460,58 @@ void swift::swift_task_checkIsolatedImpl(SerialExecutorRef executor) {
|
||||
}
|
||||
|
||||
SWIFT_CC(swift)
|
||||
SerialExecutorRef swift::swift_task_getMainExecutorImpl() {
|
||||
return SerialExecutorRef::forOrdinary(
|
||||
reinterpret_cast<HeapObject*>(&_dispatch_main_q),
|
||||
_swift_task_getDispatchQueueSerialExecutorWitnessTable());
|
||||
SwiftExecutorRef swift_task_getMainExecutorImpl() {
|
||||
return swift_executor_ordinary(
|
||||
reinterpret_cast<SwiftHeapObject*>(&_dispatch_main_q),
|
||||
reinterpret_cast<SwiftExecutorWitnessTable *>(
|
||||
_swift_task_getDispatchQueueSerialExecutorWitnessTable()));
|
||||
}
|
||||
|
||||
SWIFT_CC(swift)
|
||||
bool swift::swift_task_isMainExecutorImpl(SerialExecutorRef executor) {
|
||||
return executor.getIdentity()
|
||||
== reinterpret_cast<HeapObject *>(&_dispatch_main_q);
|
||||
bool swift_task_isMainExecutorImpl(SwiftExecutorRef executor) {
|
||||
return swift_executor_getIdentity(executor)
|
||||
== reinterpret_cast<SwiftHeapObject *>(&_dispatch_main_q);
|
||||
}
|
||||
|
||||
SWIFT_CC(swift) void
|
||||
swift_task_donateThreadToGlobalExecutorUntilImpl(bool (*condition)(void *),
|
||||
void *conditionContext) {
|
||||
swift_Concurrency_fatalError(0, "Not supported for Dispatch executor");
|
||||
}
|
||||
|
||||
SWIFT_RUNTIME_ATTRIBUTE_NORETURN
|
||||
SWIFT_CC(swift)
|
||||
void swift_task_asyncMainDrainQueueImpl() {
|
||||
#if defined(_WIN32)
|
||||
HMODULE hModule = LoadLibraryW(L"dispatch.dll");
|
||||
if (hModule == NULL) {
|
||||
swift_Concurrency_fatalError(0,
|
||||
"unable to load dispatch.dll: %lu", GetLastError());
|
||||
}
|
||||
|
||||
auto pfndispatch_main = reinterpret_cast<void (FAR *)(void)>(
|
||||
GetProcAddress(hModule, "dispatch_main"));
|
||||
if (pfndispatch_main == NULL) {
|
||||
swift_Concurrency_fatalError(0,
|
||||
"unable to locate dispatch_main in dispatch.dll: %lu", GetLastError());
|
||||
}
|
||||
|
||||
pfndispatch_main();
|
||||
swift_unreachable("Returned from dispatch_main()");
|
||||
#else
|
||||
// CFRunLoop is not available on non-Darwin targets. Foundation has an
|
||||
// implementation, but CoreFoundation is not meant to be exposed. We can only
|
||||
// assume the existence of `CFRunLoopRun` on Darwin platforms, where the
|
||||
// system provides an implementation of CoreFoundation.
|
||||
#if defined(__APPLE__)
|
||||
auto runLoop =
|
||||
reinterpret_cast<void (*)(void)>(dlsym(RTLD_DEFAULT, "CFRunLoopRun"));
|
||||
if (runLoop) {
|
||||
runLoop();
|
||||
exit(0);
|
||||
}
|
||||
#endif
|
||||
|
||||
dispatch_main();
|
||||
#endif
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user