[sre] Wrap mono_image_create_token with HANDLE_FUNCTION_{ENTER,RETURN}
[mono-project.git] / mono / metadata / w32event-unix.c
blob37ec577a6b02fb17f37d0a5f02813a867cb08f6a
1 /**
2 * \file
3 * Runtime support for managed Event on Unix
5 * Author:
6 * Ludovic Henry (luhenry@microsoft.com)
8 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
9 */
11 #include "w32event.h"
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"
21 #define MAX_PATH 260
23 static gpointer
24 mono_w32event_create_full (MonoBoolean manual, MonoBoolean initial, const gchar *name, gint32 *err);
26 static gpointer
27 mono_w32event_open (const gchar *utf8_name, gint32 rights G_GNUC_UNUSED, gint32 *error);
29 typedef struct {
30 gboolean manual;
31 guint32 set_count;
32 } MonoW32HandleEvent;
34 struct MonoW32HandleNamedEvent {
35 MonoW32HandleEvent e;
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);
47 } else {
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;
55 gboolean ok;
57 *abandoned = FALSE;
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;
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);
77 return TRUE;
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)
117 return "Event";
120 static gsize event_typesize (void)
122 return sizeof (MonoW32HandleEvent);
125 static const gchar* namedevent_typename (void)
127 return "N.Event";
130 static gsize namedevent_typesize (void)
132 return sizeof (MonoW32HandleNamedEvent);
135 void
136 mono_w32event_init (void)
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 */
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 */
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));
171 gpointer
172 mono_w32event_create (gboolean manual, gboolean initial)
174 gpointer handle;
175 gint32 error;
177 handle = mono_w32event_create_full (manual, initial, NULL, &error);
178 if (error != ERROR_SUCCESS)
179 g_assert (!handle);
181 return handle;
184 gboolean
185 mono_w32event_close (gpointer handle)
187 return mono_w32handle_close (handle);
190 void
191 mono_w32event_set (gpointer handle)
193 ves_icall_System_Threading_Events_SetEvent_internal (handle);
196 void
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)
204 gpointer handle;
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);
214 return NULL;
217 mono_w32handle_lock_handle (handle);
219 if (initial)
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);
227 return 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)
240 gpointer handle;
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. */
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);
259 /* mono_w32handle_namespace_search_handle already adds a ref to the handle */
260 } else {
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 ();
273 return handle;
276 gpointer
277 mono_w32event_create_full (MonoBoolean manual, MonoBoolean initial, const gchar *name, gint32 *error)
279 gpointer event;
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 ();
290 return event;
293 gpointer
294 ves_icall_System_Threading_Events_CreateEvent_internal (MonoBoolean manual, MonoBoolean initial, MonoStringHandle name, gint32 *err, MonoError *error)
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;
304 gboolean
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);
312 return(FALSE);
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;
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;
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);
338 } else {
339 mono_w32handle_set_signal_state (handle, TRUE, TRUE);
342 mono_w32handle_unlock_handle (handle);
344 return TRUE;
347 gboolean
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);
357 return(FALSE);
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;
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;
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);
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);
387 mono_w32handle_set_signal_state (handle, FALSE, FALSE);
390 event_handle->set_count = 0;
392 mono_w32handle_unlock_handle (handle);
394 return TRUE;
397 void
398 ves_icall_System_Threading_Events_CloseEvent_internal (gpointer handle)
400 mono_w32handle_close (handle);
403 gpointer
404 ves_icall_System_Threading_Events_OpenEvent_internal (MonoStringHandle name, gint32 rights G_GNUC_UNUSED, gint32 *err, MonoError *error)
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;
414 gpointer
415 mono_w32event_open (const gchar *utf8_name, gint32 rights G_GNUC_UNUSED, gint32 *error)
417 gpointer handle;
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;
429 goto cleanup;
430 } else if (!handle) {
431 /* This name doesn't exist */
432 *error = ERROR_FILE_NOT_FOUND;
433 goto cleanup;
436 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: returning named event handle %p", __func__, handle);
438 cleanup:
439 mono_w32handle_namespace_unlock ();
441 return handle;
444 MonoW32HandleNamespace*
445 mono_w32event_get_namespace (MonoW32HandleNamedEvent *event)
447 return &event->sharedns;