@@ -44,6 +44,14 @@ class TaskLocal {
44
44
// / lookups by skipping empty parent tasks during get(), and explained
45
45
// / in depth in `createParentLink`.
46
46
IsParent = 0b01 ,
47
+ // / The task local binding was created inside the body of a `withTaskGroup`,
48
+ // / and therefore must either copy it, or crash when a child task is created
49
+ // / using 'group.addTask' and it would refer to this task local.
50
+ // /
51
+ // / Items of this kind must be copied by a group child task for access
52
+ // / safety reasons, as otherwise the pop would happen before the child task
53
+ // / has completed.
54
+ IsNextCreatedInTaskGroupBody = 0b10 ,
47
55
};
48
56
49
57
class Item {
@@ -101,20 +109,55 @@ class TaskLocal {
101
109
// / the Item linked list into the appropriate parent.
102
110
static Item *createParentLink (AsyncTask *task, AsyncTask *parent);
103
111
112
+ static Item *createLink (AsyncTask *task,
113
+ const HeapObject *key,
114
+ const Metadata *valueType,
115
+ bool inTaskGroupBody);
116
+
104
117
static Item *createLink (AsyncTask *task,
105
118
const HeapObject *key,
106
119
const Metadata *valueType);
107
120
121
+ static Item *createLinkInTaskGroup (
122
+ AsyncTask *task,
123
+ const HeapObject *key,
124
+ const Metadata *valueType);
125
+
108
126
void destroy (AsyncTask *task);
109
127
110
128
Item *getNext () {
111
129
return reinterpret_cast <Item *>(next & ~statusMask);
112
130
}
113
131
132
+ void relinkTaskGroupLocalHeadToSafeNext (Item* nextOverride) {
133
+ assert (!getNext () &&
134
+ " Can only relink task local item that was not pointing at anything yet" );
135
+ assert ((nextOverride->isNextLinkPointer () ||
136
+ nextOverride->isParentPointer ()) &&
137
+ " Currently relinking is only done within a task group to "
138
+ " avoid within-taskgroup next pointers; attempted to point at "
139
+ " task local declared within task group body though!" );
140
+
141
+ next = reinterpret_cast <uintptr_t >(nextOverride) |
142
+ static_cast <uintptr_t >((nextOverride->isNextLinkPointer ()
143
+ ? NextLinkType::IsNextCreatedInTaskGroupBody
144
+ : NextLinkType::IsParent));
145
+ }
146
+
114
147
NextLinkType getNextLinkType () const {
115
148
return static_cast <NextLinkType>(next & statusMask);
116
149
}
117
150
151
+ bool isNextLinkPointer () const {
152
+ return static_cast <NextLinkType>(next & statusMask) ==
153
+ NextLinkType::IsNext;
154
+ }
155
+
156
+ bool isNextLinkPointerCreatedInTaskGroupBody () const {
157
+ return static_cast <NextLinkType>(next & statusMask) ==
158
+ NextLinkType::IsNextCreatedInTaskGroupBody;
159
+ }
160
+
118
161
// / Item does not contain any actual value, and is only used to point at
119
162
// / a specific parent item.
120
163
bool isEmpty () const {
@@ -127,7 +170,7 @@ class TaskLocal {
127
170
reinterpret_cast <char *>(this ) + storageOffset (valueType));
128
171
}
129
172
130
- void copyTo (AsyncTask *task);
173
+ TaskLocal::Item* copyTo (AsyncTask *task);
131
174
132
175
// / Compute the offset of the storage from the base of the item.
133
176
static size_t storageOffset (const Metadata *valueType) {
@@ -136,9 +179,9 @@ class TaskLocal {
136
179
if (valueType) {
137
180
size_t alignment = valueType->vw_alignment ();
138
181
return (offset + alignment - 1 ) & ~(alignment - 1 );
139
- } else {
140
- return offset;
141
182
}
183
+
184
+ return offset;
142
185
}
143
186
144
187
// / Determine the size of the item given a particular value type.
@@ -187,6 +230,10 @@ class TaskLocal {
187
230
188
231
public:
189
232
233
+ // / Get the "current" task local storage from either the passed in
234
+ // / task, or fall back to the *thread* local stored storage.
235
+ static Storage* getCurrent (AsyncTask *task);
236
+
190
237
void initializeLinkParent (AsyncTask *task, AsyncTask *parent);
191
238
192
239
void pushValue (AsyncTask *task,
@@ -200,6 +247,9 @@ class TaskLocal {
200
247
// / can be safely disposed of.
201
248
bool popValue (AsyncTask *task);
202
249
250
+ // / Peek at the head item and get its type.
251
+ std::optional<NextLinkType> peekHeadLinkType () const ;
252
+
203
253
// / Copy all task-local bindings to the target task.
204
254
// /
205
255
// / The new bindings allocate their own items and can out-live the current task.
@@ -212,6 +262,10 @@ class TaskLocal {
212
262
// / "pop" of the `B` value - it was spawned from a scope where only B was observable.
213
263
void copyTo (AsyncTask *target);
214
264
265
+ // FIXME(concurrency): We currently copy from "all" task groups we encounter
266
+ // however in practice we only
267
+ void copyToOnlyOnlyFromCurrentGroup (AsyncTask *target);
268
+
215
269
// / Destroy and deallocate all items stored by this specific task.
216
270
// /
217
271
// / Items owned by a parent task are left untouched, since we do not own them.
0 commit comments