From 4161f5163b2915dac39e2f14ca7dbb526bc1f257 Mon Sep 17 00:00:00 2001 From: Duncan Coutts <duncan@well-typed.com> Date: Mon, 9 Jan 2023 01:18:13 +0000 Subject: [PATCH] Add an IOManager API for scavenging TSO blocked_info When the GC scavenges a TSO it needs to scavenge the tso->blocked_info but the blocked_info is a big union and what lives there depends on the two->why_blocked, which for I/O-related reasons is something that in principle is the responsibility of the I/O manager and not the GC. So the right thing to do is for the GC to ask the I/O manager to sscavenge the blocked_info if it encounters any I/O-related why_blocked reasons. So we add scavengeTSOIOManager in IOManager.{h,c} with the usual style. Now as it happens, right now, there is no special scavenging to do, so the implementation of scavengeTSOIOManager is a fancy no-op. That's because the select I/O manager uses only the fd and target members, which are not GC pointers, and the win32-legacy I/O manager _ought_ to be using GC-managed heap objects for the StgAsyncIOResult but it is actually usingthe C heap, so again no GC pointers. If the win32-legacy were doing this more sensibly, then scavengeTSOIOManager would be the right place to do the GC magic. Future I/O managers will need GC heap objects in the tso->blocked_info and will make use of this functionality. --- rts/IOManager.c | 26 ++++++++++++++++++++++++++ rts/IOManager.h | 5 +++++ rts/sm/Scav.c | 7 +++++++ 3 files changed, 38 insertions(+) diff --git a/rts/IOManager.c b/rts/IOManager.c index ee110d34f903..0c0b1819fcc8 100644 --- a/rts/IOManager.c +++ b/rts/IOManager.c @@ -480,6 +480,32 @@ void markCapabilityIOManager(evac_fn evac, } +void scavengeTSOIOManager(StgTSO *tso) +{ + switch (iomgr_type) { + + /* case IO_MANAGER_SELECT: + * BlockedOn{Read,Write} uses block_info.fd + * BlockedOnDelay uses block_info.target + * both of these are not GC pointers, so there is nothing to do. + */ + + /* case IO_MANAGER_WIN32_LEGACY: + * BlockedOn{Read,Write,DoProc} uses block_info.async_result + * The StgAsyncIOResult async_result is allocated on the C heap. + * It'd probably be better if it used the GC heap. If it did we'd + * scavenge it here. + */ + + default: + /* All the other I/O managers do not use I/O-related why_blocked + * reasons, so there are no cases to handle. + */ + break; + } +} + + /* Declared in rts/IOInterface.h. Used only by the MIO threaded I/O manager on * Unix platforms. */ diff --git a/rts/IOManager.h b/rts/IOManager.h index 803960b0c236..7d9b793e31c6 100644 --- a/rts/IOManager.h +++ b/rts/IOManager.h @@ -272,6 +272,11 @@ void wakeupIOManager(void); void markCapabilityIOManager(evac_fn evac, void *user, CapIOManager *iomgr); +/* GC hook: scavenge I/O related tso->block_info. Used by scavengeTSO. + */ +void scavengeTSOIOManager(StgTSO *tso); + + /* Several code paths are almost identical between read and write paths. In * such cases we use a shared code path with an enum to say which we're doing. */ diff --git a/rts/sm/Scav.c b/rts/sm/Scav.c index ca40a17632f5..59465e7bd185 100644 --- a/rts/sm/Scav.c +++ b/rts/sm/Scav.c @@ -61,6 +61,7 @@ #include "Trace.h" #include "Sanity.h" #include "Capability.h" +#include "IOManager.h" #include "LdvProfile.h" #include "HeapUtils.h" #include "Hash.h" @@ -145,6 +146,12 @@ scavengeTSO (StgTSO *tso) case NotBlocked: evacuate(&tso->block_info.closure); break; + case BlockedOnRead: + case BlockedOnWrite: + case BlockedOnDelay: + case BlockedOnDoProc: + scavengeTSOIOManager(tso); + break; default: #if defined(THREADED_RTS) // in the THREADED_RTS, block_info.closure must always point to a -- GitLab