[2020-02] Fix leak in assembly-specific dllmap lookups (#21053)
[mono-project.git] / mono / metadata / w32event-unix.c
blobabc9bf98b26189311b7ead19d0dfff066fd4a4ac
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"
20 #include "icall-decl.h"
22 #define MAX_PATH 260
24 static gpointer
25 mono_w32event_create_full (MonoBoolean manual, MonoBoolean initial, const char *name, gsize name_length, gint32 *win32error);
27 static gpointer
28 mono_w32event_open (const gchar *utf8_name, gint32 rights G_GNUC_UNUSED, gint32 *error);
30 typedef struct {
31 gboolean manual;
32 guint32 set_count;
33 } MonoW32HandleEvent;
35 struct MonoW32HandleNamedEvent {
36 MonoW32HandleEvent e;
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);
52 } else {
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;
62 *abandoned = FALSE;
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);
77 return TRUE;
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)
96 return "Event";
99 static gsize event_typesize (void)
101 return sizeof (MonoW32HandleEvent);
104 static const gchar* namedevent_typename (void)
106 return "N.Event";
109 static gsize namedevent_typesize (void)
111 return sizeof (MonoW32HandleNamedEvent);
114 void
115 mono_w32event_init (void)
117 static const MonoW32HandleOps event_ops = {
118 NULL, /* close */
119 event_handle_signal, /* signal */
120 event_handle_own, /* own */
121 NULL, /* is_owned */
122 NULL, /* special_wait */
123 NULL, /* prewait */
124 event_details, /* details */
125 event_typename, /* typename */
126 event_typesize, /* typesize */
129 static const MonoW32HandleOps namedevent_ops = {
130 NULL, /* close */
131 event_handle_signal, /* signal */
132 event_handle_own, /* own */
133 NULL, /* is_owned */
134 NULL, /* special_wait */
135 NULL, /* prewait */
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));
150 gpointer
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);
158 return handle;
161 gboolean
162 mono_w32event_close (gpointer handle)
164 return mono_w32handle_close (handle);
167 void
168 mono_w32event_set (gpointer handle)
170 ves_icall_System_Threading_Events_SetEvent_internal (handle);
173 void
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;
182 gpointer handle;
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);
192 return NULL;
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);
203 if (initial)
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);
213 return handle;
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);
224 static gpointer
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. */
237 handle = NULL;
238 mono_w32error_set_last (ERROR_INVALID_HANDLE);
239 } else if (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 */
244 } else {
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 ();
259 return handle;
262 gpointer
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 ();
274 return event;
277 gpointer
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);
286 g_free (utf8_name);
287 return result;
290 gboolean
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);
299 return FALSE;
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);
306 return FALSE;
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);
319 } else {
320 mono_w32handle_set_signal_state (handle_data, TRUE, TRUE);
323 mono_w32handle_unlock (handle_data);
325 mono_w32handle_unref (handle_data);
326 return TRUE;
329 gboolean
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);
340 return FALSE;
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);
347 return FALSE;
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);
360 } else {
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);
372 return TRUE;
375 void
376 ves_icall_System_Threading_Events_CloseEvent_internal (gpointer handle)
378 mono_w32handle_close (handle);
381 #ifndef ENABLE_NETCORE
382 gpointer
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);
390 g_free (utf8_name);
391 return handle;
393 #endif
395 gpointer
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;
412 return handle;
413 } else if (!handle) {
414 /* This name doesn't exist */
415 *win32error = ERROR_FILE_NOT_FOUND;
416 return handle;
419 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_EVENT, "%s: returning named event handle %p", __func__, handle);
421 return handle;
424 MonoW32HandleNamespace*
425 mono_w32event_get_namespace (MonoW32HandleNamedEvent *event)
427 return &event->sharedns;