Files
swift-mirror/stdlib/public/Concurrency/ConcurrencyHooks.cpp
Alastair Houghton 837513dc16 [Concurrency] Fix test failures, add struct layout checks.
We were missing a field in `SwiftJob`, which broke various things.  To
avoid that problem in future, this PR adds a set of static asserts to
check the layout of various structures and that we're using the same
values as well.

Also added some functions to the ABI, and fixed things so that if you
enable the debug logging the library still builds (there was an extra
`_` in `Actor.cpp` that caused a build failure).

Finally, renamed `Hooks.cpp` to `ConcurrencyHooks.cpp`.

rdar://135380149
2024-09-30 17:16:33 +01:00

211 lines
7.4 KiB
C++

///===--- Hooks.cpp - Concurrency hook variables --------------------------===///
///
/// This source file is part of the Swift.org open source project
///
/// Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors
/// Licensed under Apache License v2.0 with Runtime Library Exception
///
/// See https:///swift.org/LICENSE.txt for license information
/// See https:///swift.org/CONTRIBUTORS.txt for the list of Swift project authors
///
///===----------------------------------------------------------------------===///
///
/// Defines all of the hook variables.
///
///===----------------------------------------------------------------------===///
#include "swift/ABI/Task.h"
#include "swift/Runtime/Concurrency.h"
#include "swift/Runtime/HeapObject.h"
#include "swift/shims/Visibility.h"
#include "ExecutorImpl.h"
#include "TaskPrivate.h"
// Define all the hooks
#define SWIFT_CONCURRENCY_HOOK(returnType, name, ...) \
swift::name##_hook_t swift::name##_hook = nullptr
#define SWIFT_CONCURRENCY_HOOK0(returnType, name) \
swift::name##_hook_t swift::name##_hook = nullptr
#define SWIFT_CONCURRENCY_HOOK_OVERRIDE0(returnType, name) \
swift::name##_hook_t swift::name##_hook = nullptr
#include "swift/Runtime/ConcurrencyHooks.def"
using namespace swift;
// Define the external entry points; because the Impl functions use the C
// types from `ExecutorHooks.h`, we need to make an Orig version containing
// appropriate type casts in each case.
SWIFT_CC(swift) static void
swift_task_enqueueGlobalOrig(Job *job) {
swift_task_enqueueGlobalImpl(reinterpret_cast<SwiftJob *>(job));
}
void
swift::swift_task_enqueueGlobal(Job *job) {
_swift_tsan_release(job);
concurrency::trace::job_enqueue_global(job);
if (SWIFT_UNLIKELY(swift_task_enqueueGlobal_hook)) {
swift_task_enqueueGlobal_hook(job, swift_task_enqueueGlobalOrig);
} else {
swift_task_enqueueGlobalOrig(job);
}
}
SWIFT_CC(swift) static void
swift_task_enqueueGlobalWithDelayOrig(JobDelay delay, Job *job) {
swift_task_enqueueGlobalWithDelayImpl(
static_cast<SwiftJobDelay>(delay), reinterpret_cast<SwiftJob *>(job));
}
void
swift::swift_task_enqueueGlobalWithDelay(JobDelay delay, Job *job) {
concurrency::trace::job_enqueue_global_with_delay(delay, job);
if (SWIFT_UNLIKELY(swift_task_enqueueGlobalWithDelay_hook))
swift_task_enqueueGlobalWithDelay_hook(
delay, job, swift_task_enqueueGlobalWithDelayOrig);
else
swift_task_enqueueGlobalWithDelayOrig(delay, job);
}
SWIFT_CC(swift) static void
swift_task_enqueueGlobalWithDeadlineOrig(
long long sec,
long long nsec,
long long tsec,
long long tnsec,
int clock, Job *job) {
swift_task_enqueueGlobalWithDeadlineImpl(sec, nsec, tsec, tnsec, clock,
reinterpret_cast<SwiftJob *>(job));
}
void
swift::swift_task_enqueueGlobalWithDeadline(
long long sec,
long long nsec,
long long tsec,
long long tnsec,
int clock, Job *job) {
if (SWIFT_UNLIKELY(swift_task_enqueueGlobalWithDeadline_hook))
swift_task_enqueueGlobalWithDeadline_hook(
sec, nsec, tsec, tnsec, clock, job,
swift_task_enqueueGlobalWithDeadlineOrig);
else
swift_task_enqueueGlobalWithDeadlineOrig(sec, nsec, tsec, tnsec, clock, job);
}
SWIFT_CC(swift) static void
swift_task_checkIsolatedOrig(SerialExecutorRef executor) {
swift_task_checkIsolatedImpl(*reinterpret_cast<SwiftExecutorRef *>(&executor));}
void
swift::swift_task_checkIsolated(SerialExecutorRef executor) {
if (SWIFT_UNLIKELY(swift_task_checkIsolated_hook))
swift_task_checkIsolated_hook(executor, swift_task_checkIsolatedOrig);
else
swift_task_checkIsolatedOrig(executor);
}
// Implemented in Swift because we need to obtain the user-defined flags on the executor ref.
//
// We could inline this with effort, though.
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wreturn-type-c-linkage"
extern "C" SWIFT_CC(swift)
swift::SerialExecutorRef _task_serialExecutor_getExecutorRef(
swift::HeapObject *executor, const swift::Metadata *selfType,
const swift::SerialExecutorWitnessTable *wtable);
#pragma clang diagnostic pop
/// WARNING: This method is expected to CRASH in new runtimes, and cannot be
/// used to implement "log warnings" mode. We would need a new entry point to
/// implement a "only log warnings" actor isolation checking mode, and it would
/// no be able handle more complex situations, as `SerialExecutor.checkIsolated`
/// is able to (by calling into dispatchPrecondition on old runtimes).
static SWIFT_CC(swift) bool
swift_task_isOnExecutorImpl(swift::HeapObject *executor,
const swift::Metadata *selfType,
const swift::SerialExecutorWitnessTable *wtable)
{
auto executorRef = _task_serialExecutor_getExecutorRef(executor,
selfType,
wtable);
return swift_task_isCurrentExecutor(executorRef);
}
bool
swift::swift_task_isOnExecutor(HeapObject *executor,
const Metadata *selfType,
const SerialExecutorWitnessTable *wtable) {
if (SWIFT_UNLIKELY(swift_task_isOnExecutor_hook))
return swift_task_isOnExecutor_hook(
executor, selfType, wtable, swift_task_isOnExecutorImpl);
else
return swift_task_isOnExecutorImpl(executor, selfType, wtable);
}
SWIFT_CC(swift) static void
swift_task_enqueueMainExecutorOrig(Job *job) {
swift_task_enqueueMainExecutorImpl(reinterpret_cast<SwiftJob *>(job));
}
void
swift::swift_task_enqueueMainExecutor(Job *job) {
concurrency::trace::job_enqueue_main_executor(job);
if (SWIFT_UNLIKELY(swift_task_enqueueMainExecutor_hook))
swift_task_enqueueMainExecutor_hook(job, swift_task_enqueueMainExecutorOrig);
else
swift_task_enqueueMainExecutorOrig(job);
}
SWIFT_CC(swift) static swift::SerialExecutorRef
swift_task_getMainExecutorOrig() {
auto ref = swift_task_getMainExecutorImpl();
return *reinterpret_cast<SerialExecutorRef *>(&ref);
}
swift::SerialExecutorRef
swift::swift_task_getMainExecutor() {
if (SWIFT_UNLIKELY(swift_task_getMainExecutor_hook))
return swift_task_getMainExecutor_hook(swift_task_getMainExecutorOrig);
else {
return swift_task_getMainExecutorOrig();
}
}
SWIFT_CC(swift) static bool
swift_task_isMainExecutorOrig(SerialExecutorRef executor) {
return swift_task_isMainExecutorImpl(
*reinterpret_cast<SwiftExecutorRef *>(&executor));
}
bool
swift::swift_task_isMainExecutor(SerialExecutorRef executor) {
if (SWIFT_UNLIKELY(swift_task_isMainExecutor_hook))
return swift_task_isMainExecutor_hook(
executor, swift_task_isMainExecutorOrig);
else
return swift_task_isMainExecutorOrig(executor);
}
SWIFT_CC(swift) static void
swift_task_donateThreadToGlobalExecutorUntilOrig(bool (*condition)(void *),
void *context) {
return swift_task_donateThreadToGlobalExecutorUntilImpl(condition, context);
}
void swift::
swift_task_donateThreadToGlobalExecutorUntil(bool (*condition)(void *),
void *context) {
if (SWIFT_UNLIKELY(swift_task_donateThreadToGlobalExecutorUntil_hook))
return swift_task_donateThreadToGlobalExecutorUntil_hook(
condition, context,
swift_task_donateThreadToGlobalExecutorUntilOrig);
else
return swift_task_donateThreadToGlobalExecutorUntilOrig(condition, context);
}