11
11
// ===----------------------------------------------------------------------===//
12
12
13
13
#include " ../CompatibilityOverride/CompatibilityOverride.h"
14
- #include " swift/ABI/TaskLocal.h"
15
- #include " swift/ABI/Actor.h"
16
- #include " swift/ABI/Task.h"
17
- #include " swift/ABI/Metadata.h"
14
+ #include " ../runtime/ThreadLocalStorage.h"
15
+ #include " swift/Runtime/Atomic.h"
16
+ #include " swift/Runtime/Casting.h"
18
17
#include " swift/Runtime/Once.h"
19
18
#include " swift/Runtime/Mutex.h"
20
19
#include " swift/Runtime/Concurrency.h"
20
+ #include " swift/Runtime/ThreadLocal.h"
21
+ #include " swift/ABI/TaskLocal.h"
22
+ #include " swift/ABI/Task.h"
23
+ #include " swift/ABI/Actor.h"
24
+ #include " swift/ABI/Metadata.h"
25
+ #include " llvm/ADT/PointerIntPair.h"
21
26
#include " TaskPrivate.h"
22
27
23
28
#if defined(__APPLE__)
26
31
#include < android/log.h>
27
32
#endif
28
33
34
+ #if HAVE_PTHREAD_H
35
+ #include < pthread.h>
36
+ #endif
37
+
29
38
#if defined(_WIN32)
30
39
#include < io.h>
40
+ #include < handleapi.h>
41
+ #include < processthreadsapi.h>
31
42
#endif
32
43
33
44
using namespace swift ;
34
45
35
46
// =============================================================================
47
+
48
+ // / An extremely silly class which exists to make pointer
49
+ // / default-initialization constexpr.
50
+ template <class T > struct Pointer {
51
+ T *Value;
52
+ constexpr Pointer () : Value(nullptr ) {}
53
+ constexpr Pointer (T *value) : Value(value) {}
54
+ operator T *() const { return Value; }
55
+ T *operator ->() const { return Value; }
56
+ };
57
+
58
+ // / THIS IS RUNTIME INTERNAL AND NOT ABI.
59
+ class FallbackTaskLocalStorage {
60
+ static SWIFT_RUNTIME_DECLARE_THREAD_LOCAL (
61
+ Pointer<TaskLocal::Storage>,
62
+ Value);
63
+
64
+ public:
65
+ static void set (TaskLocal::Storage *task) { Value.set (task); }
66
+ static TaskLocal::Storage *get () { return Value.get (); }
67
+ };
68
+
69
+ // / Define the thread-locals.
70
+ SWIFT_RUNTIME_DECLARE_THREAD_LOCAL (
71
+ Pointer<TaskLocal::Storage>,
72
+ FallbackTaskLocalStorage::Value);
73
+
36
74
// ==== ABI --------------------------------------------------------------------
37
75
38
76
SWIFT_CC (swift)
39
- static void swift_task_localValuePushImpl(AsyncTask *task,
40
- const HeapObject *key,
41
- /* +1 */ OpaqueValue *value,
42
- const Metadata *valueType) {
43
- task->localValuePush (key, value, valueType);
77
+ static void swift_task_localValuePushImpl(const HeapObject *key,
78
+ /* +1 */ OpaqueValue *value,
79
+ const Metadata *valueType) {
80
+ if (AsyncTask *task = swift_task_getCurrent ()) {
81
+ task->localValuePush (key, value, valueType);
82
+ return ;
83
+ }
84
+
85
+ // no AsyncTask available so we must check the fallback
86
+ TaskLocal::Storage *Local = nullptr ;
87
+ if (auto storage = FallbackTaskLocalStorage::get ()) {
88
+ Local = storage;
89
+ } else {
90
+ void *allocation = malloc (sizeof (TaskLocal::Storage));
91
+ auto *freshStorage = new (allocation) TaskLocal::Storage ();
92
+
93
+ FallbackTaskLocalStorage::set (freshStorage);
94
+ Local = freshStorage;
95
+ }
96
+
97
+ Local->pushValue (/* task=*/ nullptr , key, value, valueType);
44
98
}
45
99
46
100
SWIFT_CC (swift)
47
- static OpaqueValue* swift_task_localValueGetImpl(AsyncTask *task,
48
- const HeapObject *key) {
49
- return task->localValueGet (key);
101
+ static OpaqueValue* swift_task_localValueGetImpl(const HeapObject *key) {
102
+ if (AsyncTask *task = swift_task_getCurrent ()) {
103
+ // we're in the context of a task and can use the task's storage
104
+ return task->localValueGet (key);
105
+ }
106
+
107
+ // no AsyncTask available so we must check the fallback
108
+ if (auto Local = FallbackTaskLocalStorage::get ()) {
109
+ return Local->getValue (/* task*/ nullptr , key);
110
+ }
111
+
112
+ // no value found in task-local or fallback thread-local storage.
113
+ return nullptr ;
50
114
}
51
115
52
116
SWIFT_CC (swift)
53
- static void swift_task_localValuePopImpl(AsyncTask *task) {
54
- task->localValuePop ();
117
+ static void swift_task_localValuePopImpl() {
118
+ if (AsyncTask *task = swift_task_getCurrent ()) {
119
+ task->localValuePop ();
120
+ return ;
121
+ }
122
+
123
+ if (TaskLocal::Storage *Local = FallbackTaskLocalStorage::get ()) {
124
+ bool hasRemainingBindings = Local->popValue (nullptr );
125
+ if (!hasRemainingBindings) {
126
+ // We clean up eagerly, it may be that this non-swift-concurrency thread
127
+ // never again will use task-locals, and as such we better remove the storage.
128
+ FallbackTaskLocalStorage::set (nullptr );
129
+ free (Local);
130
+ }
131
+ return ;
132
+ }
133
+
134
+ assert (false && " Attempted to pop value but no task or thread-local storage available!" );
55
135
}
56
136
57
137
// =============================================================================
@@ -179,17 +259,14 @@ static void swift_task_reportIllegalTaskLocalBindingWithinWithTaskGroupImpl(
179
259
180
260
TaskLocal::Item*
181
261
TaskLocal::Item::createLink (AsyncTask *task,
182
- const HeapObject *key,
183
- const Metadata *valueType) {
184
- assert (task);
185
-
262
+ const HeapObject *key,
263
+ const Metadata *valueType) {
186
264
size_t amountToAllocate = Item::itemSize (valueType);
187
- // assert(amountToAllocate % MaximumAlignment == 0); // TODO: do we need this?
188
-
189
- void *allocation = _swift_task_alloc_specific (task, amountToAllocate);
190
- Item *item = new (allocation) Item (key, valueType);
265
+ void *allocation = task ? _swift_task_alloc_specific (task, amountToAllocate)
266
+ : malloc (amountToAllocate);
267
+ Item *item = new (allocation) Item (key, valueType);
191
268
192
- auto next = task->Local .head ;
269
+ auto next = task ? task ->Local .head : FallbackTaskLocalStorage::get ()-> head ;
193
270
item->next = reinterpret_cast <uintptr_t >(next) |
194
271
static_cast <uintptr_t >(NextLinkType::IsNext);
195
272
@@ -205,7 +282,10 @@ void TaskLocal::Item::destroy(AsyncTask *task) {
205
282
valueType->vw_destroy (getStoragePtr ());
206
283
}
207
284
208
- _swift_task_dealloc_specific (task, this );
285
+ // if task is available, we must have used the task allocator to allocate this item,
286
+ // so we must deallocate it using the same. Otherwise, we must have used malloc.
287
+ if (task) _swift_task_dealloc_specific (task, this );
288
+ else free (this );
209
289
}
210
290
211
291
void TaskLocal::Storage::destroy (AsyncTask *task) {
@@ -244,11 +324,14 @@ void TaskLocal::Storage::pushValue(AsyncTask *task,
244
324
head = item;
245
325
}
246
326
247
- void TaskLocal::Storage::popValue (AsyncTask *task) {
327
+ bool TaskLocal::Storage::popValue (AsyncTask *task) {
248
328
assert (head && " attempted to pop value off empty task-local stack" );
249
329
auto old = head;
250
330
head = head->getNext ();
251
331
old->destroy (task);
332
+
333
+ // / if pointing at not-null next item, there are remaining bindings.
334
+ return head != nullptr ;
252
335
}
253
336
254
337
OpaqueValue* TaskLocal::Storage::getValue (AsyncTask *task,
0 commit comments