35f1b5e1bf123b50b5800e96a10299edf0683958
[ghc.git] / rts / win32 / ThrIOManager.c
1 /* -----------------------------------------------------------------------------
2 *
3 * (c) The GHC Team, 1998-2006
4 *
5 * The IO manager thread in THREADED_RTS.
6 * See also libraries/base/GHC/Conc.lhs.
7 *
8 * ---------------------------------------------------------------------------*/
9
10 #include "Rts.h"
11 #include "IOManager.h"
12 #include "Prelude.h"
13 #include <windows.h>
14
15 // Here's the Event that we use to wake up the IO manager thread
16 static HANDLE io_manager_event = INVALID_HANDLE_VALUE;
17
18 // must agree with values in GHC.Conc:
19 #define IO_MANAGER_WAKEUP 0xffffffff
20 #define IO_MANAGER_DIE 0xfffffffe
21 // spurios wakeups are returned as zero.
22 // console events are ((event<<1) | 1)
23
24 HANDLE
25 getIOManagerEvent (void)
26 {
27 // This function has to exist even in the non-THREADED_RTS,
28 // because code in GHC.Conc refers to it. It won't ever be called
29 // unless we're in the threaded RTS, however.
30 #ifdef THREADED_RTS
31 HANDLE hRes;
32
33 if (io_manager_event == INVALID_HANDLE_VALUE) {
34 hRes = CreateEvent ( NULL, // no security attrs
35 TRUE, // manual reset
36 FALSE, // initial state,
37 NULL ); // event name: NULL for private events
38 if (hRes == NULL) {
39 sysErrorBelch("getIOManagerEvent");
40 stg_exit(EXIT_FAILURE);
41 }
42 io_manager_event = hRes;
43 return hRes;
44 } else {
45 return io_manager_event;
46 }
47 #else
48 return NULL;
49 #endif
50 }
51
52
53 #if defined(THREADED_RTS)
54
55 #define EVENT_BUFSIZ 256
56 Mutex event_buf_mutex;
57 StgWord32 event_buf[EVENT_BUFSIZ];
58 nat next_event;
59
60 #endif
61
62 HsWord32
63 readIOManagerEvent (void)
64 {
65 // This function must exist even in non-THREADED_RTS,
66 // see getIOManagerEvent() above.
67 #if defined(THREADED_RTS)
68 HsWord32 res;
69
70 if (io_manager_event != INVALID_HANDLE_VALUE) {
71 ACQUIRE_LOCK(&event_buf_mutex);
72 if (next_event == 0) {
73 res = 0; // no event to return
74 } else {
75 res = (HsWord32)(event_buf[--next_event]);
76 if (next_event == 0) {
77 if (!ResetEvent(io_manager_event)) {
78 sysErrorBelch("readIOManagerEvent");
79 stg_exit(EXIT_FAILURE);
80 }
81 }
82 }
83 RELEASE_LOCK(&event_buf_mutex);
84 } else {
85 res = 0;
86 }
87 // debugBelch("readIOManagerEvent: %d\n", res);
88 return res;
89 #else
90 return 0;
91 #endif
92 }
93
94 void
95 sendIOManagerEvent (HsWord32 event)
96 {
97 #if defined(THREADED_RTS)
98 // debugBelch("sendIOManagerEvent: %d\n", event);
99 if (io_manager_event != INVALID_HANDLE_VALUE) {
100 ACQUIRE_LOCK(&event_buf_mutex);
101 if (next_event == EVENT_BUFSIZ) {
102 errorBelch("event buffer overflowed; event dropped");
103 } else {
104 if (!SetEvent(io_manager_event)) {
105 sysErrorBelch("sendIOManagerEvent");
106 stg_exit(EXIT_FAILURE);
107 }
108 event_buf[next_event++] = (StgWord32)event;
109 }
110 RELEASE_LOCK(&event_buf_mutex);
111 }
112 #endif
113 }
114
115 void
116 ioManagerWakeup (void)
117 {
118 sendIOManagerEvent(IO_MANAGER_WAKEUP);
119 }
120
121 #if defined(THREADED_RTS)
122 void
123 ioManagerDie (void)
124 {
125 sendIOManagerEvent(IO_MANAGER_DIE);
126 // IO_MANAGER_DIE must be idempotent, as it is called
127 // repeatedly by shutdownCapability(). Try conc059(threaded1) to
128 // illustrate the problem.
129 io_manager_event = INVALID_HANDLE_VALUE;
130 // ToDo: wait for the IO manager to pick up the event, and
131 // then release the Event and Mutex objects we've allocated.
132 }
133
134 void
135 ioManagerStart (void)
136 {
137 initMutex(&event_buf_mutex);
138 next_event = 0;
139
140 // Make sure the IO manager thread is running
141 Capability *cap;
142 if (io_manager_event == INVALID_HANDLE_VALUE) {
143 cap = rts_lock();
144 #if defined(mingw32_HOST_OS) && defined(__PIC__)
145 rts_evalIO(cap,_imp__base_GHCziConc_ensureIOManagerIsRunning_closure,NULL);
146 #else
147 rts_evalIO(cap,&base_GHCziConc_ensureIOManagerIsRunning_closure,NULL);
148 #endif
149 rts_unlock(cap);
150 }
151 }
152 #endif