3 * Runtime support for managed Event on Unix
6 * Ludovic Henry (luhenry@microsoft.com)
8 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
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"
24 mono_w32event_create_full (MonoBoolean manual, MonoBoolean initial, const gchar *name, gint32 *err);
27 mono_w32event_open (const gchar *utf8_name, gint32 rights G_GNUC_UNUSED, gint32 *error);
34 struct MonoW32HandleNamedEvent {
36 MonoW32HandleNamespace sharedns;
39 static void event_handle_signal (gpointer handle, MonoW32HandleType type, MonoW32HandleEvent *event_handle)
41 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: signalling %s handle %p",
42 __func__, mono_w32handle_get_typename (type), handle);
44 if (!event_handle->manual) {
45 event_handle->set_count = 1;
46 mono_w32handle_set_signal_state (handle, TRUE, FALSE);
48 mono_w32handle_set_signal_state (handle, TRUE, TRUE);
52 static gboolean event_handle_own (gpointer handle, MonoW32HandleType type, gboolean *abandoned)
54 MonoW32HandleEvent *event_handle;
59 ok = mono_w32handle_lookup (handle, type, (gpointer *)&event_handle);
61 g_warning ("%s: error looking up %s handle %p",
62 __func__, mono_w32handle_get_typename (type), handle);
66 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: owning %s handle %p",
67 __func__, mono_w32handle_get_typename (type), handle);
69 if (!event_handle->manual) {
70 g_assert (event_handle->set_count > 0);
71 event_handle->set_count --;
73 if (event_handle->set_count == 0)
74 mono_w32handle_set_signal_state (handle, FALSE, FALSE);
80 static void event_signal(gpointer handle, gpointer handle_specific)
82 event_handle_signal (handle, MONO_W32HANDLE_EVENT, (MonoW32HandleEvent*) handle_specific);
85 static gboolean event_own (gpointer handle, gboolean *abandoned)
87 return event_handle_own (handle, MONO_W32HANDLE_EVENT, abandoned);
90 static void namedevent_signal (gpointer handle, gpointer handle_specific)
92 event_handle_signal (handle, MONO_W32HANDLE_NAMEDEVENT, (MonoW32HandleEvent*) handle_specific);
95 /* NB, always called with the shared handle lock held */
96 static gboolean namedevent_own (gpointer handle, gboolean *abandoned)
98 return event_handle_own (handle, MONO_W32HANDLE_NAMEDEVENT, abandoned);
101 static void event_details (gpointer data)
103 MonoW32HandleEvent *event = (MonoW32HandleEvent *)data;
104 g_print ("manual: %s, set_count: %d",
105 event->manual ? "TRUE" : "FALSE", event->set_count);
108 static void namedevent_details (gpointer data)
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);
115 static const gchar* event_typename (void)
120 static gsize event_typesize (void)
122 return sizeof (MonoW32HandleEvent);
125 static const gchar* namedevent_typename (void)
130 static gsize namedevent_typesize (void)
132 return sizeof (MonoW32HandleNamedEvent);
136 mono_w32event_init (void)
138 static MonoW32HandleOps event_ops = {
140 event_signal, /* signal */
143 NULL, /* special_wait */
145 event_details, /* details */
146 event_typename, /* typename */
147 event_typesize, /* typesize */
150 static MonoW32HandleOps namedevent_ops = {
152 namedevent_signal, /* signal */
153 namedevent_own, /* own */
155 NULL, /* special_wait */
157 namedevent_details, /* details */
158 namedevent_typename, /* typename */
159 namedevent_typesize, /* typesize */
162 mono_w32handle_register_ops (MONO_W32HANDLE_EVENT, &event_ops);
163 mono_w32handle_register_ops (MONO_W32HANDLE_NAMEDEVENT, &namedevent_ops);
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));
172 mono_w32event_create (gboolean manual, gboolean initial)
177 handle = mono_w32event_create_full (manual, initial, NULL, &error);
178 if (error != ERROR_SUCCESS)
185 mono_w32event_close (gpointer handle)
187 return mono_w32handle_close (handle);
191 mono_w32event_set (gpointer handle)
193 ves_icall_System_Threading_Events_SetEvent_internal (handle);
197 mono_w32event_reset (gpointer handle)
199 ves_icall_System_Threading_Events_ResetEvent_internal (handle);
202 static gpointer event_handle_create (MonoW32HandleEvent *event_handle, MonoW32HandleType type, gboolean manual, gboolean initial)
206 event_handle->manual = manual;
207 event_handle->set_count = (initial && !manual) ? 1 : 0;
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);
217 mono_w32handle_lock_handle (handle);
220 mono_w32handle_set_signal_state (handle, TRUE, FALSE);
222 mono_w32handle_unlock_handle (handle);
224 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: created %s handle %p",
225 __func__, mono_w32handle_get_typename (type), handle);
230 static gpointer event_create (gboolean manual, gboolean initial)
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);
238 static gpointer namedevent_create (gboolean manual, gboolean initial, const gchar *utf8_name G_GNUC_UNUSED)
242 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: creating %s handle",
243 __func__, mono_w32handle_get_typename (MONO_W32HANDLE_NAMEDEVENT));
245 /* w32 seems to guarantee that opening named objects can't race each other */
246 mono_w32handle_namespace_lock ();
248 glong utf8_len = strlen (utf8_name);
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. */
254 mono_w32error_set_last (ERROR_INVALID_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);
259 /* mono_w32handle_namespace_search_handle already adds a ref to the handle */
261 /* A new named event */
262 MonoW32HandleNamedEvent namedevent_handle;
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';
268 handle = event_handle_create ((MonoW32HandleEvent*) &namedevent_handle, MONO_W32HANDLE_NAMEDEVENT, manual, initial);
271 mono_w32handle_namespace_unlock ();
277 mono_w32event_create_full (MonoBoolean manual, MonoBoolean initial, const gchar *name, gint32 *error)
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);
286 event = name ? namedevent_create (manual, initial, name) : event_create (manual, initial);
288 *error = mono_w32error_get_last ();
294 ves_icall_System_Threading_Events_CreateEvent_internal (MonoBoolean manual, MonoBoolean initial, MonoStringHandle name, gint32 *err, MonoError *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);
305 ves_icall_System_Threading_Events_SetEvent_internal (gpointer handle)
307 MonoW32HandleType type;
308 MonoW32HandleEvent *event_handle;
310 if (handle == NULL) {
311 mono_w32error_set_last (ERROR_INVALID_HANDLE);
315 switch (type = mono_w32handle_get_type (handle)) {
316 case MONO_W32HANDLE_EVENT:
317 case MONO_W32HANDLE_NAMEDEVENT:
320 mono_w32error_set_last (ERROR_INVALID_HANDLE);
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);
330 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: setting %s handle %p",
331 __func__, mono_w32handle_get_typename (type), handle);
333 mono_w32handle_lock_handle (handle);
335 if (!event_handle->manual) {
336 event_handle->set_count = 1;
337 mono_w32handle_set_signal_state (handle, TRUE, FALSE);
339 mono_w32handle_set_signal_state (handle, TRUE, TRUE);
342 mono_w32handle_unlock_handle (handle);
348 ves_icall_System_Threading_Events_ResetEvent_internal (gpointer handle)
350 MonoW32HandleType type;
351 MonoW32HandleEvent *event_handle;
353 mono_w32error_set_last (ERROR_SUCCESS);
355 if (handle == NULL) {
356 mono_w32error_set_last (ERROR_INVALID_HANDLE);
360 switch (type = mono_w32handle_get_type (handle)) {
361 case MONO_W32HANDLE_EVENT:
362 case MONO_W32HANDLE_NAMEDEVENT:
365 mono_w32error_set_last (ERROR_INVALID_HANDLE);
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);
375 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: resetting %s handle %p",
376 __func__, mono_w32handle_get_typename (type), handle);
378 mono_w32handle_lock_handle (handle);
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);
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);
387 mono_w32handle_set_signal_state (handle, FALSE, FALSE);
390 event_handle->set_count = 0;
392 mono_w32handle_unlock_handle (handle);
398 ves_icall_System_Threading_Events_CloseEvent_internal (gpointer handle)
400 mono_w32handle_close (handle);
404 ves_icall_System_Threading_Events_OpenEvent_internal (MonoStringHandle name, gint32 rights G_GNUC_UNUSED, gint32 *err, MonoError *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);
415 mono_w32event_open (const gchar *utf8_name, gint32 rights G_GNUC_UNUSED, gint32 *error)
418 *error = ERROR_SUCCESS;
420 /* w32 seems to guarantee that opening named objects can't race each other */
421 mono_w32handle_namespace_lock ();
423 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Opening named event [%s]", __func__, utf8_name);
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;
430 } else if (!handle) {
431 /* This name doesn't exist */
432 *error = ERROR_FILE_NOT_FOUND;
436 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: returning named event handle %p", __func__, handle);
439 mono_w32handle_namespace_unlock ();
444 MonoW32HandleNamespace*
445 mono_w32event_get_namespace (MonoW32HandleNamedEvent *event)
447 return &event->sharedns;