Implement vararg support for s390. Minor fix to atomic operation for s390.
[mono.git] / mono / io-layer / events.c
blobc99175dd34224c2e8c9cae062487d8fdd5041036
1 /*
2 * events.c: Event handles
4 * Author:
5 * Dick Porter (dick@ximian.com)
7 * (C) 2002 Ximian, Inc.
8 */
10 #include <config.h>
11 #include <glib.h>
12 #include <pthread.h>
13 #include <string.h>
15 #include <mono/io-layer/wapi.h>
16 #include <mono/io-layer/wapi-private.h>
17 #include <mono/io-layer/handles-private.h>
18 #include <mono/io-layer/misc-private.h>
20 #include <mono/io-layer/mono-mutex.h>
22 #include <mono/io-layer/event-private.h>
24 #undef DEBUG
26 static void event_close_shared (gpointer handle);
27 static void event_signal(gpointer handle);
28 static void event_own (gpointer handle);
30 struct _WapiHandleOps _wapi_event_ops = {
31 event_close_shared, /* close_shared */
32 NULL, /* close_private */
33 event_signal, /* signal */
34 event_own, /* own */
35 NULL, /* is_owned */
38 static mono_once_t event_ops_once=MONO_ONCE_INIT;
40 static void event_ops_init (void)
42 _wapi_handle_register_capabilities (WAPI_HANDLE_EVENT,
43 WAPI_HANDLE_CAP_WAIT |
44 WAPI_HANDLE_CAP_SIGNAL);
47 static void event_close_shared(gpointer handle)
49 struct _WapiHandle_event *event_handle;
50 gboolean ok;
52 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_EVENT,
53 (gpointer *)&event_handle, NULL);
54 if(ok==FALSE) {
55 g_warning (G_GNUC_PRETTY_FUNCTION
56 ": error looking up event handle %p", handle);
57 return;
60 #ifdef DEBUG
61 g_message(G_GNUC_PRETTY_FUNCTION ": closing event handle %p", handle);
62 #endif
65 static void event_signal(gpointer handle)
67 ResetEvent(handle);
70 static void event_own (gpointer handle)
72 struct _WapiHandle_event *event_handle;
73 gboolean ok;
75 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_EVENT,
76 (gpointer *)&event_handle, NULL);
77 if(ok==FALSE) {
78 g_warning (G_GNUC_PRETTY_FUNCTION
79 ": error looking up event handle %p", handle);
80 return;
83 #ifdef DEBUG
84 g_message(G_GNUC_PRETTY_FUNCTION ": owning event handle %p", handle);
85 #endif
87 if(event_handle->manual==FALSE) {
88 g_assert (event_handle->set_count > 0);
90 if (--event_handle->set_count == 0) {
91 _wapi_handle_set_signal_state (handle, FALSE, FALSE);
96 /**
97 * CreateEvent:
98 * @security: Ignored for now.
99 * @manual: Specifies whether the new event handle has manual or auto
100 * reset behaviour.
101 * @initial: Specifies whether the new event handle is initially
102 * signalled or not.
103 * @name:Pointer to a string specifying the name of this name, or
104 * %NULL. Currently ignored.
106 * Creates a new event handle.
108 * An event handle is signalled with SetEvent(). If the new handle is
109 * a manual reset event handle, it remains signalled until it is reset
110 * with ResetEvent(). An auto reset event remains signalled until a
111 * single thread has waited for it, at which time the event handle is
112 * automatically reset to unsignalled.
114 * Return value: A new handle, or %NULL on error.
116 gpointer CreateEvent(WapiSecurityAttributes *security G_GNUC_UNUSED, gboolean manual,
117 gboolean initial, const gunichar2 *name G_GNUC_UNUSED)
119 struct _WapiHandle_event *event_handle;
120 gpointer handle;
121 gboolean ok;
122 gpointer ret = NULL;
123 int thr_ret;
125 mono_once (&event_ops_once, event_ops_init);
127 handle=_wapi_handle_new (WAPI_HANDLE_EVENT);
128 if(handle==_WAPI_HANDLE_INVALID) {
129 g_warning (G_GNUC_PRETTY_FUNCTION
130 ": error creating event handle");
131 return(NULL);
134 pthread_cleanup_push ((void(*)(void *))_wapi_handle_unlock_handle,
135 handle);
136 thr_ret = _wapi_handle_lock_handle (handle);
137 g_assert (thr_ret == 0);
139 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_EVENT,
140 (gpointer *)&event_handle, NULL);
141 if(ok==FALSE) {
142 g_warning (G_GNUC_PRETTY_FUNCTION
143 ": error looking up event handle %p", handle);
144 goto cleanup;
146 ret = handle;
148 event_handle->manual=manual;
149 event_handle->set_count = 0;
151 if(initial==TRUE) {
152 if (manual == FALSE) {
153 event_handle->set_count = 1;
156 _wapi_handle_set_signal_state (handle, TRUE, FALSE);
159 #ifdef DEBUG
160 g_message(G_GNUC_PRETTY_FUNCTION ": created new event handle %p",
161 handle);
162 #endif
164 cleanup:
165 thr_ret = _wapi_handle_unlock_handle (handle);
166 g_assert (thr_ret == 0);
168 pthread_cleanup_pop (0);
170 return(ret);
174 * PulseEvent:
175 * @handle: The event handle.
177 * Sets the event handle @handle to the signalled state, and then
178 * resets it to unsignalled after informing any waiting threads.
180 * If @handle is a manual reset event, all waiting threads that can be
181 * released immediately are released. @handle is then reset. If
182 * @handle is an auto reset event, one waiting thread is released even
183 * if multiple threads are waiting.
185 * Return value: %TRUE on success, %FALSE otherwise. (Currently only
186 * ever returns %TRUE).
188 gboolean PulseEvent(gpointer handle)
190 struct _WapiHandle_event *event_handle;
191 gboolean ok;
192 int thr_ret;
194 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_EVENT,
195 (gpointer *)&event_handle, NULL);
196 if(ok==FALSE) {
197 g_warning (G_GNUC_PRETTY_FUNCTION
198 ": error looking up event handle %p", handle);
199 return(FALSE);
202 pthread_cleanup_push ((void(*)(void *))_wapi_handle_unlock_handle,
203 handle);
204 thr_ret = _wapi_handle_lock_handle (handle);
205 g_assert (thr_ret == 0);
207 #ifdef DEBUG
208 g_message(G_GNUC_PRETTY_FUNCTION ": Pulsing event handle %p", handle);
209 #endif
211 if(event_handle->manual==TRUE) {
212 _wapi_handle_set_signal_state (handle, TRUE, TRUE);
213 } else {
214 event_handle->set_count++;
215 _wapi_handle_set_signal_state (handle, TRUE, FALSE);
218 thr_ret = _wapi_handle_unlock_handle (handle);
219 g_assert (thr_ret == 0);
221 pthread_cleanup_pop (0);
223 if(event_handle->manual==TRUE) {
224 /* For a manual-reset event, we're about to try and
225 * get the handle lock again, so give other threads a
226 * chance
228 sched_yield ();
230 /* Reset the handle signal state */
231 /* I'm not sure whether or not we need a barrier here
232 * to make sure that all threads waiting on the event
233 * have proceeded. Currently we rely on broadcasting
234 * a condition.
236 #ifdef DEBUG
237 g_message(G_GNUC_PRETTY_FUNCTION
238 ": Obtained write lock on event handle %p", handle);
239 #endif
241 pthread_cleanup_push ((void(*)(void *))_wapi_handle_unlock_handle, handle);
242 thr_ret = _wapi_handle_lock_handle (handle);
243 g_assert (thr_ret == 0);
245 _wapi_handle_set_signal_state (handle, FALSE, FALSE);
247 thr_ret = _wapi_handle_unlock_handle (handle);
248 g_assert (thr_ret == 0);
249 pthread_cleanup_pop (0);
252 return(TRUE);
256 * ResetEvent:
257 * @handle: The event handle.
259 * Resets the event handle @handle to the unsignalled state.
261 * Return value: %TRUE on success, %FALSE otherwise. (Currently only
262 * ever returns %TRUE).
264 gboolean ResetEvent(gpointer handle)
266 struct _WapiHandle_event *event_handle;
267 gboolean ok;
268 int thr_ret;
270 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_EVENT,
271 (gpointer *)&event_handle, NULL);
272 if(ok==FALSE) {
273 g_warning (G_GNUC_PRETTY_FUNCTION
274 ": error looking up event handle %p", handle);
275 return(FALSE);
278 #ifdef DEBUG
279 g_message(G_GNUC_PRETTY_FUNCTION ": Resetting event handle %p",
280 handle);
281 #endif
283 pthread_cleanup_push ((void(*)(void *))_wapi_handle_unlock_handle,
284 handle);
285 thr_ret = _wapi_handle_lock_handle (handle);
286 g_assert (thr_ret == 0);
288 if(_wapi_handle_issignalled (handle)==FALSE) {
289 #ifdef DEBUG
290 g_message(G_GNUC_PRETTY_FUNCTION
291 ": No need to reset event handle %p", handle);
292 #endif
293 } else {
294 #ifdef DEBUG
295 g_message(G_GNUC_PRETTY_FUNCTION
296 ": Obtained write lock on event handle %p", handle);
297 #endif
299 _wapi_handle_set_signal_state (handle, FALSE, FALSE);
302 event_handle->set_count = 0;
304 thr_ret = _wapi_handle_unlock_handle (handle);
305 g_assert (thr_ret == 0);
307 pthread_cleanup_pop (0);
309 return(TRUE);
313 * SetEvent:
314 * @handle: The event handle
316 * Sets the event handle @handle to the signalled state.
318 * If @handle is a manual reset event, it remains signalled until it
319 * is reset with ResetEvent(). An auto reset event remains signalled
320 * until a single thread has waited for it, at which time @handle is
321 * automatically reset to unsignalled.
323 * Return value: %TRUE on success, %FALSE otherwise. (Currently only
324 * ever returns %TRUE).
326 gboolean SetEvent(gpointer handle)
328 struct _WapiHandle_event *event_handle;
329 gboolean ok;
330 int thr_ret;
332 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_EVENT,
333 (gpointer *)&event_handle, NULL);
334 if(ok==FALSE) {
335 g_warning (G_GNUC_PRETTY_FUNCTION
336 ": error looking up event handle %p", handle);
337 return(FALSE);
340 pthread_cleanup_push ((void(*)(void *))_wapi_handle_unlock_handle,
341 handle);
342 thr_ret = _wapi_handle_lock_handle (handle);
343 g_assert (thr_ret == 0);
345 #ifdef DEBUG
346 g_message(G_GNUC_PRETTY_FUNCTION ": Setting event handle %p", handle);
347 #endif
349 if(event_handle->manual==TRUE) {
350 _wapi_handle_set_signal_state (handle, TRUE, TRUE);
351 } else {
352 event_handle->set_count++;
353 _wapi_handle_set_signal_state (handle, TRUE, FALSE);
356 thr_ret = _wapi_handle_unlock_handle (handle);
357 g_assert (thr_ret == 0);
359 pthread_cleanup_pop (0);
361 return(TRUE);