diff --git a/rts/IOManager.c b/rts/IOManager.c
index 383b042a00f7051b17b75e491a5deee645ed08f2..69fcdc2d9c74c964d88176f28668b467075fd000 100644
--- a/rts/IOManager.c
+++ b/rts/IOManager.c
@@ -467,6 +467,59 @@ setIOManagerControlFd(uint32_t cap_no USED_IF_THREADS, int fd USED_IF_THREADS) {
 }
 #endif
 
+
+bool anyPendingTimeoutsOrIO(CapIOManager *iomgr USED_IF_NOT_THREADS)
+{
+    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);
+#endif
+
+#if defined(IOMGR_ENABLED_WIN32_LEGACY)
+        case IO_MANAGER_WIN32_LEGACY:
+          return (iomgr->blocked_queue_hd != END_TSO_QUEUE);
+#endif
+
+    /* For the purpose of the scheduler, the threaded I/O managers never have
+       pending I/O or timers. Of course in reality they do, but they're
+       managed via other primitives that the scheduler can see into (threads,
+       MVars and foreign blocking calls).
+     */
+#if defined(IOMGR_ENABLED_MIO_POSIX)
+        case IO_MANAGER_MIO_POSIX:
+          return false;
+#endif
+
+#if defined(IOMGR_ENABLED_MIO_WIN32)
+        case IO_MANAGER_MIO_WIN32:
+          return false;
+#endif
+
+#if defined(IOMGR_ENABLED_WINIO)
+#if defined(THREADED_RTS)
+        /* As above, the threaded variants never have pending I/O or timers */
+        case IO_MANAGER_WINIO:
+          return false;
+#else
+        case IO_MANAGER_WINIO:
+          return false;
+        /* FIXME: But what is this? The WinIO I/O manager *also* returns false
+           in the non-threaded case! This is *totally bogus*! In the
+           non-threaded RTS the scheduler expects to be able to poll for IO.
+           The fact that this gives a wrong and useless answer for WinIO is
+           probably the cause of the complication in the scheduler with having
+           to call awaitCompletedTimeoutsOrIO() in multiple places (on Windows,
+           non-threaded).
+         */
+#endif
+#endif
+        default:
+            barf("anyPendingTimeoutsOrIO not implemented");
+    }
+}
+
 #pragma GCC diagnostic push
 #pragma GCC diagnostic ignored "-Wsuggest-attribute=noreturn"
 
diff --git a/rts/IOManager.h b/rts/IOManager.h
index 55d6239b5d458e0566d97a42299d7f3aeaecec50..62be167d6eaf00db69c0e07a10941b0724342549 100644
--- a/rts/IOManager.h
+++ b/rts/IOManager.h
@@ -301,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.
  */
-INLINE_HEADER bool anyPendingTimeoutsOrIO(CapIOManager *iomgr);
+bool anyPendingTimeoutsOrIO(CapIOManager *iomgr);
 
 
 #if !defined(THREADED_RTS)
@@ -332,40 +332,4 @@ void awaitEvent(Capability *cap, bool wait);
 #define USED_IF_THREADS_AND_NOT_MINGW32 STG_UNUSED
 #endif
 
-/* -----------------------------------------------------------------------------
- * INLINE functions... private from here on down.
- *
- * Some of these hooks are performance sensitive so parts of them are
- * implemented here so they can be inlined.
- * -----------------------------------------------------------------------------
- */
-
-INLINE_HEADER bool anyPendingTimeoutsOrIO(CapIOManager *iomgr USED_IF_NOT_THREADS)
-{
-#if defined(THREADED_RTS)
-    /* For the purpose of the scheduler, the threaded I/O managers never have
-       pending I/O or timers. Of course in reality they do, but they're
-       managed via other primitives that the scheduler can see into (threads,
-       MVars and foreign blocking calls).
-     */
-    return false;
-#else
-#if defined(mingw32_HOST_OS)
-    /* The MIO I/O manager uses the blocked_queue, while the WinIO does not.
-       Note: the latter fact makes this test useless for the WinIO I/O manager,
-       and is the probable cause of the complication in the scheduler with
-       having to call awaitEvent in multiple places.
-
-       None of the Windows I/O managers use the sleeping_queue
-     */
-    return (iomgr->blocked_queue_hd != END_TSO_QUEUE);
-#else
-    /* The select() I/O manager uses the blocked_queue and the sleeping_queue.
-     */
-    return (iomgr->blocked_queue_hd != END_TSO_QUEUE)
-        || (iomgr->sleeping_queue   != END_TSO_QUEUE);
-#endif
-#endif
-}
-
 #include "EndPrivate.h"