Merge pull request #5714 from alexischr/update_bockbuild
[mono.git] / mono / metadata / w32event-unix.c
1 /**
2  * \file
3  * Runtime support for managed Event on Unix
4  *
5  * Author:
6  *      Ludovic Henry (luhenry@microsoft.com)
7  *
8  * Licensed under the MIT license. See LICENSE file in the project root for full license information.
9  */
10
11 #include "w32event.h"
12
13 #include "w32error.h"
14 #include "w32handle-namespace.h"
15 #include "mono/utils/mono-error-internals.h"
16 #include "mono/utils/mono-logger-internals.h"
17 #include "mono/metadata/handle.h"
18 #include "mono/metadata/object-internals.h"
19 #include "mono/metadata/w32handle.h"
20
21 #define MAX_PATH 260
22
23 static gpointer
24 mono_w32event_create_full (MonoBoolean manual, MonoBoolean initial, const gchar *name, gint32 *err);
25
26 static gpointer
27 mono_w32event_open (const gchar *utf8_name, gint32 rights G_GNUC_UNUSED, gint32 *error);
28
29 typedef struct {
30         gboolean manual;
31         guint32 set_count;
32 } MonoW32HandleEvent;
33
34 struct MonoW32HandleNamedEvent {
35         MonoW32HandleEvent e;
36         MonoW32HandleNamespace sharedns;
37 };
38
39 static void event_handle_signal (gpointer handle, MonoW32HandleType type, MonoW32HandleEvent *event_handle)
40 {
41         mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: signalling %s handle %p",
42                 __func__, mono_w32handle_get_typename (type), handle);
43
44         if (!event_handle->manual) {
45                 event_handle->set_count = 1;
46                 mono_w32handle_set_signal_state (handle, TRUE, FALSE);
47         } else {
48                 mono_w32handle_set_signal_state (handle, TRUE, TRUE);
49         }
50 }
51
52 static gboolean event_handle_own (gpointer handle, MonoW32HandleType type, gboolean *abandoned)
53 {
54         MonoW32HandleEvent *event_handle;
55         gboolean ok;
56
57         *abandoned = FALSE;
58
59         ok = mono_w32handle_lookup (handle, type, (gpointer *)&event_handle);
60         if (!ok) {
61                 g_warning ("%s: error looking up %s handle %p",
62                         __func__, mono_w32handle_get_typename (type), handle);
63                 return FALSE;
64         }
65
66         mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: owning %s handle %p",
67                 __func__, mono_w32handle_get_typename (type), handle);
68
69         if (!event_handle->manual) {
70                 g_assert (event_handle->set_count > 0);
71                 event_handle->set_count --;
72
73                 if (event_handle->set_count == 0)
74                         mono_w32handle_set_signal_state (handle, FALSE, FALSE);
75         }
76
77         return TRUE;
78 }
79
80 static void event_signal(gpointer handle, gpointer handle_specific)
81 {
82         event_handle_signal (handle, MONO_W32HANDLE_EVENT, (MonoW32HandleEvent*) handle_specific);
83 }
84
85 static gboolean event_own (gpointer handle, gboolean *abandoned)
86 {
87         return event_handle_own (handle, MONO_W32HANDLE_EVENT, abandoned);
88 }
89
90 static void namedevent_signal (gpointer handle, gpointer handle_specific)
91 {
92         event_handle_signal (handle, MONO_W32HANDLE_NAMEDEVENT, (MonoW32HandleEvent*) handle_specific);
93 }
94
95 /* NB, always called with the shared handle lock held */
96 static gboolean namedevent_own (gpointer handle, gboolean *abandoned)
97 {
98         return event_handle_own (handle, MONO_W32HANDLE_NAMEDEVENT, abandoned);
99 }
100
101 static void event_details (gpointer data)
102 {
103         MonoW32HandleEvent *event = (MonoW32HandleEvent *)data;
104         g_print ("manual: %s, set_count: %d",
105                 event->manual ? "TRUE" : "FALSE", event->set_count);
106 }
107
108 static void namedevent_details (gpointer data)
109 {
110         MonoW32HandleNamedEvent *namedevent = (MonoW32HandleNamedEvent *)data;
111         g_print ("manual: %s, set_count: %d, name: \"%s\"",
112                 namedevent->e.manual ? "TRUE" : "FALSE", namedevent->e.set_count, namedevent->sharedns.name);
113 }
114
115 static const gchar* event_typename (void)
116 {
117         return "Event";
118 }
119
120 static gsize event_typesize (void)
121 {
122         return sizeof (MonoW32HandleEvent);
123 }
124
125 static const gchar* namedevent_typename (void)
126 {
127         return "N.Event";
128 }
129
130 static gsize namedevent_typesize (void)
131 {
132         return sizeof (MonoW32HandleNamedEvent);
133 }
134
135 void
136 mono_w32event_init (void)
137 {
138         static MonoW32HandleOps event_ops = {
139                 NULL,                   /* close */
140                 event_signal,           /* signal */
141                 event_own,              /* own */
142                 NULL,                   /* is_owned */
143                 NULL,                   /* special_wait */
144                 NULL,                   /* prewait */
145                 event_details,  /* details */
146                 event_typename, /* typename */
147                 event_typesize, /* typesize */
148         };
149
150         static MonoW32HandleOps namedevent_ops = {
151                 NULL,                   /* close */
152                 namedevent_signal,      /* signal */
153                 namedevent_own,         /* own */
154                 NULL,                   /* is_owned */
155                 NULL,                   /* special_wait */
156                 NULL,                   /* prewait */
157                 namedevent_details,     /* details */
158                 namedevent_typename, /* typename */
159                 namedevent_typesize, /* typesize */
160         };
161
162         mono_w32handle_register_ops (MONO_W32HANDLE_EVENT,      &event_ops);
163         mono_w32handle_register_ops (MONO_W32HANDLE_NAMEDEVENT, &namedevent_ops);
164
165         mono_w32handle_register_capabilities (MONO_W32HANDLE_EVENT,
166                 (MonoW32HandleCapability)(MONO_W32HANDLE_CAP_WAIT | MONO_W32HANDLE_CAP_SIGNAL));
167         mono_w32handle_register_capabilities (MONO_W32HANDLE_NAMEDEVENT,
168                 (MonoW32HandleCapability)(MONO_W32HANDLE_CAP_WAIT | MONO_W32HANDLE_CAP_SIGNAL));
169 }
170
171 gpointer
172 mono_w32event_create (gboolean manual, gboolean initial)
173 {
174         gpointer handle;
175         gint32 error;
176
177         handle = mono_w32event_create_full (manual, initial, NULL, &error);
178         if (error != ERROR_SUCCESS)
179                 g_assert (!handle);
180
181         return handle;
182 }
183
184 gboolean
185 mono_w32event_close (gpointer handle)
186 {
187         return mono_w32handle_close (handle);
188 }
189
190 void
191 mono_w32event_set (gpointer handle)
192 {
193         ves_icall_System_Threading_Events_SetEvent_internal (handle);
194 }
195
196 void
197 mono_w32event_reset (gpointer handle)
198 {
199         ves_icall_System_Threading_Events_ResetEvent_internal (handle);
200 }
201
202 static gpointer event_handle_create (MonoW32HandleEvent *event_handle, MonoW32HandleType type, gboolean manual, gboolean initial)
203 {
204         gpointer handle;
205
206         event_handle->manual = manual;
207         event_handle->set_count = (initial && !manual) ? 1 : 0;
208
209         handle = mono_w32handle_new (type, event_handle);
210         if (handle == INVALID_HANDLE_VALUE) {
211                 g_warning ("%s: error creating %s handle",
212                         __func__, mono_w32handle_get_typename (type));
213                 mono_w32error_set_last (ERROR_GEN_FAILURE);
214                 return NULL;
215         }
216
217         mono_w32handle_lock_handle (handle);
218
219         if (initial)
220                 mono_w32handle_set_signal_state (handle, TRUE, FALSE);
221
222         mono_w32handle_unlock_handle (handle);
223
224         mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: created %s handle %p",
225                 __func__, mono_w32handle_get_typename (type), handle);
226
227         return handle;
228 }
229
230 static gpointer event_create (gboolean manual, gboolean initial)
231 {
232         MonoW32HandleEvent event_handle;
233         mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: creating %s handle",
234                 __func__, mono_w32handle_get_typename (MONO_W32HANDLE_EVENT));
235         return event_handle_create (&event_handle, MONO_W32HANDLE_EVENT, manual, initial);
236 }
237
238 static gpointer namedevent_create (gboolean manual, gboolean initial, const gchar *utf8_name G_GNUC_UNUSED)
239 {
240         gpointer handle;
241
242         mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: creating %s handle",
243                 __func__, mono_w32handle_get_typename (MONO_W32HANDLE_NAMEDEVENT));
244
245         /* w32 seems to guarantee that opening named objects can't race each other */
246         mono_w32handle_namespace_lock ();
247
248         glong utf8_len = strlen (utf8_name);
249
250         handle = mono_w32handle_namespace_search_handle (MONO_W32HANDLE_NAMEDEVENT, utf8_name);
251         if (handle == INVALID_HANDLE_VALUE) {
252                 /* The name has already been used for a different object. */
253                 handle = NULL;
254                 mono_w32error_set_last (ERROR_INVALID_HANDLE);
255         } else if (handle) {
256                 /* Not an error, but this is how the caller is informed that the event wasn't freshly created */
257                 mono_w32error_set_last (ERROR_ALREADY_EXISTS);
258
259                 /* mono_w32handle_namespace_search_handle already adds a ref to the handle */
260         } else {
261                 /* A new named event */
262                 MonoW32HandleNamedEvent namedevent_handle;
263
264                 size_t len = utf8_len < MAX_PATH ? utf8_len : MAX_PATH;
265                 memcpy (&namedevent_handle.sharedns.name [0], utf8_name, len);
266                 namedevent_handle.sharedns.name [len] = '\0';
267
268                 handle = event_handle_create ((MonoW32HandleEvent*) &namedevent_handle, MONO_W32HANDLE_NAMEDEVENT, manual, initial);
269         }
270
271         mono_w32handle_namespace_unlock ();
272
273         return handle;
274 }
275
276 gpointer
277 mono_w32event_create_full (MonoBoolean manual, MonoBoolean initial, const gchar *name, gint32 *error)
278 {
279         gpointer event;
280
281         /* Need to blow away any old errors here, because code tests
282          * for ERROR_ALREADY_EXISTS on success (!) to see if an event
283          * was freshly created */
284         mono_w32error_set_last (ERROR_SUCCESS);
285
286         event = name ? namedevent_create (manual, initial, name) : event_create (manual, initial);
287
288         *error = mono_w32error_get_last ();
289
290         return event;
291 }
292
293 gpointer
294 ves_icall_System_Threading_Events_CreateEvent_internal (MonoBoolean manual, MonoBoolean initial, MonoStringHandle name, gint32 *err, MonoError *error)
295 {
296         error_init (error);
297         gchar *utf8_name = mono_string_handle_to_utf8 (name, error);
298         return_val_if_nok (error, NULL);
299         gpointer result = mono_w32event_create_full (manual, initial, utf8_name, err);
300         g_free (utf8_name);
301         return result;
302 }
303
304 gboolean
305 ves_icall_System_Threading_Events_SetEvent_internal (gpointer handle)
306 {
307         MonoW32HandleType type;
308         MonoW32HandleEvent *event_handle;
309
310         if (handle == NULL) {
311                 mono_w32error_set_last (ERROR_INVALID_HANDLE);
312                 return(FALSE);
313         }
314
315         switch (type = mono_w32handle_get_type (handle)) {
316         case MONO_W32HANDLE_EVENT:
317         case MONO_W32HANDLE_NAMEDEVENT:
318                 break;
319         default:
320                 mono_w32error_set_last (ERROR_INVALID_HANDLE);
321                 return FALSE;
322         }
323
324         if (!mono_w32handle_lookup (handle, type, (gpointer *)&event_handle)) {
325                 g_warning ("%s: error looking up %s handle %p",
326                         __func__, mono_w32handle_get_typename (type), handle);
327                 return FALSE;
328         }
329
330         mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: setting %s handle %p",
331                 __func__, mono_w32handle_get_typename (type), handle);
332
333         mono_w32handle_lock_handle (handle);
334
335         if (!event_handle->manual) {
336                 event_handle->set_count = 1;
337                 mono_w32handle_set_signal_state (handle, TRUE, FALSE);
338         } else {
339                 mono_w32handle_set_signal_state (handle, TRUE, TRUE);
340         }
341
342         mono_w32handle_unlock_handle (handle);
343
344         return TRUE;
345 }
346
347 gboolean
348 ves_icall_System_Threading_Events_ResetEvent_internal (gpointer handle)
349 {
350         MonoW32HandleType type;
351         MonoW32HandleEvent *event_handle;
352
353         mono_w32error_set_last (ERROR_SUCCESS);
354
355         if (handle == NULL) {
356                 mono_w32error_set_last (ERROR_INVALID_HANDLE);
357                 return(FALSE);
358         }
359
360         switch (type = mono_w32handle_get_type (handle)) {
361         case MONO_W32HANDLE_EVENT:
362         case MONO_W32HANDLE_NAMEDEVENT:
363                 break;
364         default:
365                 mono_w32error_set_last (ERROR_INVALID_HANDLE);
366                 return FALSE;
367         }
368
369         if (!mono_w32handle_lookup (handle, type, (gpointer *)&event_handle)) {
370                 g_warning ("%s: error looking up %s handle %p",
371                         __func__, mono_w32handle_get_typename (type), handle);
372                 return FALSE;
373         }
374
375         mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: resetting %s handle %p",
376                 __func__, mono_w32handle_get_typename (type), handle);
377
378         mono_w32handle_lock_handle (handle);
379
380         if (!mono_w32handle_issignalled (handle)) {
381                 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: no need to reset %s handle %p",
382                         __func__, mono_w32handle_get_typename (type), handle);
383         } else {
384                 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: obtained write lock on %s handle %p",
385                         __func__, mono_w32handle_get_typename (type), handle);
386
387                 mono_w32handle_set_signal_state (handle, FALSE, FALSE);
388         }
389
390         event_handle->set_count = 0;
391
392         mono_w32handle_unlock_handle (handle);
393
394         return TRUE;
395 }
396
397 void
398 ves_icall_System_Threading_Events_CloseEvent_internal (gpointer handle)
399 {
400         mono_w32handle_close (handle);
401 }
402
403 gpointer
404 ves_icall_System_Threading_Events_OpenEvent_internal (MonoStringHandle name, gint32 rights G_GNUC_UNUSED, gint32 *err, MonoError *error)
405 {
406         error_init (error);
407         gchar *utf8_name = mono_string_handle_to_utf8 (name, error);
408         return_val_if_nok (error, NULL);
409         gpointer handle = mono_w32event_open (utf8_name, rights, err);
410         g_free (utf8_name);
411         return handle;
412 }
413
414 gpointer
415 mono_w32event_open (const gchar *utf8_name, gint32 rights G_GNUC_UNUSED, gint32 *error)
416 {
417         gpointer handle;
418         *error = ERROR_SUCCESS;
419
420         /* w32 seems to guarantee that opening named objects can't race each other */
421         mono_w32handle_namespace_lock ();
422
423         mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Opening named event [%s]", __func__, utf8_name);
424
425         handle = mono_w32handle_namespace_search_handle (MONO_W32HANDLE_NAMEDEVENT, utf8_name);
426         if (handle == INVALID_HANDLE_VALUE) {
427                 /* The name has already been used for a different object. */
428                 *error = ERROR_INVALID_HANDLE;
429                 goto cleanup;
430         } else if (!handle) {
431                 /* This name doesn't exist */
432                 *error = ERROR_FILE_NOT_FOUND;
433                 goto cleanup;
434         }
435
436         mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: returning named event handle %p", __func__, handle);
437
438 cleanup:
439         mono_w32handle_namespace_unlock ();
440
441         return handle;
442 }
443
444 MonoW32HandleNamespace*
445 mono_w32event_get_namespace (MonoW32HandleNamedEvent *event)
446 {
447         return &event->sharedns;
448 }