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