ThrIOManager.c 4.25 KB
Newer Older
1 2 3 4 5 6 7 8 9 10
/* -----------------------------------------------------------------------------
 *
 * (c) The GHC Team, 1998-2006
 *
 * The IO manager thread in THREADED_RTS.  
 * See also libraries/base/GHC/Conc.lhs.
 *
 * ---------------------------------------------------------------------------*/

#include "Rts.h"
Simon Marlow's avatar
Simon Marlow committed
11
#include "IOManager.h"
12 13 14 15 16 17 18 19 20 21 22 23
#include "Prelude.h"
#include <windows.h>

// Here's the Event that we use to wake up the IO manager thread
static HANDLE io_manager_event = INVALID_HANDLE_VALUE;

// must agree with values in GHC.Conc:
#define IO_MANAGER_WAKEUP 0xffffffff
#define IO_MANAGER_DIE    0xfffffffe
// spurios wakeups are returned as zero.
// console events are ((event<<1) | 1)

24 25 26 27 28 29 30 31 32
#if defined(THREADED_RTS)

#define EVENT_BUFSIZ 256
Mutex event_buf_mutex;
StgWord32 event_buf[EVENT_BUFSIZ];
nat next_event;

#endif

33 34 35 36 37 38 39 40 41
HANDLE
getIOManagerEvent (void)
{
    // This function has to exist even in the non-THREADED_RTS,
    // because code in GHC.Conc refers to it.  It won't ever be called
    // unless we're in the threaded RTS, however.
#ifdef THREADED_RTS
    HANDLE hRes;

42 43
    ACQUIRE_LOCK(&event_buf_mutex);

44 45 46 47
    if (io_manager_event == INVALID_HANDLE_VALUE) {
        hRes = CreateEvent ( NULL, // no security attrs
                             TRUE, // manual reset
                             FALSE, // initial state,
48
                             NULL ); // event name: NULL for private events
49 50 51 52 53 54
        if (hRes == NULL) {
            sysErrorBelch("getIOManagerEvent");
            stg_exit(EXIT_FAILURE);
        }
        io_manager_event = hRes;
    } else {
55
        hRes = io_manager_event;
56
    }
57 58 59

    RELEASE_LOCK(&event_buf_mutex);
    return hRes;
60 61 62 63 64 65
#else
    return NULL;
#endif
}


Ian Lynagh's avatar
Ian Lynagh committed
66
HsWord32
67 68 69 70 71
readIOManagerEvent (void)
{
    // This function must exist even in non-THREADED_RTS, 
    // see getIOManagerEvent() above.
#if defined(THREADED_RTS)
Ian Lynagh's avatar
Ian Lynagh committed
72
    HsWord32 res;
73

74 75
    ACQUIRE_LOCK(&event_buf_mutex);

76 77 78 79
    if (io_manager_event != INVALID_HANDLE_VALUE) {
        if (next_event == 0) {
            res = 0; // no event to return
        } else {
Ian Lynagh's avatar
Ian Lynagh committed
80
            res = (HsWord32)(event_buf[--next_event]);
81 82 83 84 85 86 87 88 89 90
            if (next_event == 0) {
                if (!ResetEvent(io_manager_event)) {
                    sysErrorBelch("readIOManagerEvent");
                    stg_exit(EXIT_FAILURE);
                }
            }
        }
    } else {
        res = 0;
    }
91 92 93

    RELEASE_LOCK(&event_buf_mutex);

94 95 96 97 98 99 100 101
    // debugBelch("readIOManagerEvent: %d\n", res);
    return res;
#else
    return 0;
#endif
}

void
Ian Lynagh's avatar
Ian Lynagh committed
102
sendIOManagerEvent (HsWord32 event)
103 104
{
#if defined(THREADED_RTS)
105 106
    ACQUIRE_LOCK(&event_buf_mutex);

107 108 109 110 111 112 113 114 115
    // debugBelch("sendIOManagerEvent: %d\n", event);
    if (io_manager_event != INVALID_HANDLE_VALUE) {
        if (next_event == EVENT_BUFSIZ) {
            errorBelch("event buffer overflowed; event dropped");
        } else {
            if (!SetEvent(io_manager_event)) {
                sysErrorBelch("sendIOManagerEvent");
                stg_exit(EXIT_FAILURE);
            }        
Ian Lynagh's avatar
Ian Lynagh committed
116
            event_buf[next_event++] = (StgWord32)event;
117 118
        }
    }
119 120

    RELEASE_LOCK(&event_buf_mutex);
121 122 123 124 125 126 127 128 129
#endif
}    

void
ioManagerWakeup (void)
{
    sendIOManagerEvent(IO_MANAGER_WAKEUP);
}

130
#if defined(THREADED_RTS)
131 132 133 134
void
ioManagerDie (void)
{
    sendIOManagerEvent(IO_MANAGER_DIE);
Simon Marlow's avatar
Simon Marlow committed
135 136 137
    // IO_MANAGER_DIE must be idempotent, as it is called
    // repeatedly by shutdownCapability().  Try conc059(threaded1) to
    // illustrate the problem.
138
    ACQUIRE_LOCK(&event_buf_mutex);
Simon Marlow's avatar
Simon Marlow committed
139
    io_manager_event = INVALID_HANDLE_VALUE;
140
    RELEASE_LOCK(&event_buf_mutex);
141 142 143 144 145 146 147 148 149 150 151 152 153 154
    // ToDo: wait for the IO manager to pick up the event, and
    // then release the Event and Mutex objects we've allocated.
}

void
ioManagerStart (void)
{
    initMutex(&event_buf_mutex);
    next_event = 0;

    // Make sure the IO manager thread is running
    Capability *cap;
    if (io_manager_event == INVALID_HANDLE_VALUE) {
	cap = rts_lock();
155
#if defined(COMPILING_WINDOWS_DLL)
156
        rts_evalIO(&cap,_imp__base_GHCziConcziIO_ensureIOManagerIsRunning_closure,NULL);
157
#else
158
        rts_evalIO(&cap,&base_GHCziConcziIO_ensureIOManagerIsRunning_closure,NULL);
159
#endif
160 161 162 163
	rts_unlock(cap);
    }
}
#endif