1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195
|
#include "Runtime/Concurrency.h"
#include "Concurrency/Actor.h"
#include "Concurrency/Task.h"
#include "Concurrency/TaskPrivate.h"
#include "Concurrency/VoucherSupport.h"
#include "swift/Runtime/Atomic.h"
#include "swift/Runtime/Casting.h"
#include "Runtime/Threading/ThreadLocal.h"
#include <Availability.h>
#include <TargetConditionals.h>
#include <atomic>
#include <new>
using namespace swift;
namespace {
/// An extremely silly class which exists to make pointer
/// default-initialization constexpr.
template <class T> struct Pointer {
T *Value;
constexpr Pointer() : Value(nullptr) {}
constexpr Pointer(T *value) : Value(value) {}
operator T *() const { return Value; }
T *operator->() const { return Value; }
};
/// A class which encapsulates the information we track about
/// the current thread and active executor.
class ExecutorTrackingInfo {
/// A thread-local variable pointing to the active tracking
/// information about the current thread, if any.
///
/// TODO: this is obviously runtime-internal and therefore not
/// reasonable to make ABI. We might want to also provide a way
/// for generated code to efficiently query the identity of the
/// current executor, in order to do a cheap comparison to avoid
/// doing all the work to suspend the task when we're already on
/// the right executor. It would make sense for that to be a
/// separate thread-local variable (or whatever is most efficient
/// on the target platform).
static SWIFT_RUNTIME_DECLARE_THREAD_LOCAL(
Pointer<ExecutorTrackingInfo>, ActiveInfoInThread,
SWIFT_CONCURRENCY_EXECUTOR_TRACKING_INFO_KEY);
/// The active executor.
ExecutorRef ActiveExecutor = ExecutorRef::generic();
/// Whether this context allows switching. Some contexts do not;
/// for example, we do not allow switching from swift_job_run
/// unless the passed-in executor is generic.
bool AllowsSwitching = true;
VoucherManager voucherManager;
/// The tracking info that was active when this one was entered.
ExecutorTrackingInfo *SavedInfo;
public:
ExecutorTrackingInfo() = default;
ExecutorTrackingInfo(const ExecutorTrackingInfo &) = delete;
ExecutorTrackingInfo &operator=(const ExecutorTrackingInfo &) = delete;
/// Unconditionally initialize a fresh tracking state on the
/// current state, shadowing any previous tracking state.
/// leave() must be called before the object goes out of scope.
void enterAndShadow(ExecutorRef currentExecutor) {
ActiveExecutor = currentExecutor;
SavedInfo = ActiveInfoInThread.get();
ActiveInfoInThread.set(this);
}
void swapToJob(Job *job) { voucherManager.swapToJob(job); }
void restoreVoucher(AsyncTask *task) { voucherManager.restoreVoucher(task); }
ExecutorRef getActiveExecutor() const {
return ActiveExecutor;
}
void setActiveExecutor(ExecutorRef newExecutor) {
ActiveExecutor = newExecutor;
}
bool allowsSwitching() const {
return AllowsSwitching;
}
/// Disallow switching in this tracking context. This should only
/// be set on a new tracking info, before any jobs are run in it.
void disallowSwitching() {
AllowsSwitching = false;
}
static ExecutorTrackingInfo *current() {
return ActiveInfoInThread.get();
}
void leave() {
voucherManager.leave();
ActiveInfoInThread.set(SavedInfo);
}
};
class ActiveTask {
/// A thread-local variable pointing to the active tracking
/// information about the current thread, if any.
static SWIFT_RUNTIME_DECLARE_THREAD_LOCAL(Pointer<AsyncTask>, Value,
SWIFT_CONCURRENCY_TASK_KEY);
public:
static void set(AsyncTask *task) { Value.set(task); }
static AsyncTask *get() { return Value.get(); }
};
/// Define the thread-locals.
SWIFT_RUNTIME_DECLARE_THREAD_LOCAL(
Pointer<AsyncTask>,
ActiveTask::Value,
SWIFT_CONCURRENCY_TASK_KEY);
SWIFT_RUNTIME_DECLARE_THREAD_LOCAL(
Pointer<ExecutorTrackingInfo>,
ExecutorTrackingInfo::ActiveInfoInThread,
SWIFT_CONCURRENCY_EXECUTOR_TRACKING_INFO_KEY);
} // namespace
SWIFT_CC(swift)
AsyncTask *swift::swift_task_getCurrent() {
return ActiveTask::get();
}
AsyncTask *swift::_swift_task_clearCurrent() {
auto task = ActiveTask::get();
ActiveTask::set(nullptr);
return task;
}
void swift::adoptTaskVoucher(AsyncTask *task) {
ExecutorTrackingInfo::current()->swapToJob(task);
}
void swift::restoreTaskVoucher(AsyncTask *task) {
ExecutorTrackingInfo::current()->restoreVoucher(task);
}
static swift_once_t voucherDisableCheckOnce;
static bool vouchersDisabled;
namespace {
struct _SwiftNSOperatingSystemVersion{
intptr_t majorVersion;
intptr_t minorVersion;
intptr_t patchVersion;
};
}
extern "C"
_SwiftNSOperatingSystemVersion
_swift_stdlib_operatingSystemVersion() __attribute__((const));
static void _initializeVouchersDisabled(void *ctxt) {
auto osVersion = _swift_stdlib_operatingSystemVersion();
#if TARGET_OS_WATCH
vouchersDisabled = (
osVersion.majorVersion == 8 &&
osVersion.minorVersion >= 0 && osVersion.minorVersion < 3
);
#elif TARGET_OS_IPHONE
vouchersDisabled = (
osVersion.majorVersion == 15 &&
osVersion.minorVersion >= 0 && osVersion.minorVersion < 2
);
#elif TARGET_OS_OSX
vouchersDisabled = (
osVersion.majorVersion == 12 &&
osVersion.minorVersion >= 0 && osVersion.minorVersion < 1
);
#else
vouchersDisabled = false;
#endif
}
bool VoucherManager::vouchersAreDisabled() {
swift_once(&voucherDisableCheckOnce,
&_initializeVouchersDisabled,
nullptr);
return vouchersDisabled;
}
|