diff --git a/rts/Capability.c b/rts/Capability.c index a9fe393a08db207bab3a60b1c14dda5ac1ad7fd2..ad6965d93f45f0949919f7937dcf1fc4dad50c97 100644 --- a/rts/Capability.c +++ b/rts/Capability.c @@ -1322,7 +1322,7 @@ markCapability (evac_fn evac, void *user, Capability *cap, } #endif - markCapabilityIOManager(evac, user, cap->iomgr); + markCapabilityIOManager(evac, user, cap); // Free STM structures for this Capability stmPreGCHook(cap); diff --git a/rts/Capability.h b/rts/Capability.h index 463e03cf133d14ef843327706bbbcacba8088813..f54eaf97ba9520889deaae18787acd51f5ff8687 100644 --- a/rts/Capability.h +++ b/rts/Capability.h @@ -24,7 +24,6 @@ #include "Task.h" #include "Sparks.h" #include "sm/NonMovingMark.h" // for MarkQueue -#include "IOManager.h" // for CapIOManager #include "BeginPrivate.h" @@ -36,6 +35,15 @@ #define CAPABILITY_ALIGNMENT 64 #endif +/* A forward declaration of the per-capability data structures belonging to + * the I/O manager. It is opaque and only passed by pointer, so the full + * structure definition is not needed. The full definition can be found in + * IOManagerInternals.h, which is only used by IOManager.c and the individual + * I/O manager implementations. + */ +struct _CapIOManager; +typedef struct _CapIOManager CapIOManager; + /* N.B. This must be consistent with CapabilityPublic in RtsAPI.h */ struct Capability_ { // State required by the STG virtual machine when running Haskell diff --git a/rts/IOManager.c b/rts/IOManager.c index e0e4ef04ac2e207446e00926b0a18fe7c6f40182..894a12cf4276d9cae47f8ac16a7733cc5d6652e0 100644 --- a/rts/IOManager.c +++ b/rts/IOManager.c @@ -22,6 +22,9 @@ #include "Schedule.h" #include "RtsFlags.h" #include "RtsUtils.h" +#include "sm/Evac.h" + +#include "IOManagerInternals.h" #if defined(IOMGR_ENABLED_SELECT) #include "Threads.h" @@ -475,30 +478,32 @@ void wakeupIOManager(void) } } -void markCapabilityIOManager(evac_fn evac, - void *user, - CapIOManager *iomgr) +void markCapabilityIOManager(evac_fn evac, void *user, Capability *cap) { - switch (iomgr_type) { #if defined(IOMGR_ENABLED_SELECT) case IO_MANAGER_SELECT: + { + CapIOManager *iomgr = cap->iomgr; evac(user, (StgClosure **)(void *)&iomgr->blocked_queue_hd); evac(user, (StgClosure **)(void *)&iomgr->blocked_queue_tl); evac(user, (StgClosure **)(void *)&iomgr->sleeping_queue); break; + } #endif #if defined(IOMGR_ENABLED_WIN32_LEGACY) case IO_MANAGER_WIN32_LEGACY: + { + CapIOManager *iomgr = cap->iomgr; evac(user, (StgClosure **)(void *)&iomgr->blocked_queue_hd); evac(user, (StgClosure **)(void *)&iomgr->blocked_queue_tl); break; + } #endif default: break; } - } @@ -545,18 +550,24 @@ setIOManagerControlFd(uint32_t cap_no, int fd) { #endif -bool anyPendingTimeoutsOrIO(CapIOManager *iomgr) +bool anyPendingTimeoutsOrIO(Capability *cap) { switch (iomgr_type) { #if defined(IOMGR_ENABLED_SELECT) case IO_MANAGER_SELECT: - return (iomgr->blocked_queue_hd != END_TSO_QUEUE) - || (iomgr->sleeping_queue != END_TSO_QUEUE); + { + CapIOManager *iomgr = cap->iomgr; + return (iomgr->blocked_queue_hd != END_TSO_QUEUE) + || (iomgr->sleeping_queue != END_TSO_QUEUE); + } #endif #if defined(IOMGR_ENABLED_WIN32_LEGACY) case IO_MANAGER_WIN32_LEGACY: - return (iomgr->blocked_queue_hd != END_TSO_QUEUE); + { + CapIOManager *iomgr = cap->iomgr; + return (iomgr->blocked_queue_hd != END_TSO_QUEUE); + } #endif /* For the purpose of the scheduler, the threaded I/O managers never have diff --git a/rts/IOManager.h b/rts/IOManager.h index b54dbd0974d1b8df15841a6c5909657b488744e3..d56f9a94e7448379c80f54ed41e0b4b3cf9a351f 100644 --- a/rts/IOManager.h +++ b/rts/IOManager.h @@ -19,10 +19,9 @@ #pragma once -#include "BeginPrivate.h" - #include "sm/GC.h" // for evac_fn -#include "posix/Select.h" // for LowResTime TODO: switch to normal Time + +#include "BeginPrivate.h" /* The ./configure gives us a set of CPP flags, one for each named I/O manager: * IOMGR_BUILD_<name> : which ones should be built (some) @@ -156,6 +155,20 @@ extern bool rts_IOManagerIsWin32Native; #endif +/* The CapIOManager is the per-capability data structure belonging to the I/O + * manager. It is defined in full in IOManagerInternals.h. The opaque forward + * declaration for it lives in Capability.h, and looks like: + * + * struct _CapIOManager; + * typedef struct _CapIOManager CapIOManager; + * + * It can be accessed as cap->iomgr. + * + * The content of the structure is defined conditionally so it is different for + * each I/O manager implementation. + */ + + /* Parse the I/O manager flag value, returning if is available, unavailable or * unrecognised. * @@ -177,42 +190,6 @@ parseIOManagerFlag(const char *iomgrstr, IO_MANAGER_FLAG *flag); */ bool is_io_mng_native_p (void); -/* The per-capability data structures belonging to the I/O manager. - * - * It can be accessed as cap->iomgr. - * - * The content of the structure is defined conditionally so it is different for - * each I/O manager implementation. - * - * TODO: once the content of this struct is genuinely private, and not shared - * with other parts of the RTS, then it can be made opaque, so the content is - * known only to the I/O manager and not the rest of the RTS. - */ -typedef struct { - -#if defined(IOMGR_ENABLED_SELECT) - /* Thread queue for threads blocked on I/O completion. */ - StgTSO *blocked_queue_hd; - StgTSO *blocked_queue_tl; - - /* Thread queue for threads blocked on timeouts. */ - StgTSO *sleeping_queue; -#endif - -#if defined(IOMGR_ENABLED_WIN32_LEGACY) - /* Thread queue for threads blocked on I/O completion. */ - StgTSO *blocked_queue_hd; - StgTSO *blocked_queue_tl; -#endif - -#if defined(IOMGR_ENABLED_MIO_POSIX) - /* Control FD for the (posix) MIO manager for this capability, - */ - int control_fd; -#endif - -} CapIOManager; - /* Init hook: called from hs_init_ghc, early in the startup after the RTS flags * have been processed. @@ -283,7 +260,7 @@ void wakeupIOManager(void); /* GC hook: mark any per-capability GC roots the I/O manager uses. */ -void markCapabilityIOManager(evac_fn evac, void *user, CapIOManager *iomgr); +void markCapabilityIOManager(evac_fn evac, void *user, Capability *cap); /* GC hook: scavenge I/O related tso->block_info. Used by scavengeTSO. @@ -324,7 +301,7 @@ void appendToIOBlockedQueue(Capability *cap, StgTSO *tso); * This is used by the scheduler as part of deadlock-detection, and the * "context switch as often as possible" test. */ -bool anyPendingTimeoutsOrIO(CapIOManager *iomgr); +bool anyPendingTimeoutsOrIO(Capability *cap); /* If there are any completed I/O operations or expired timers, process the * completions as appropriate (which will typically unblock some waiting diff --git a/rts/IOManagerInternals.h b/rts/IOManagerInternals.h new file mode 100644 index 0000000000000000000000000000000000000000..a294f28aa4909cc2fada597b4152e7ff45ecf2c3 --- /dev/null +++ b/rts/IOManagerInternals.h @@ -0,0 +1,54 @@ +/* ----------------------------------------------------------------------------- + * + * (c) The GHC Team 1998-2020 + * + * Internal type definitions for use within the I/O manager implementations, + * but not exposed to the rest of the RTS that calls into the I/O managers. + * + * In particular this defines the representation of CapIOManager, which is + * known only to IOManager.c and each individual I/O manager implementation. + * + * -------------------------------------------------------------------------*/ + +#pragma once + +#include "IOManager.h" + +#include "BeginPrivate.h" + +/* The per-capability data structures belonging to the I/O manager. + * + * It can be accessed as cap->iomgr. + * + * The content of the structure is defined conditionally so it is different for + * each I/O manager implementation. + * + * Here is where we actually define the representation. + */ +struct _CapIOManager { + +#if defined(IOMGR_ENABLED_SELECT) + /* Thread queue for threads blocked on I/O completion. */ + StgTSO *blocked_queue_hd; + StgTSO *blocked_queue_tl; + + /* Thread queue for threads blocked on timeouts. */ + StgTSO *sleeping_queue; +#endif + +#if defined(IOMGR_ENABLED_WIN32_LEGACY) + /* Thread queue for threads blocked on I/O completion. */ + StgTSO *blocked_queue_hd; + StgTSO *blocked_queue_tl; +#endif + +#if defined(IOMGR_ENABLED_MIO_POSIX) + /* Control FD for the (posix) MIO manager for this capability, + */ + int control_fd; +#endif + +}; + +#include "EndPrivate.h" + diff --git a/rts/RtsFlags.c b/rts/RtsFlags.c index b0c6b13beb1ba85e55c17f81484d4d9b4a1e5497..ed88015e23646e2f60db504286e0ff6c8203f206 100644 --- a/rts/RtsFlags.c +++ b/rts/RtsFlags.c @@ -16,6 +16,7 @@ #include "sm/OSMem.h" #include "hooks/Hooks.h" #include "Capability.h" +#include "IOManager.h" #if defined(HAVE_CTYPE_H) #include <ctype.h> diff --git a/rts/Schedule.c b/rts/Schedule.c index 1dd903e27a99eed2baadc7ed00c09cdefbc79dce..0f3c737d0c28cd662cb07c954797d58c16a48d4f 100644 --- a/rts/Schedule.c +++ b/rts/Schedule.c @@ -405,7 +405,7 @@ schedule (Capability *initialCapability, Task *task) */ if (RtsFlags.ConcFlags.ctxtSwitchTicks == 0 && (!emptyRunQueue(cap) || - anyPendingTimeoutsOrIO(cap->iomgr))) { + anyPendingTimeoutsOrIO(cap))) { RELAXED_STORE(&cap->context_switch, 1); } @@ -932,7 +932,7 @@ scheduleCheckBlockedThreads(Capability *cap USED_IF_NOT_THREADS) * awaitCompletedTimeoutsOrIO below for the case of !defined(THREADED_RTS) * && defined(mingw32_HOST_OS). */ - if (anyPendingTimeoutsOrIO(cap->iomgr)) + if (anyPendingTimeoutsOrIO(cap)) { if (emptyRunQueue(cap)) { // block and wait @@ -959,7 +959,7 @@ scheduleDetectDeadlock (Capability **pcap, Task *task) * other tasks are waiting for work, we must have a deadlock of * some description. */ - if ( emptyRunQueue(cap) && !anyPendingTimeoutsOrIO(cap->iomgr) ) + if ( emptyRunQueue(cap) && !anyPendingTimeoutsOrIO(cap) ) { #if defined(THREADED_RTS) /* diff --git a/rts/posix/Select.c b/rts/posix/Select.c index 26da034f0253e3be7b6c4e409c8a853d348cf71f..92c7948e55d6361b5ad084e2612dc4ef2f155b06 100644 --- a/rts/posix/Select.c +++ b/rts/posix/Select.c @@ -19,7 +19,7 @@ #include "RtsUtils.h" #include "Capability.h" #include "Select.h" -#include "IOManager.h" +#include "IOManagerInternals.h" #include "Stats.h" #include "GetTime.h" diff --git a/rts/posix/Signals.c b/rts/posix/Signals.c index c21a5c07e599fa3533b500be56e517f8437cc717..b6bfe77f3527f2e22ef01e61a7254df6ea668f05 100644 --- a/rts/posix/Signals.c +++ b/rts/posix/Signals.c @@ -19,6 +19,12 @@ #include "ThreadLabels.h" #include "Libdw.h" +/* TODO: eliminate this include. This file should be about signals, not be + * part of an I/O manager implementation. The code here that are really part + * of an I/O manager should be moved into an appropriate I/O manager impl. + */ +#include "IOManagerInternals.h" + #if defined(alpha_HOST_ARCH) # if defined(linux_HOST_OS) # include <asm/fpu.h> diff --git a/rts/win32/AsyncMIO.c b/rts/win32/AsyncMIO.c index a581c555abe9cc77f833725aba8e7f8ab7764fbb..964914961f086246349e68f3a79e21fc2e854afe 100644 --- a/rts/win32/AsyncMIO.c +++ b/rts/win32/AsyncMIO.c @@ -16,6 +16,7 @@ #include <stdio.h> #include "Schedule.h" #include "Capability.h" +#include "IOManagerInternals.h" #include "win32/AsyncMIO.h" #include "win32/MIOManager.h"