summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBen Gamari <ben@smart-cactus.org>2023-01-16 11:46:09 -0500
committerCheng Shao <terrorjack@type.dance>2023-05-08 12:15:19 +0000
commit3e3a6be4023189b2d637beda240e23fa9e856810 (patch)
tree580ce4ea0256d1f892dc04b3194c756810437d4a
parent994bda563604461ffb8454d6e298b0310520bcc8 (diff)
downloadhaskell-wip/T22756.tar.gz
rts: Fix data-race in hs_init_ghcwip/T22756
As noticed by @Terrorjack, `hs_init_ghc` previously used non-atomic increment/decrement on the RTS's initialization count. This may go wrong in a multithreaded program which initializes the runtime multiple times. Closes #22756.
-rw-r--r--rts/RtsStartup.c19
1 files changed, 11 insertions, 8 deletions
diff --git a/rts/RtsStartup.c b/rts/RtsStartup.c
index 5cb94c71e8..cfbd0421f5 100644
--- a/rts/RtsStartup.c
+++ b/rts/RtsStartup.c
@@ -68,7 +68,7 @@
#endif
// Count of how many outstanding hs_init()s there have been.
-static int hs_init_count = 0;
+static StgWord hs_init_count = 0;
static bool rts_shutdown = false;
#if defined(mingw32_HOST_OS)
@@ -242,8 +242,9 @@ hs_init_with_rtsopts(int *argc, char **argv[])
void
hs_init_ghc(int *argc, char **argv[], RtsConfig rts_config)
{
- hs_init_count++;
- if (hs_init_count > 1) {
+ // N.B. atomic_inc returns the new value.
+ StgWord init_count = atomic_inc(&hs_init_count, 1);
+ if (init_count > 1) {
// second and subsequent inits are ignored
return;
}
@@ -452,15 +453,17 @@ hs_exit_(bool wait_foreign)
{
uint32_t g, i;
- if (hs_init_count <= 0) {
- errorBelch("warning: too many hs_exit()s");
+ // N.B. atomic_dec returns the new value.
+ StgInt init_count = (StgInt)atomic_dec(&hs_init_count);
+ if (init_count > 0) {
+ // ignore until it's the last one
return;
}
- hs_init_count--;
- if (hs_init_count > 0) {
- // ignore until it's the last one
+ if (init_count < 0) {
+ errorBelch("warning: too many hs_exit()s");
return;
}
+
rts_shutdown = true;
/* start timing the shutdown */