| ... |
... |
@@ -66,6 +66,48 @@ void sendMessage(Capability *from_cap, Capability *to_cap, Message *msg) |
|
66
|
66
|
Handle a message
|
|
67
|
67
|
------------------------------------------------------------------------- */
|
|
68
|
68
|
|
|
|
69
|
+/*
|
|
|
70
|
+Note [TSO owner may change in between Msg being sent and received]
|
|
|
71
|
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
72
|
+When a message is sent from Capability (C1) to a target TSO (T2) (e.g.
|
|
|
73
|
+MessageUpdTSOFlag, MessageCloneStack, ...), it is queued on the TSO's owner
|
|
|
74
|
+Capability (C3) inbox (inboxes are owned by Capabilities, not TSOs).
|
|
|
75
|
+
|
|
|
76
|
+At a later point, the Capability (C3) will process its inbox. Upon receiving
|
|
|
77
|
+the message meant for a specific TSO (T2), it must first always check that the
|
|
|
78
|
+TSO's owner is *still* itself (C3).
|
|
|
79
|
+
|
|
|
80
|
+The target TSO (T2) may have migrated after the message was queued on its old
|
|
|
81
|
+capability (C3). In that case we must forward the request to the new owner
|
|
|
82
|
+(say, C4); otherwise the Capability C3 could be modifying a TSO it no longer
|
|
|
83
|
+owns, racing with its actual owner mutating it, since it is no longer the owner.
|
|
|
84
|
+
|
|
|
85
|
+The message meant for a TSO should only be executed when the receiving
|
|
|
86
|
+Capability is still the owner of that TSO. Otherwise, it must be forwarded to
|
|
|
87
|
+the new owner. The pseudo code for handling a message that targets a particular
|
|
|
88
|
+TSO will look something like:
|
|
|
89
|
+
|
|
|
90
|
+ executeMessage(...) {
|
|
|
91
|
+
|
|
|
92
|
+ if (i == &stg_MY_MSG_info) {
|
|
|
93
|
+
|
|
|
94
|
+ MessageMyMsg* msg = (MessageMyMsg*) m
|
|
|
95
|
+
|
|
|
96
|
+ Capability *owner = RELAXED_LOAD(&msg->tso->cap);
|
|
|
97
|
+ if (owner != cap) {
|
|
|
98
|
+ sendMessage(cap, owner, (Message *)msg);
|
|
|
99
|
+ return;
|
|
|
100
|
+ }
|
|
|
101
|
+
|
|
|
102
|
+ actuallyExecute(...)
|
|
|
103
|
+
|
|
|
104
|
+ }
|
|
|
105
|
+ }
|
|
|
106
|
+
|
|
|
107
|
+See `executeMessage`'s `stg_MSG_UPD_TSO_FLAG_info` and
|
|
|
108
|
+`stg_MSG_CLONE_STACK_info` for two live examples.
|
|
|
109
|
+*/
|
|
|
110
|
+
|
|
69
|
111
|
#if defined(THREADED_RTS)
|
|
70
|
112
|
|
|
71
|
113
|
void
|
| ... |
... |
@@ -142,12 +184,18 @@ loop: |
|
142
|
184
|
}
|
|
143
|
185
|
else if(i == &stg_MSG_UPD_TSO_FLAG_info){
|
|
144
|
186
|
MessageUpdTSOFlag *u = (MessageUpdTSOFlag*) m;
|
|
145
|
|
- if (u->set) {
|
|
146
|
|
- u->tso->flags |= u->flag;
|
|
147
|
|
- }
|
|
148
|
|
- else {
|
|
149
|
|
- u->tso->flags &= ~u->flag;
|
|
|
187
|
+
|
|
|
188
|
+ // We must check that the current owner of the thread is still this capability.
|
|
|
189
|
+ // See Note [TSO owner may change in between Msg being sent and received]
|
|
|
190
|
+ Capability *owner = RELAXED_LOAD(&u->tso->cap);
|
|
|
191
|
+ if (owner != cap) {
|
|
|
192
|
+ sendMessage(cap, owner, (Message *)u);
|
|
|
193
|
+ return;
|
|
150
|
194
|
}
|
|
|
195
|
+
|
|
|
196
|
+ if (u->set) { u->tso->flags |= u->flag; }
|
|
|
197
|
+ else { u->tso->flags &= ~u->flag; }
|
|
|
198
|
+
|
|
151
|
199
|
return;
|
|
152
|
200
|
}
|
|
153
|
201
|
else
|