Rodrigo Mesquita pushed to branch wip/romes/27729 at Glasgow Haskell Compiler / GHC Commits: 7f843566 by Rodrigo Mesquita at 2026-08-21T16:07:58+01:00 rts: Fix race condition in MSG_UPD_TSO_FLAGS execution The code for processing the MSG_UPD_TSO_FLAGS message was not taking into consideration that the TSO's owner might have moved in between that capability receiving the message (since it was its previous owner) and starting to process its inbox (a point at which it was no longer the owner) Added Note [TSO owner may change in between Msg being sent and received] to explain this race and the pattern used to fix this, where we just forward the message to the new owner. Fixes #27729 - - - - - 2 changed files: - rts/CloneStack.c - rts/Messages.c Changes: ===================================== rts/CloneStack.c ===================================== @@ -88,6 +88,7 @@ void sendCloneStackMessage(StgTSO *tso, HsStablePtr mvar) { void handleCloneStackMessage(Capability *cap, MessageCloneStack *msg){ // We must check that the current owner of the thread we want to clone the stack for // is still this capability. + // See Note [TSO owner may change in between Msg being sent and received] Capability *owner = RELAXED_LOAD(&msg->tso->cap); if (owner != cap) { // The target TSO may have migrated after the message was queued on the old ===================================== rts/Messages.c ===================================== @@ -66,6 +66,48 @@ void sendMessage(Capability *from_cap, Capability *to_cap, Message *msg) Handle a message ------------------------------------------------------------------------- */ +/* +Note [TSO owner may change in between Msg being sent and received] +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +When a message is sent from Capability (C1) to a target TSO (T2) (e.g. +MessageUpdTSOFlag, MessageCloneStack, ...), it is queued on the TSO's owner +Capability (C3) inbox (inboxes are owned by Capabilities, not TSOs). + +At a later point, the Capability (C3) will process its inbox. Upon receiving +the message meant for a specific TSO (T2), it must first always check that the +TSO's owner is *still* itself (C3). + +The target TSO (T2) may have migrated after the message was queued on its old +capability (C3). In that case we must forward the request to the new owner +(say, C4); otherwise the Capability C3 could be modifying a TSO it no longer +owns, racing with its actual owner mutating it, since it is no longer the owner. + +The message meant for a TSO should only be executed when the receiving +Capability is still the owner of that TSO. Otherwise, it must be forwarded to +the new owner. The pseudo code for handling a message that targets a particular +TSO will look something like: + + executeMessage(...) { + + if (i == &stg_MY_MSG_info) { + + MessageMyMsg* msg = (MessageMyMsg*) m + + Capability *owner = RELAXED_LOAD(&msg->tso->cap); + if (owner != cap) { + sendMessage(cap, owner, (Message *)msg); + return; + } + + actuallyExecute(...) + + } + } + +See `executeMessage`'s `stg_MSG_UPD_TSO_FLAG_info` and +`stg_MSG_CLONE_STACK_info` for two live examples. +*/ + #if defined(THREADED_RTS) void @@ -142,12 +184,18 @@ loop: } else if(i == &stg_MSG_UPD_TSO_FLAG_info){ MessageUpdTSOFlag *u = (MessageUpdTSOFlag*) m; - if (u->set) { - u->tso->flags |= u->flag; - } - else { - u->tso->flags &= ~u->flag; + + // We must check that the current owner of the thread is still this capability. + // See Note [TSO owner may change in between Msg being sent and received] + Capability *owner = RELAXED_LOAD(&u->tso->cap); + if (owner != cap) { + sendMessage(cap, owner, (Message *)u); + return; } + + if (u->set) { u->tso->flags |= u->flag; } + else { u->tso->flags &= ~u->flag; } + return; } else View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/7f84356660ba202f676e67073b96fd3f... -- View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/7f84356660ba202f676e67073b96fd3f... You're receiving this email because of your account on gitlab.haskell.org. Manage all notifications: https://gitlab.haskell.org/-/profile/notifications | Help: https://gitlab.haskell.org/help