Skip to content
Snippets Groups Projects
Commit f0c1f862 authored by Duncan Coutts's avatar Duncan Coutts Committed by Marge Bot
Browse files

Have the throwTo impl go via (new) IOManager APIs

rather than directly operating on the IO manager's data structures.

Specifically, when thowing an async exception to a thread that is
blocked waiting for I/O or waiting for a timer, then we want to cancel
that I/O waiting or cancel the timer. Currently this is done directly in
removeFromQueues() in RaiseAsync.c. We want it to go via proper APIs
both for modularity but also to let us support multiple I/O managers.

So add sync{IO,Delay}Cancel, which is the cancellation for the
corresponding sync{IO,Delay}. The implementations of these use the usual
"switch (iomgr_type)" style.
parent b48805b9
No related branches found
No related tags found
No related merge requests found
......@@ -23,7 +23,13 @@
#include "RtsFlags.h"
#include "RtsUtils.h"
#if !defined(mingw32_HOST_OS) && defined(HAVE_SIGNAL_H)
#if defined(IOMGR_ENABLED_SELECT)
#include "Threads.h"
#include "posix/Select.h"
#include "posix/Signals.h"
#endif
#if defined(IOMGR_ENABLED_MIO_POSIX)
#include "posix/Signals.h"
#endif
......@@ -33,6 +39,7 @@
#endif
#if defined(IOMGR_ENABLED_WIN32_LEGACY)
#include "Threads.h"
#include "win32/AsyncMIO.h"
#include "win32/MIOManager.h"
#endif
......@@ -571,6 +578,29 @@ void syncIOWaitReady(Capability *cap,
}
}
void syncIOCancel(Capability *cap, StgTSO *tso)
{
switch (iomgr_type) {
#if defined(IOMGR_ENABLED_SELECT)
case IO_MANAGER_SELECT:
removeThreadFromDeQueue(cap, &cap->iomgr->blocked_queue_hd,
&cap->iomgr->blocked_queue_tl, tso);
break;
#endif
#if defined(IOMGR_ENABLED_WIN32_LEGACY)
case IO_MANAGER_WIN32_LEGACY:
removeThreadFromDeQueue(cap, &cap->iomgr->blocked_queue_hd,
&cap->iomgr->blocked_queue_tl, tso);
abandonWorkRequest(tso->block_info.async_result->reqID);
break;
#endif
default:
barf("syncIOCancel not supported for I/O manager %d", iomgr_type);
}
}
#if defined(IOMGR_ENABLED_SELECT)
static void insertIntoSleepingQueue(Capability *cap, StgTSO *tso, LowResTime target);
#endif
......@@ -617,6 +647,29 @@ void syncDelay(Capability *cap, StgTSO *tso, HsInt us_delay)
}
}
void syncDelayCancel(Capability *cap, StgTSO *tso)
{
debugTrace(DEBUG_iomanager, "cancelling delay for thread %ld", (long) tso->id);
switch (iomgr_type) {
#if defined(IOMGR_ENABLED_SELECT)
case IO_MANAGER_SELECT:
removeThreadFromQueue(cap, &cap->iomgr->sleeping_queue, tso);
break;
#endif
/* Note: no case for IO_MANAGER_WIN32_LEGACY despite it having a case
* for syncDelay above. This is because the win32 legacy I/O manager
* treats delay as an I/O operation, using the BlockedOnDoProc blocking
* reason, rather than the BlockedOnDelay reason. As a consequence,
* cancellation goes via syncIOCancel instead. Yes, it's a bit weird.
*/
default:
barf("syncDelayCancel not supported for I/O manager %d", iomgr_type);
}
}
#if defined(IOMGR_ENABLED_SELECT) || defined(IOMGR_ENABLED_WIN32_LEGACY)
void appendToIOBlockedQueue(Capability *cap, StgTSO *tso)
{
......
......@@ -284,8 +284,12 @@ typedef enum { IORead, IOWrite } IOReadOrWrite;
void syncIOWaitReady(Capability *cap, StgTSO *tso, IOReadOrWrite rw, HsInt fd);
void syncIOCancel(Capability *cap, StgTSO *tso);
void syncDelay(Capability *cap, StgTSO *tso, HsInt us_delay);
void syncDelayCancel(Capability *cap, StgTSO *tso);
#if defined(IOMGR_ENABLED_SELECT) || defined(IOMGR_ENABLED_WIN32_LEGACY)
/* Add a thread to the end of the queue of threads blocked on I/O.
*
......
......@@ -20,6 +20,7 @@
#include "sm/Sanity.h"
#include "Profiling.h"
#include "Messages.h"
#include "IOManager.h"
#if defined(mingw32_HOST_OS)
#include "win32/MIOManager.h"
#endif
......@@ -703,26 +704,17 @@ removeFromQueues(Capability *cap, StgTSO *tso)
break;
}
#if !defined(THREADED_RTS)
case BlockedOnRead:
case BlockedOnWrite:
#if defined(mingw32_HOST_OS)
case BlockedOnDoProc:
#endif
removeThreadFromDeQueue(cap, &cap->iomgr->blocked_queue_hd,
&cap->iomgr->blocked_queue_tl, tso);
#if defined(mingw32_HOST_OS)
/* (Cooperatively) signal that the worker thread should abort
* the request.
*/
abandonWorkRequest(tso->block_info.async_result->reqID);
#endif
// These blocking reasons are only used by some I/O managers
syncIOCancel(cap, tso);
goto done;
case BlockedOnDelay:
removeThreadFromQueue(cap, &cap->iomgr->sleeping_queue, tso);
goto done;
#endif
// This blocking reasons is only used by some I/O managers
syncDelayCancel(cap, tso);
goto done;
default:
barf("removeFromQueues: %d", tso->why_blocked);
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment