From 3be6d5910416e738384d83f89d3de8a0f647ead9 Mon Sep 17 00:00:00 2001
From: Duncan Coutts <duncan@well-typed.com>
Date: Mon, 9 Jan 2023 17:06:28 +0000
Subject: [PATCH] Select an I/O manager early in RTS startup

We need to select the I/O manager to use during startup before the
per-cap I/O manager initialisation.
---
 rts/Capability.c |  2 +-
 rts/IOManager.c  | 21 +++++++++++++--------
 rts/IOManager.h  | 14 +++++++++++---
 rts/RtsStartup.c |  3 +++
 4 files changed, 28 insertions(+), 12 deletions(-)

diff --git a/rts/Capability.c b/rts/Capability.c
index c8e15c178d56..a9fe393a08db 100644
--- a/rts/Capability.c
+++ b/rts/Capability.c
@@ -281,7 +281,7 @@ initCapability (Capability *cap, uint32_t i)
 #endif
     cap->total_allocated        = 0;
 
-    initCapabilityIOManager(&cap->iomgr);
+    initCapabilityIOManager(cap); /* initialises cap->iomgr */
 
     cap->f.stgEagerBlackholeInfo = (W_)&__stg_EAGER_BLACKHOLE_info;
     cap->f.stgGCEnter1     = (StgFunPtr)__stg_gc_enter_1;
diff --git a/rts/IOManager.c b/rts/IOManager.c
index e6db47fa50fe..e0e4ef04ac2e 100644
--- a/rts/IOManager.c
+++ b/rts/IOManager.c
@@ -174,8 +174,11 @@ parseIOManagerFlag(const char *iomgrstr, IO_MANAGER_FLAG *flag)
  *
  * This fills in the iomgr_type and rts_IOManagerIsWin32Native globals.
  * Must be called before the I/O manager is started.
+ *
+ * Called early in the RTS initialisation, after the RTS flags have been
+ * processed.
  */
-static void selectIOManager(void)
+void selectIOManager(void)
 {
     switch (RtsFlags.MiscFlags.ioManager) {
         case IO_MNGR_FLAG_AUTO:
@@ -242,9 +245,13 @@ static void selectIOManager(void)
 
 
 /* Allocate and initialise the per-capability CapIOManager that lives in each
- * Capability. Called early in the RTS initialisation.
+ * Capability. Called from initCapability(), which is done in the RTS startup
+ * in initCapabilities(), and later at runtime via setNumCapabilities().
+ *
+ * Note that during RTS startup this is called _before_ the storage manager
+ * is initialised, so this is not allowed to allocate on the GC heap.
  */
-void initCapabilityIOManager(CapIOManager **piomgr)
+void initCapabilityIOManager(Capability *cap)
 {
     CapIOManager *iomgr =
       (CapIOManager *) stgMallocBytes(sizeof(CapIOManager),
@@ -275,20 +282,18 @@ void initCapabilityIOManager(CapIOManager **piomgr)
             break;
     }
 
-    *piomgr = iomgr;
+    cap->iomgr = iomgr;
 }
 
 
 /* Called late in the RTS initialisation
  */
-void
-initIOManager(void)
+void initIOManager(void)
 {
-    selectIOManager();
 
     switch (iomgr_type) {
 
-        /* The IO_MANAGER_SELECT needs no initialisation */
+        /* The IO_MANAGER_SELECT needs no global initialisation */
 
 #if defined(IOMGR_ENABLED_MIO_POSIX)
         case IO_MANAGER_MIO_POSIX:
diff --git a/rts/IOManager.h b/rts/IOManager.h
index 24218e9315d0..b54dbd0974d1 100644
--- a/rts/IOManager.h
+++ b/rts/IOManager.h
@@ -214,11 +214,19 @@ typedef struct {
 } CapIOManager;
 
 
+/* Init hook: called from hs_init_ghc, early in the startup after the RTS flags
+ * have been processed.
+ *
+ * Based on the I/O manager RTS flag, select an I/O manager to use.
+ */
+void selectIOManager(void);
+
+
 /* Allocate and initialise the per-capability CapIOManager that lives in each
- * Capability. It is called from initCapability, via initScheduler,
- * via hs_init_ghc.
+ * Capability. Called from initCapability(), which is done in the RTS startup
+ * in initCapabilities(), and later at runtime via setNumCapabilities().
  */
-void initCapabilityIOManager(CapIOManager **iomgr);
+void initCapabilityIOManager(Capability *cap);
 
 
 /* Init hook: called from hs_init_ghc, very late in the startup after almost
diff --git a/rts/RtsStartup.c b/rts/RtsStartup.c
index cfbd0421f5d4..70e926b44623 100644
--- a/rts/RtsStartup.c
+++ b/rts/RtsStartup.c
@@ -331,6 +331,9 @@ hs_init_ghc(int *argc, char **argv[], RtsConfig rts_config)
 #endif /* DEBUG */
     }
 
+    /* Based on the RTS flags, decide which I/O manager to use. */
+    selectIOManager();
+
     /* Initialize console Codepage.  */
 #if defined(mingw32_HOST_OS)
    if (is_io_mng_native_p())
-- 
GitLab