2 * events.c: Event handles
5 * Dick Porter (dick@ximian.com)
7 * (C) 2002 Ximian, Inc.
15 #include <mono/io-layer/wapi.h>
16 #include <mono/io-layer/wapi-private.h>
17 #include <mono/io-layer/handles-private.h>
18 #include <mono/io-layer/event-private.h>
19 #include <mono/io-layer/io-trace.h>
20 #include <mono/utils/mono-once.h>
21 #include <mono/utils/mono-logger-internals.h>
23 static void event_signal(gpointer handle);
24 static gboolean event_own (gpointer handle);
26 static void namedevent_signal (gpointer handle);
27 static gboolean namedevent_own (gpointer handle);
29 struct _WapiHandleOps _wapi_event_ops = {
31 event_signal, /* signal */
34 NULL, /* special_wait */
38 struct _WapiHandleOps _wapi_namedevent_ops = {
40 namedevent_signal, /* signal */
41 namedevent_own, /* own */
45 void _wapi_event_details (gpointer handle_info)
47 struct _WapiHandle_event *event = (struct _WapiHandle_event *)handle_info;
49 g_print ("manual: %s", event->manual?"TRUE":"FALSE");
52 static mono_once_t event_ops_once=MONO_ONCE_INIT;
54 static void event_ops_init (void)
56 _wapi_handle_register_capabilities (WAPI_HANDLE_EVENT,
57 (WapiHandleCapability)(WAPI_HANDLE_CAP_WAIT | WAPI_HANDLE_CAP_SIGNAL));
58 _wapi_handle_register_capabilities (WAPI_HANDLE_NAMEDEVENT,
59 (WapiHandleCapability)(WAPI_HANDLE_CAP_WAIT | WAPI_HANDLE_CAP_SIGNAL));
62 static const char* event_handle_type_to_string (WapiHandleType type)
65 case WAPI_HANDLE_EVENT: return "event";
66 case WAPI_HANDLE_NAMEDEVENT: return "named event";
68 g_assert_not_reached ();
72 static gboolean event_handle_own (gpointer handle, WapiHandleType type)
74 struct _WapiHandle_event *event_handle;
77 ok = _wapi_lookup_handle (handle, type, (gpointer *)&event_handle);
79 g_warning ("%s: error looking up %s handle %p",
80 __func__, event_handle_type_to_string (type), handle);
84 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: owning %s handle %p",
85 __func__, event_handle_type_to_string (type), handle);
87 if (!event_handle->manual) {
88 g_assert (event_handle->set_count > 0);
89 event_handle->set_count --;
91 if (event_handle->set_count == 0)
92 _wapi_handle_set_signal_state (handle, FALSE, FALSE);
98 static void event_signal(gpointer handle)
103 static gboolean event_own (gpointer handle)
105 return event_handle_own (handle, WAPI_HANDLE_EVENT);
108 static void namedevent_signal (gpointer handle)
113 /* NB, always called with the shared handle lock held */
114 static gboolean namedevent_own (gpointer handle)
116 return event_handle_own (handle, WAPI_HANDLE_NAMEDEVENT);
119 static gpointer event_handle_create (struct _WapiHandle_event *event_handle, WapiHandleType type, gboolean manual, gboolean initial)
124 event_handle->manual = manual;
125 event_handle->set_count = (initial && !manual) ? 1 : 0;
127 handle = _wapi_handle_new (type, event_handle);
128 if (handle == _WAPI_HANDLE_INVALID) {
129 g_warning ("%s: error creating %s handle",
130 __func__, event_handle_type_to_string (type));
131 SetLastError (ERROR_GEN_FAILURE);
135 thr_ret = _wapi_handle_lock_handle (handle);
136 g_assert (thr_ret == 0);
139 _wapi_handle_set_signal_state (handle, TRUE, FALSE);
141 thr_ret = _wapi_handle_unlock_handle (handle);
142 g_assert (thr_ret == 0);
144 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: created %s handle %p",
145 __func__, event_handle_type_to_string (type), handle);
150 static gpointer event_create (gboolean manual, gboolean initial)
152 struct _WapiHandle_event event_handle;
153 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: creating %s handle",
154 __func__, event_handle_type_to_string (WAPI_HANDLE_EVENT));
155 return event_handle_create (&event_handle, WAPI_HANDLE_EVENT, manual, initial);
158 static gpointer namedevent_create (gboolean manual, gboolean initial, const gunichar2 *name G_GNUC_UNUSED)
164 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: creating %s handle",
165 __func__, event_handle_type_to_string (WAPI_HANDLE_NAMEDEVENT));
167 /* w32 seems to guarantee that opening named objects can't race each other */
168 thr_ret = _wapi_namespace_lock ();
169 g_assert (thr_ret == 0);
171 utf8_name = g_utf16_to_utf8 (name, -1, NULL, NULL, NULL);
173 handle = _wapi_search_handle_namespace (WAPI_HANDLE_NAMEDEVENT, utf8_name);
174 if (handle == _WAPI_HANDLE_INVALID) {
175 /* The name has already been used for a different object. */
177 SetLastError (ERROR_INVALID_HANDLE);
179 /* Not an error, but this is how the caller is informed that the event wasn't freshly created */
180 SetLastError (ERROR_ALREADY_EXISTS);
182 /* this is used as creating a new handle */
183 _wapi_handle_ref (handle);
185 /* A new named event */
186 struct _WapiHandle_namedevent namedevent_handle;
188 strncpy (&namedevent_handle.sharedns.name [0], utf8_name, MAX_PATH);
189 namedevent_handle.sharedns.name [MAX_PATH] = '\0';
191 handle = event_handle_create ((struct _WapiHandle_event*) &namedevent_handle, WAPI_HANDLE_NAMEDEVENT, manual, initial);
196 thr_ret = _wapi_namespace_unlock (NULL);
197 g_assert (thr_ret == 0);
205 * @security: Ignored for now.
206 * @manual: Specifies whether the new event handle has manual or auto
208 * @initial: Specifies whether the new event handle is initially
210 * @name:Pointer to a string specifying the name of this name, or
211 * %NULL. Currently ignored.
213 * Creates a new event handle.
215 * An event handle is signalled with SetEvent(). If the new handle is
216 * a manual reset event handle, it remains signalled until it is reset
217 * with ResetEvent(). An auto reset event remains signalled until a
218 * single thread has waited for it, at which time the event handle is
219 * automatically reset to unsignalled.
221 * Return value: A new handle, or %NULL on error.
223 gpointer CreateEvent(WapiSecurityAttributes *security G_GNUC_UNUSED,
224 gboolean manual, gboolean initial,
225 const gunichar2 *name G_GNUC_UNUSED)
227 mono_once (&event_ops_once, event_ops_init);
229 /* Need to blow away any old errors here, because code tests
230 * for ERROR_ALREADY_EXISTS on success (!) to see if an event
231 * was freshly created
233 SetLastError (ERROR_SUCCESS);
235 return name ? namedevent_create (manual, initial, name) : event_create (manual, initial);
240 * @handle: The event handle.
242 * Sets the event handle @handle to the signalled state, and then
243 * resets it to unsignalled after informing any waiting threads.
245 * If @handle is a manual reset event, all waiting threads that can be
246 * released immediately are released. @handle is then reset. If
247 * @handle is an auto reset event, one waiting thread is released even
248 * if multiple threads are waiting.
250 * Return value: %TRUE on success, %FALSE otherwise. (Currently only
251 * ever returns %TRUE).
253 gboolean PulseEvent(gpointer handle)
256 struct _WapiHandle_event *event_handle;
259 if (handle == NULL) {
260 SetLastError (ERROR_INVALID_HANDLE);
264 switch (type = _wapi_handle_type (handle)) {
265 case WAPI_HANDLE_EVENT:
266 case WAPI_HANDLE_NAMEDEVENT:
269 SetLastError (ERROR_INVALID_HANDLE);
273 if (!_wapi_lookup_handle (handle, type, (gpointer *)&event_handle)) {
274 g_warning ("%s: error looking up %s handle %p",
275 __func__, event_handle_type_to_string (type), handle);
279 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: pulsing %s handle %p",
280 __func__, event_handle_type_to_string (type), handle);
282 thr_ret = _wapi_handle_lock_handle (handle);
283 g_assert (thr_ret == 0);
285 if (!event_handle->manual) {
286 event_handle->set_count = 1;
287 _wapi_handle_set_signal_state (handle, TRUE, FALSE);
289 _wapi_handle_set_signal_state (handle, TRUE, TRUE);
291 thr_ret = _wapi_handle_unlock_handle (handle);
292 g_assert (thr_ret == 0);
294 /* For a manual-reset event, we're about to try and get the handle
295 * lock again, so give other threads a chance */
298 /* Reset the handle signal state */
300 /* I'm not sure whether or not we need a barrier here to make sure
301 * that all threads waiting on the event have proceeded. Currently
302 * we rely on broadcasting a condition. */
304 thr_ret = _wapi_handle_lock_handle (handle);
305 g_assert (thr_ret == 0);
307 _wapi_handle_set_signal_state (handle, FALSE, FALSE);
310 thr_ret = _wapi_handle_unlock_handle (handle);
311 g_assert (thr_ret == 0);
318 * @handle: The event handle.
320 * Resets the event handle @handle to the unsignalled state.
322 * Return value: %TRUE on success, %FALSE otherwise. (Currently only
323 * ever returns %TRUE).
325 gboolean ResetEvent(gpointer handle)
328 struct _WapiHandle_event *event_handle;
331 SetLastError (ERROR_SUCCESS);
333 if (handle == NULL) {
334 SetLastError (ERROR_INVALID_HANDLE);
338 switch (type = _wapi_handle_type (handle)) {
339 case WAPI_HANDLE_EVENT:
340 case WAPI_HANDLE_NAMEDEVENT:
343 SetLastError (ERROR_INVALID_HANDLE);
347 if (!_wapi_lookup_handle (handle, type, (gpointer *)&event_handle)) {
348 g_warning ("%s: error looking up %s handle %p",
349 __func__, event_handle_type_to_string (type), handle);
353 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: resetting %s handle %p",
354 __func__, event_handle_type_to_string (type), handle);
356 thr_ret = _wapi_handle_lock_handle (handle);
357 g_assert (thr_ret == 0);
359 if (!_wapi_handle_issignalled (handle)) {
360 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: no need to reset %s handle %p",
361 __func__, event_handle_type_to_string (type), handle);
363 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: obtained write lock on %s handle %p",
364 __func__, event_handle_type_to_string (type), handle);
366 _wapi_handle_set_signal_state (handle, FALSE, FALSE);
369 event_handle->set_count = 0;
371 thr_ret = _wapi_handle_unlock_handle (handle);
372 g_assert (thr_ret == 0);
379 * @handle: The event handle
381 * Sets the event handle @handle to the signalled state.
383 * If @handle is a manual reset event, it remains signalled until it
384 * is reset with ResetEvent(). An auto reset event remains signalled
385 * until a single thread has waited for it, at which time @handle is
386 * automatically reset to unsignalled.
388 * Return value: %TRUE on success, %FALSE otherwise. (Currently only
389 * ever returns %TRUE).
391 gboolean SetEvent(gpointer handle)
394 struct _WapiHandle_event *event_handle;
397 if (handle == NULL) {
398 SetLastError (ERROR_INVALID_HANDLE);
402 switch (type = _wapi_handle_type (handle)) {
403 case WAPI_HANDLE_EVENT:
404 case WAPI_HANDLE_NAMEDEVENT:
407 SetLastError (ERROR_INVALID_HANDLE);
411 if (!_wapi_lookup_handle (handle, type, (gpointer *)&event_handle)) {
412 g_warning ("%s: error looking up %s handle %p",
413 __func__, event_handle_type_to_string (type), handle);
417 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: setting %s handle %p",
418 __func__, event_handle_type_to_string (type), handle);
420 thr_ret = _wapi_handle_lock_handle (handle);
421 g_assert (thr_ret == 0);
423 if (!event_handle->manual) {
424 event_handle->set_count = 1;
425 _wapi_handle_set_signal_state (handle, TRUE, FALSE);
427 _wapi_handle_set_signal_state (handle, TRUE, TRUE);
430 thr_ret = _wapi_handle_unlock_handle (handle);
431 g_assert (thr_ret == 0);
436 gpointer OpenEvent (guint32 access G_GNUC_UNUSED, gboolean inherit G_GNUC_UNUSED, const gunichar2 *name)
442 mono_once (&event_ops_once, event_ops_init);
444 /* w32 seems to guarantee that opening named objects can't
447 thr_ret = _wapi_namespace_lock ();
448 g_assert (thr_ret == 0);
450 utf8_name = g_utf16_to_utf8 (name, -1, NULL, NULL, NULL);
452 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Opening named event [%s]", __func__, utf8_name);
454 handle = _wapi_search_handle_namespace (WAPI_HANDLE_NAMEDEVENT,
456 if (handle == _WAPI_HANDLE_INVALID) {
457 /* The name has already been used for a different
460 SetLastError (ERROR_INVALID_HANDLE);
462 } else if (!handle) {
463 /* This name doesn't exist */
464 SetLastError (ERROR_FILE_NOT_FOUND); /* yes, really */
468 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: returning named event handle %p", __func__, handle);
473 _wapi_namespace_unlock (NULL);