[io-layer] Remove empty function _wapi_shm_semaphores_remove
[mono.git] / mono / io-layer / events.c
1 /*
2  * events.c:  Event handles
3  *
4  * Author:
5  *      Dick Porter (dick@ximian.com)
6  *
7  * (C) 2002 Ximian, Inc.
8  */
9
10 #include <config.h>
11 #include <glib.h>
12 #include <pthread.h>
13 #include <string.h>
14
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/event-private.h>
19 #include <mono/io-layer/io-trace.h>
20 #include <mono/utils/mono-once.h>
21 #include <mono/utils/mono-logger-internals.h>
22
23 static void event_signal(gpointer handle);
24 static gboolean event_own (gpointer handle);
25
26 static void namedevent_signal (gpointer handle);
27 static gboolean namedevent_own (gpointer handle);
28
29 struct _WapiHandleOps _wapi_event_ops = {
30         NULL,                   /* close */
31         event_signal,           /* signal */
32         event_own,              /* own */
33         NULL,                   /* is_owned */
34         NULL,                   /* special_wait */
35         NULL                    /* prewait */
36 };
37
38 struct _WapiHandleOps _wapi_namedevent_ops = {
39         NULL,                   /* close */
40         namedevent_signal,      /* signal */
41         namedevent_own,         /* own */
42         NULL,                   /* is_owned */
43 };
44
45 void _wapi_event_details (gpointer handle_info)
46 {
47         struct _WapiHandle_event *event = (struct _WapiHandle_event *)handle_info;
48         
49         g_print ("manual: %s", event->manual?"TRUE":"FALSE");
50 }
51
52 static mono_once_t event_ops_once=MONO_ONCE_INIT;
53
54 static void event_ops_init (void)
55 {
56         _wapi_handle_register_capabilities (WAPI_HANDLE_EVENT,
57                 (WapiHandleCapability)(WAPI_HANDLE_CAP_WAIT | WAPI_HANDLE_CAP_SIGNAL));
58         _wapi_handle_register_capabilities (WAPI_HANDLE_NAMEDEVENT,
59                 (WapiHandleCapability)(WAPI_HANDLE_CAP_WAIT | WAPI_HANDLE_CAP_SIGNAL));
60 }
61
62 static const char* event_handle_type_to_string (WapiHandleType type)
63 {
64         switch (type) {
65         case WAPI_HANDLE_EVENT: return "event";
66         case WAPI_HANDLE_NAMEDEVENT: return "named event";
67         default:
68                 g_assert_not_reached ();
69         }
70 }
71
72 static gboolean event_handle_own (gpointer handle, WapiHandleType type)
73 {
74         struct _WapiHandle_event *event_handle;
75         gboolean ok;
76
77         ok = _wapi_lookup_handle (handle, type, (gpointer *)&event_handle);
78         if (!ok) {
79                 g_warning ("%s: error looking up %s handle %p",
80                         __func__, event_handle_type_to_string (type), handle);
81                 return FALSE;
82         }
83
84         MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: owning %s handle %p",
85                 __func__, event_handle_type_to_string (type), handle);
86
87         if (!event_handle->manual) {
88                 g_assert (event_handle->set_count > 0);
89                 event_handle->set_count --;
90
91                 if (event_handle->set_count == 0)
92                         _wapi_handle_set_signal_state (handle, FALSE, FALSE);
93         }
94
95         return TRUE;
96 }
97
98 static void event_signal(gpointer handle)
99 {
100         SetEvent(handle);
101 }
102
103 static gboolean event_own (gpointer handle)
104 {
105         return event_handle_own (handle, WAPI_HANDLE_EVENT);
106 }
107
108 static void namedevent_signal (gpointer handle)
109 {
110         SetEvent (handle);
111 }
112
113 /* NB, always called with the shared handle lock held */
114 static gboolean namedevent_own (gpointer handle)
115 {
116         return event_handle_own (handle, WAPI_HANDLE_NAMEDEVENT);
117 }
118
119 static gpointer event_handle_create (struct _WapiHandle_event *event_handle, WapiHandleType type, gboolean manual, gboolean initial)
120 {
121         gpointer handle;
122         int thr_ret;
123
124         event_handle->manual = manual;
125         event_handle->set_count = (initial && !manual) ? 1 : 0;
126
127         handle = _wapi_handle_new (type, event_handle);
128         if (handle == _WAPI_HANDLE_INVALID) {
129                 g_warning ("%s: error creating %s handle",
130                         __func__, event_handle_type_to_string (type));
131                 SetLastError (ERROR_GEN_FAILURE);
132                 return NULL;
133         }
134
135         thr_ret = _wapi_handle_lock_handle (handle);
136         g_assert (thr_ret == 0);
137
138         if (initial)
139                 _wapi_handle_set_signal_state (handle, TRUE, FALSE);
140
141         thr_ret = _wapi_handle_unlock_handle (handle);
142         g_assert (thr_ret == 0);
143
144         MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: created %s handle %p",
145                 __func__, event_handle_type_to_string (type), handle);
146
147         return handle;
148 }
149
150 static gpointer event_create (gboolean manual, gboolean initial)
151 {
152         struct _WapiHandle_event event_handle;
153         MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: creating %s handle",
154                 __func__, event_handle_type_to_string (WAPI_HANDLE_EVENT));
155         return event_handle_create (&event_handle, WAPI_HANDLE_EVENT, manual, initial);
156 }
157
158 static gpointer namedevent_create (gboolean manual, gboolean initial, const gunichar2 *name G_GNUC_UNUSED)
159 {
160         gpointer handle;
161         gchar *utf8_name;
162         int thr_ret;
163
164         MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: creating %s handle",
165                 __func__, event_handle_type_to_string (WAPI_HANDLE_NAMEDEVENT));
166
167         /* w32 seems to guarantee that opening named objects can't race each other */
168         thr_ret = _wapi_namespace_lock ();
169         g_assert (thr_ret == 0);
170
171         utf8_name = g_utf16_to_utf8 (name, -1, NULL, NULL, NULL);
172
173         handle = _wapi_search_handle_namespace (WAPI_HANDLE_NAMEDEVENT, utf8_name);
174         if (handle == _WAPI_HANDLE_INVALID) {
175                 /* The name has already been used for a different object. */
176                 handle = NULL;
177                 SetLastError (ERROR_INVALID_HANDLE);
178         } else if (handle) {
179                 /* Not an error, but this is how the caller is informed that the event wasn't freshly created */
180                 SetLastError (ERROR_ALREADY_EXISTS);
181
182                 /* this is used as creating a new handle */
183                 _wapi_handle_ref (handle);
184         } else {
185                 /* A new named event */
186                 struct _WapiHandle_namedevent namedevent_handle;
187
188                 strncpy (&namedevent_handle.sharedns.name [0], utf8_name, MAX_PATH);
189                 namedevent_handle.sharedns.name [MAX_PATH] = '\0';
190
191                 handle = event_handle_create ((struct _WapiHandle_event*) &namedevent_handle, WAPI_HANDLE_NAMEDEVENT, manual, initial);
192         }
193
194         g_free (utf8_name);
195
196         thr_ret = _wapi_namespace_unlock (NULL);
197         g_assert (thr_ret == 0);
198
199         return handle;
200 }
201
202
203 /**
204  * CreateEvent:
205  * @security: Ignored for now.
206  * @manual: Specifies whether the new event handle has manual or auto
207  * reset behaviour.
208  * @initial: Specifies whether the new event handle is initially
209  * signalled or not.
210  * @name:Pointer to a string specifying the name of this name, or
211  * %NULL.  Currently ignored.
212  *
213  * Creates a new event handle.
214  *
215  * An event handle is signalled with SetEvent().  If the new handle is
216  * a manual reset event handle, it remains signalled until it is reset
217  * with ResetEvent().  An auto reset event remains signalled until a
218  * single thread has waited for it, at which time the event handle is
219  * automatically reset to unsignalled.
220  *
221  * Return value: A new handle, or %NULL on error.
222  */
223 gpointer CreateEvent(WapiSecurityAttributes *security G_GNUC_UNUSED,
224                      gboolean manual, gboolean initial,
225                      const gunichar2 *name G_GNUC_UNUSED)
226 {
227         mono_once (&event_ops_once, event_ops_init);
228
229         /* Need to blow away any old errors here, because code tests
230          * for ERROR_ALREADY_EXISTS on success (!) to see if an event
231          * was freshly created
232          */
233         SetLastError (ERROR_SUCCESS);
234
235         return name ? namedevent_create (manual, initial, name) : event_create (manual, initial);
236 }
237
238 /**
239  * PulseEvent:
240  * @handle: The event handle.
241  *
242  * Sets the event handle @handle to the signalled state, and then
243  * resets it to unsignalled after informing any waiting threads.
244  *
245  * If @handle is a manual reset event, all waiting threads that can be
246  * released immediately are released.  @handle is then reset.  If
247  * @handle is an auto reset event, one waiting thread is released even
248  * if multiple threads are waiting.
249  *
250  * Return value: %TRUE on success, %FALSE otherwise.  (Currently only
251  * ever returns %TRUE).
252  */
253 gboolean PulseEvent(gpointer handle)
254 {
255         WapiHandleType type;
256         struct _WapiHandle_event *event_handle;
257         int thr_ret;
258
259         if (handle == NULL) {
260                 SetLastError (ERROR_INVALID_HANDLE);
261                 return(FALSE);
262         }
263
264         switch (type = _wapi_handle_type (handle)) {
265         case WAPI_HANDLE_EVENT:
266         case WAPI_HANDLE_NAMEDEVENT:
267                 break;
268         default:
269                 SetLastError (ERROR_INVALID_HANDLE);
270                 return FALSE;
271         }
272
273         if (!_wapi_lookup_handle (handle, type, (gpointer *)&event_handle)) {
274                 g_warning ("%s: error looking up %s handle %p",
275                         __func__, event_handle_type_to_string (type), handle);
276                 return FALSE;
277         }
278
279         MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: pulsing %s handle %p",
280                 __func__, event_handle_type_to_string (type), handle);
281
282         thr_ret = _wapi_handle_lock_handle (handle);
283         g_assert (thr_ret == 0);
284
285         if (!event_handle->manual) {
286                 event_handle->set_count = 1;
287                 _wapi_handle_set_signal_state (handle, TRUE, FALSE);
288         } else {
289                 _wapi_handle_set_signal_state (handle, TRUE, TRUE);
290
291                 thr_ret = _wapi_handle_unlock_handle (handle);
292                 g_assert (thr_ret == 0);
293
294                 /* For a manual-reset event, we're about to try and get the handle
295                  * lock again, so give other threads a chance */
296                 sched_yield ();
297
298                 /* Reset the handle signal state */
299
300                 /* I'm not sure whether or not we need a barrier here to make sure
301                  * that all threads waiting on the event have proceeded. Currently
302                  * we rely on broadcasting a condition. */
303
304                 thr_ret = _wapi_handle_lock_handle (handle);
305                 g_assert (thr_ret == 0);
306
307                 _wapi_handle_set_signal_state (handle, FALSE, FALSE);
308         }
309
310         thr_ret = _wapi_handle_unlock_handle (handle);
311         g_assert (thr_ret == 0);
312
313         return TRUE;
314 }
315
316 /**
317  * ResetEvent:
318  * @handle: The event handle.
319  *
320  * Resets the event handle @handle to the unsignalled state.
321  *
322  * Return value: %TRUE on success, %FALSE otherwise.  (Currently only
323  * ever returns %TRUE).
324  */
325 gboolean ResetEvent(gpointer handle)
326 {
327         WapiHandleType type;
328         struct _WapiHandle_event *event_handle;
329         int thr_ret;
330
331         SetLastError (ERROR_SUCCESS);
332         
333         if (handle == NULL) {
334                 SetLastError (ERROR_INVALID_HANDLE);
335                 return(FALSE);
336         }
337         
338         switch (type = _wapi_handle_type (handle)) {
339         case WAPI_HANDLE_EVENT:
340         case WAPI_HANDLE_NAMEDEVENT:
341                 break;
342         default:
343                 SetLastError (ERROR_INVALID_HANDLE);
344                 return FALSE;
345         }
346
347         if (!_wapi_lookup_handle (handle, type, (gpointer *)&event_handle)) {
348                 g_warning ("%s: error looking up %s handle %p",
349                         __func__, event_handle_type_to_string (type), handle);
350                 return FALSE;
351         }
352
353         MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: resetting %s handle %p",
354                 __func__, event_handle_type_to_string (type), handle);
355
356         thr_ret = _wapi_handle_lock_handle (handle);
357         g_assert (thr_ret == 0);
358
359         if (!_wapi_handle_issignalled (handle)) {
360                 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: no need to reset %s handle %p",
361                         __func__, event_handle_type_to_string (type), handle);
362         } else {
363                 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: obtained write lock on %s handle %p",
364                         __func__, event_handle_type_to_string (type), handle);
365
366                 _wapi_handle_set_signal_state (handle, FALSE, FALSE);
367         }
368
369         event_handle->set_count = 0;
370
371         thr_ret = _wapi_handle_unlock_handle (handle);
372         g_assert (thr_ret == 0);
373
374         return TRUE;
375 }
376
377 /**
378  * SetEvent:
379  * @handle: The event handle
380  *
381  * Sets the event handle @handle to the signalled state.
382  *
383  * If @handle is a manual reset event, it remains signalled until it
384  * is reset with ResetEvent().  An auto reset event remains signalled
385  * until a single thread has waited for it, at which time @handle is
386  * automatically reset to unsignalled.
387  *
388  * Return value: %TRUE on success, %FALSE otherwise.  (Currently only
389  * ever returns %TRUE).
390  */
391 gboolean SetEvent(gpointer handle)
392 {
393         WapiHandleType type;
394         struct _WapiHandle_event *event_handle;
395         int thr_ret;
396         
397         if (handle == NULL) {
398                 SetLastError (ERROR_INVALID_HANDLE);
399                 return(FALSE);
400         }
401         
402         switch (type = _wapi_handle_type (handle)) {
403         case WAPI_HANDLE_EVENT:
404         case WAPI_HANDLE_NAMEDEVENT:
405                 break;
406         default:
407                 SetLastError (ERROR_INVALID_HANDLE);
408                 return FALSE;
409         }
410
411         if (!_wapi_lookup_handle (handle, type, (gpointer *)&event_handle)) {
412                 g_warning ("%s: error looking up %s handle %p",
413                         __func__, event_handle_type_to_string (type), handle);
414                 return FALSE;
415         }
416
417         MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: setting %s handle %p",
418                 __func__, event_handle_type_to_string (type), handle);
419
420         thr_ret = _wapi_handle_lock_handle (handle);
421         g_assert (thr_ret == 0);
422
423         if (!event_handle->manual) {
424                 event_handle->set_count = 1;
425                 _wapi_handle_set_signal_state (handle, TRUE, FALSE);
426         } else {
427                 _wapi_handle_set_signal_state (handle, TRUE, TRUE);
428         }
429
430         thr_ret = _wapi_handle_unlock_handle (handle);
431         g_assert (thr_ret == 0);
432
433         return TRUE;
434 }
435
436 gpointer OpenEvent (guint32 access G_GNUC_UNUSED, gboolean inherit G_GNUC_UNUSED, const gunichar2 *name)
437 {
438         gpointer handle;
439         gchar *utf8_name;
440         int thr_ret;
441         
442         mono_once (&event_ops_once, event_ops_init);
443
444         /* w32 seems to guarantee that opening named objects can't
445          * race each other
446          */
447         thr_ret = _wapi_namespace_lock ();
448         g_assert (thr_ret == 0);
449
450         utf8_name = g_utf16_to_utf8 (name, -1, NULL, NULL, NULL);
451         
452         MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Opening named event [%s]", __func__, utf8_name);
453         
454         handle = _wapi_search_handle_namespace (WAPI_HANDLE_NAMEDEVENT,
455                                                 utf8_name);
456         if (handle == _WAPI_HANDLE_INVALID) {
457                 /* The name has already been used for a different
458                  * object.
459                  */
460                 SetLastError (ERROR_INVALID_HANDLE);
461                 goto cleanup;
462         } else if (!handle) {
463                 /* This name doesn't exist */
464                 SetLastError (ERROR_FILE_NOT_FOUND);    /* yes, really */
465                 goto cleanup;
466         }
467
468         MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: returning named event handle %p", __func__, handle);
469
470 cleanup:
471         g_free (utf8_name);
472
473         _wapi_namespace_unlock (NULL);
474         
475         return handle;
476
477 }