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"
20 #include "icall-decl.h"
25 mono_w32event_create_full (MonoBoolean manual
, MonoBoolean initial
, const char *name
, gsize name_length
, gint32
*win32error
);
28 mono_w32event_open (const gchar
*utf8_name
, gint32 rights G_GNUC_UNUSED
, gint32
*error
);
35 struct MonoW32HandleNamedEvent
{
37 MonoW32HandleNamespace sharedns
;
40 static gint32
event_handle_signal (MonoW32Handle
*handle_data
)
42 MonoW32HandleEvent
*event_handle
;
44 event_handle
= (MonoW32HandleEvent
*) handle_data
->specific
;
46 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_IO_LAYER_EVENT
, "%s: signalling %s handle %p",
47 __func__
, mono_w32handle_get_typename (handle_data
->type
), handle_data
);
49 if (!event_handle
->manual
) {
50 event_handle
->set_count
= 1;
51 mono_w32handle_set_signal_state (handle_data
, TRUE
, FALSE
);
53 mono_w32handle_set_signal_state (handle_data
, TRUE
, TRUE
);
55 return MONO_W32HANDLE_WAIT_RET_SUCCESS_0
;
58 static gboolean
event_handle_own (MonoW32Handle
*handle_data
, gboolean
*abandoned
)
60 MonoW32HandleEvent
*event_handle
;
64 event_handle
= (MonoW32HandleEvent
*) handle_data
->specific
;
66 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_IO_LAYER_EVENT
, "%s: owning %s handle %p",
67 __func__
, mono_w32handle_get_typename (handle_data
->type
), handle_data
);
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_data
, FALSE
, FALSE
);
80 static void event_details (MonoW32Handle
*handle_data
)
82 MonoW32HandleEvent
*event
= (MonoW32HandleEvent
*)handle_data
->specific
;
83 g_print ("manual: %s, set_count: %d",
84 event
->manual
? "TRUE" : "FALSE", event
->set_count
);
87 static void namedevent_details (MonoW32Handle
*handle_data
)
89 MonoW32HandleNamedEvent
*namedevent
= (MonoW32HandleNamedEvent
*)handle_data
->specific
;
90 g_print ("manual: %s, set_count: %d, name: \"%s\"",
91 namedevent
->e
.manual
? "TRUE" : "FALSE", namedevent
->e
.set_count
, namedevent
->sharedns
.name
);
94 static const gchar
* event_typename (void)
99 static gsize
event_typesize (void)
101 return sizeof (MonoW32HandleEvent
);
104 static const gchar
* namedevent_typename (void)
109 static gsize
namedevent_typesize (void)
111 return sizeof (MonoW32HandleNamedEvent
);
115 mono_w32event_init (void)
117 static const MonoW32HandleOps event_ops
= {
119 event_handle_signal
, /* signal */
120 event_handle_own
, /* own */
122 NULL
, /* special_wait */
124 event_details
, /* details */
125 event_typename
, /* typename */
126 event_typesize
, /* typesize */
129 static const MonoW32HandleOps namedevent_ops
= {
131 event_handle_signal
, /* signal */
132 event_handle_own
, /* own */
134 NULL
, /* special_wait */
136 namedevent_details
, /* details */
137 namedevent_typename
, /* typename */
138 namedevent_typesize
, /* typesize */
141 mono_w32handle_register_ops (MONO_W32TYPE_EVENT
, &event_ops
);
142 mono_w32handle_register_ops (MONO_W32TYPE_NAMEDEVENT
, &namedevent_ops
);
144 mono_w32handle_register_capabilities (MONO_W32TYPE_EVENT
,
145 (MonoW32HandleCapability
)(MONO_W32HANDLE_CAP_WAIT
| MONO_W32HANDLE_CAP_SIGNAL
));
146 mono_w32handle_register_capabilities (MONO_W32TYPE_NAMEDEVENT
,
147 (MonoW32HandleCapability
)(MONO_W32HANDLE_CAP_WAIT
| MONO_W32HANDLE_CAP_SIGNAL
));
151 mono_w32event_create (gboolean manual
, gboolean initial
)
153 gint32 win32error
= ERROR_SUCCESS
;
155 gpointer handle
= mono_w32event_create_full (manual
, initial
, NULL
, 0, &win32error
);
156 g_assert ((win32error
!= ERROR_SUCCESS
) == !handle
);
162 mono_w32event_close (gpointer handle
)
164 return mono_w32handle_close (handle
);
168 mono_w32event_set (gpointer handle
)
170 ves_icall_System_Threading_Events_SetEvent_internal (handle
);
174 mono_w32event_reset (gpointer handle
)
176 ves_icall_System_Threading_Events_ResetEvent_internal (handle
);
179 static gpointer
event_handle_create (MonoW32HandleEvent
*event_handle
, MonoW32Type type
, gboolean manual
, gboolean initial
)
181 MonoW32Handle
*handle_data
;
184 event_handle
->manual
= manual
;
185 event_handle
->set_count
= (initial
&& !manual
) ? 1 : 0;
187 handle
= mono_w32handle_new (type
, event_handle
);
188 if (handle
== INVALID_HANDLE_VALUE
) {
189 g_warning ("%s: error creating %s handle",
190 __func__
, mono_w32handle_get_typename (type
));
191 mono_w32error_set_last (ERROR_GEN_FAILURE
);
195 if (!mono_w32handle_lookup_and_ref (handle
, &handle_data
))
196 g_error ("%s: unkown handle %p", __func__
, handle
);
198 if (handle_data
->type
!= type
)
199 g_error ("%s: unknown event handle %p", __func__
, handle
);
201 mono_w32handle_lock (handle_data
);
204 mono_w32handle_set_signal_state (handle_data
, TRUE
, FALSE
);
206 mono_w32handle_unlock (handle_data
);
208 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_IO_LAYER_EVENT
, "%s: created %s handle %p",
209 __func__
, mono_w32handle_get_typename (type
), handle
);
211 mono_w32handle_unref (handle_data
);
216 static gpointer
event_create (gboolean manual
, gboolean initial
)
218 MonoW32HandleEvent event_handle
;
219 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_IO_LAYER_EVENT
, "%s: creating %s handle",
220 __func__
, mono_w32handle_get_typename (MONO_W32TYPE_EVENT
));
221 return event_handle_create (&event_handle
, MONO_W32TYPE_EVENT
, manual
, initial
);
225 namedevent_create (gboolean manual
, gboolean initial
, const char *utf8_name
, gsize utf8_len
)
227 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_IO_LAYER_EVENT
, "%s: creating %s handle",
228 __func__
, mono_w32handle_get_typename (MONO_W32TYPE_NAMEDEVENT
));
230 // Opening named objects does not race.
231 mono_w32handle_namespace_lock ();
233 gpointer handle
= mono_w32handle_namespace_search_handle (MONO_W32TYPE_NAMEDEVENT
, utf8_name
);
235 if (handle
== INVALID_HANDLE_VALUE
) {
236 /* The name has already been used for a different object. */
238 mono_w32error_set_last (ERROR_INVALID_HANDLE
);
240 /* Not an error, but this is how the caller is informed that the event wasn't freshly created */
241 mono_w32error_set_last (ERROR_ALREADY_EXISTS
);
243 /* mono_w32handle_namespace_search_handle already adds a ref to the handle */
245 /* A new named event */
246 MonoW32HandleNamedEvent namedevent_handle
;
248 // FIXME Silent truncation.
250 size_t len
= utf8_len
< MAX_PATH
? utf8_len
: MAX_PATH
;
251 memcpy (&namedevent_handle
.sharedns
.name
[0], utf8_name
, len
);
252 namedevent_handle
.sharedns
.name
[len
] = '\0';
254 handle
= event_handle_create ((MonoW32HandleEvent
*) &namedevent_handle
, MONO_W32TYPE_NAMEDEVENT
, manual
, initial
);
257 mono_w32handle_namespace_unlock ();
263 mono_w32event_create_full (MonoBoolean manual
, MonoBoolean initial
, const char *name
, gsize name_length
, gint32
*win32error
)
265 /* Need to blow away any old errors here, because code tests
266 * for ERROR_ALREADY_EXISTS on success (!) to see if an event
267 * was freshly created */
268 mono_w32error_set_last (ERROR_SUCCESS
);
270 gpointer event
= name
? namedevent_create (manual
, initial
, name
, name_length
) : event_create (manual
, initial
);
272 *win32error
= mono_w32error_get_last ();
278 ves_icall_System_Threading_Events_CreateEvent_icall (MonoBoolean manual
, MonoBoolean initial
,
279 const gunichar2
* name
, gint32 name_length
, gint32
*win32error
, MonoError
*error
)
281 *win32error
= ERROR_SUCCESS
;
282 gsize utf8_name_length
= 0;
283 char *utf8_name
= mono_utf16_to_utf8len (name
, name_length
, &utf8_name_length
, error
);
284 return_val_if_nok (error
, NULL
);
285 gpointer result
= mono_w32event_create_full (manual
, initial
, utf8_name
, utf8_name_length
, win32error
);
291 ves_icall_System_Threading_Events_SetEvent_internal (gpointer handle
)
293 MonoW32Handle
*handle_data
;
294 MonoW32HandleEvent
*event_handle
;
296 if (!mono_w32handle_lookup_and_ref (handle
, &handle_data
)) {
297 g_warning ("%s: unkown handle %p", __func__
, handle
);
298 mono_w32error_set_last (ERROR_INVALID_HANDLE
);
302 if (handle_data
->type
!= MONO_W32TYPE_EVENT
&& handle_data
->type
!= MONO_W32TYPE_NAMEDEVENT
) {
303 g_warning ("%s: unkown event handle %p", __func__
, handle
);
304 mono_w32error_set_last (ERROR_INVALID_HANDLE
);
305 mono_w32handle_unref (handle_data
);
309 event_handle
= (MonoW32HandleEvent
*) handle_data
->specific
;
311 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_IO_LAYER_EVENT
, "%s: setting %s handle %p",
312 __func__
, mono_w32handle_get_typename (handle_data
->type
), handle
);
314 mono_w32handle_lock (handle_data
);
316 if (!event_handle
->manual
) {
317 event_handle
->set_count
= 1;
318 mono_w32handle_set_signal_state (handle_data
, TRUE
, FALSE
);
320 mono_w32handle_set_signal_state (handle_data
, TRUE
, TRUE
);
323 mono_w32handle_unlock (handle_data
);
325 mono_w32handle_unref (handle_data
);
330 ves_icall_System_Threading_Events_ResetEvent_internal (gpointer handle
)
332 MonoW32Handle
*handle_data
;
333 MonoW32HandleEvent
*event_handle
;
335 mono_w32error_set_last (ERROR_SUCCESS
);
337 if (!mono_w32handle_lookup_and_ref (handle
, &handle_data
)) {
338 g_warning ("%s: unkown handle %p", __func__
, handle
);
339 mono_w32error_set_last (ERROR_INVALID_HANDLE
);
343 if (handle_data
->type
!= MONO_W32TYPE_EVENT
&& handle_data
->type
!= MONO_W32TYPE_NAMEDEVENT
) {
344 g_warning ("%s: unkown event handle %p", __func__
, handle
);
345 mono_w32error_set_last (ERROR_INVALID_HANDLE
);
346 mono_w32handle_unref (handle_data
);
350 event_handle
= (MonoW32HandleEvent
*) handle_data
->specific
;
352 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_IO_LAYER_EVENT
, "%s: resetting %s handle %p",
353 __func__
, mono_w32handle_get_typename (handle_data
->type
), handle
);
355 mono_w32handle_lock (handle_data
);
357 if (!mono_w32handle_issignalled (handle_data
)) {
358 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_IO_LAYER_EVENT
, "%s: no need to reset %s handle %p",
359 __func__
, mono_w32handle_get_typename (handle_data
->type
), handle
);
361 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_IO_LAYER_EVENT
, "%s: obtained write lock on %s handle %p",
362 __func__
, mono_w32handle_get_typename (handle_data
->type
), handle
);
364 mono_w32handle_set_signal_state (handle_data
, FALSE
, FALSE
);
367 event_handle
->set_count
= 0;
369 mono_w32handle_unlock (handle_data
);
371 mono_w32handle_unref (handle_data
);
376 ves_icall_System_Threading_Events_CloseEvent_internal (gpointer handle
)
378 mono_w32handle_close (handle
);
381 #ifndef ENABLE_NETCORE
383 ves_icall_System_Threading_Events_OpenEvent_icall (const gunichar2
*name
, gint32 name_length
,
384 gint32 rights
, gint32
*win32error
, MonoError
*error
)
386 *win32error
= ERROR_SUCCESS
;
387 char *utf8_name
= mono_utf16_to_utf8 (name
, name_length
, error
);
388 return_val_if_nok (error
, NULL
);
389 gpointer handle
= mono_w32event_open (utf8_name
, rights
, win32error
);
396 mono_w32event_open (const gchar
*utf8_name
, gint32 rights G_GNUC_UNUSED
, gint32
*win32error
)
398 *win32error
= ERROR_SUCCESS
;
400 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_IO_LAYER_EVENT
, "%s: Opening named event [%s]", __func__
, utf8_name
);
402 // Opening named objects does not race.
403 mono_w32handle_namespace_lock ();
405 gpointer handle
= mono_w32handle_namespace_search_handle (MONO_W32TYPE_NAMEDEVENT
, utf8_name
);
407 mono_w32handle_namespace_unlock ();
409 if (handle
== INVALID_HANDLE_VALUE
) {
410 /* The name has already been used for a different object. */
411 *win32error
= ERROR_INVALID_HANDLE
;
413 } else if (!handle
) {
414 /* This name doesn't exist */
415 *win32error
= ERROR_FILE_NOT_FOUND
;
419 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_IO_LAYER_EVENT
, "%s: returning named event handle %p", __func__
, handle
);
424 MonoW32HandleNamespace
*
425 mono_w32event_get_namespace (MonoW32HandleNamedEvent
*event
)
427 return &event
->sharedns
;