+/*
+ * events.c: Event handles
+ *
+ * Author:
+ * Dick Porter (dick@ximian.com)
+ *
+ * (C) 2002 Ximian, Inc.
+ */
+
#include <config.h>
#include <glib.h>
#include <pthread.h>
#include <string.h>
-#include "mono/io-layer/wapi.h"
-#include "wapi-private.h"
-#include "wait-private.h"
-#include "handles-private.h"
-#include "misc-private.h"
+#include <mono/io-layer/wapi.h>
+#include <mono/io-layer/wapi-private.h>
+#include <mono/io-layer/handles-private.h>
+#include <mono/io-layer/misc-private.h>
-#define DEBUG
+#include <mono/io-layer/mono-mutex.h>
-/* event_wait() uses the event-private condition to signal that the
- * event has been set
- *
- * Hold mutex before setting the event, and before the final test
- * Hold rwlock for reading while testing the event
- * Hold rwlock for writing before resetting the event
- */
-struct _WapiHandle_event
-{
- WapiHandle handle;
- pthread_mutex_t mutex;
- pthread_cond_t cond;
- pthread_rwlock_t rwlock;
- gboolean manual;
+#include <mono/io-layer/event-private.h>
+
+#undef DEBUG
+
+static void event_signal(gpointer handle);
+static gboolean event_own (gpointer handle);
+
+static void namedevent_signal (gpointer handle);
+static gboolean namedevent_own (gpointer handle);
+
+struct _WapiHandleOps _wapi_event_ops = {
+ NULL, /* close */
+ event_signal, /* signal */
+ event_own, /* own */
+ NULL, /* is_owned */
+ NULL, /* special_wait */
+ NULL /* prewait */
};
-/* event_wait_multiple() uses the global condition to signal that an
- * event has been set
- */
-static pthread_mutex_t event_signal_mutex = PTHREAD_MUTEX_INITIALIZER;
-static pthread_cond_t event_signal_cond = PTHREAD_COND_INITIALIZER;
-
-static void event_close(WapiHandle *handle);
-static gboolean event_wait(WapiHandle *handle, guint32 ms);
-static guint32 event_wait_multiple(gpointer data);
-
-static struct _WapiHandleOps event_ops = {
- event_close, /* close */
- NULL, /* getfiletype */
- NULL, /* readfile */
- NULL, /* writefile */
- NULL, /* seek */
- NULL, /* setendoffile */
- NULL, /* getfilesize */
- event_wait, /* wait */
- event_wait_multiple, /* wait_multiple */
+struct _WapiHandleOps _wapi_namedevent_ops = {
+ NULL, /* close */
+ namedevent_signal, /* signal */
+ namedevent_own, /* own */
+ NULL, /* is_owned */
};
-static void event_close(WapiHandle *handle)
+static gboolean event_pulse (gpointer handle);
+static gboolean event_reset (gpointer handle);
+static gboolean event_set (gpointer handle);
+
+static gboolean namedevent_pulse (gpointer handle);
+static gboolean namedevent_reset (gpointer handle);
+static gboolean namedevent_set (gpointer handle);
+
+static struct
{
- struct _WapiHandle_event *event_handle=(struct _WapiHandle_event *)handle;
+ gboolean (*pulse)(gpointer handle);
+ gboolean (*reset)(gpointer handle);
+ gboolean (*set)(gpointer handle);
+} event_ops[WAPI_HANDLE_COUNT] = {
+ {NULL},
+ {NULL},
+ {NULL},
+ {NULL},
+ {NULL},
+ {NULL},
+ {event_pulse, event_reset, event_set},
+ {NULL},
+ {NULL},
+ {NULL},
+ {NULL},
+ {NULL},
+ {NULL},
+ {namedevent_pulse, namedevent_reset, namedevent_set},
+};
+
+void _wapi_event_details (gpointer handle_info)
+{
+ struct _WapiHandle_event *event = (struct _WapiHandle_event *)handle_info;
-#ifdef DEBUG
- g_message(G_GNUC_PRETTY_FUNCTION ": closing event handle %p",
- event_handle);
-#endif
+ g_print ("manual: %s", event->manual?"TRUE":"FALSE");
}
-static gboolean event_wait(WapiHandle *handle, guint32 ms)
+static mono_once_t event_ops_once=MONO_ONCE_INIT;
+
+static void event_ops_init (void)
{
- struct _WapiHandle_event *event_handle=(struct _WapiHandle_event *)handle;
- struct timespec timeout;
- int ret;
+ _wapi_handle_register_capabilities (WAPI_HANDLE_EVENT,
+ WAPI_HANDLE_CAP_WAIT |
+ WAPI_HANDLE_CAP_SIGNAL);
+ _wapi_handle_register_capabilities (WAPI_HANDLE_NAMEDEVENT,
+ WAPI_HANDLE_CAP_WAIT |
+ WAPI_HANDLE_CAP_SIGNAL);
+}
-#ifdef DEBUG
- g_message(G_GNUC_PRETTY_FUNCTION
- ": waiting on event handle %p for %d ms", handle, ms);
-#endif
+static void event_signal(gpointer handle)
+{
+ SetEvent(handle);
+}
- pthread_mutex_lock(&event_handle->mutex);
-
- /* First check if the handle is already signalled */
- if(handle->signalled==TRUE) {
- /* If this is an auto-reset event, reset the state to
- * unsignalled
- */
+static gboolean event_own (gpointer handle)
+{
+ struct _WapiHandle_event *event_handle;
+ gboolean ok;
+
+ ok=_wapi_lookup_handle (handle, WAPI_HANDLE_EVENT,
+ (gpointer *)&event_handle);
+ if(ok==FALSE) {
+ g_warning ("%s: error looking up event handle %p", __func__,
+ handle);
+ return (FALSE);
+ }
#ifdef DEBUG
- g_message(G_GNUC_PRETTY_FUNCTION
- ": event handle %p already signalled", handle);
+ g_message("%s: owning event handle %p", __func__, handle);
#endif
- if(event_handle->manual==FALSE) {
-#ifdef DEBUG
- g_message(G_GNUC_PRETTY_FUNCTION
- ": resetting auto event handle %p", handle);
-#endif
- handle->signalled=FALSE;
- }
- pthread_mutex_unlock(&event_handle->mutex);
+ if(event_handle->manual==FALSE) {
+ g_assert (event_handle->set_count > 0);
- return(TRUE);
+ if (--event_handle->set_count == 0) {
+ _wapi_handle_set_signal_state (handle, FALSE, FALSE);
+ }
}
- /* We'll have to wait for it then */
- if(ms!=INFINITE) {
- _wapi_calc_timeout(&timeout, ms);
- }
-
-again:
- /* Acquire a read lock so that the signal status can't be
- * reset without us noticing. (PulseEvent and ResetEvent will
- * gain a write lock before changing the status to
- * unsignalled, which will block while one or more threads
- * hold a read lock.)
- */
- pthread_rwlock_rdlock(&event_handle->rwlock);
-
-#ifdef DEBUG
- g_message(G_GNUC_PRETTY_FUNCTION
- ": waiting for event handle %p to be signalled", handle);
-#endif
+ return(TRUE);
+}
- if(ms==INFINITE) {
- ret=pthread_cond_wait(&event_handle->cond,
- &event_handle->mutex);
- } else {
- ret=pthread_cond_timedwait(&event_handle->cond,
- &event_handle->mutex, &timeout);
- }
+static void namedevent_signal (gpointer handle)
+{
+ SetEvent (handle);
+}
- if(ret==0) {
- /* Condition was signalled, so hopefully event is
- * signalled now. (It might not be if its an
- * auto-reset event and someone else got in before
- * us.)
- */
-
-#ifdef DEBUG
- g_message(G_GNUC_PRETTY_FUNCTION ": event handle %p signalled",
- handle);
-#endif
- if(handle->signalled==TRUE) {
-
-#ifdef DEBUG
- g_message(G_GNUC_PRETTY_FUNCTION
- ": event handle %p still signalled", handle);
-#endif
- /* If this is an auto-reset event, reset the
- * state to unsignalled
- */
- if(event_handle->manual==FALSE) {
-#ifdef DEBUG
- g_message(G_GNUC_PRETTY_FUNCTION
- ": resetting auto event handle %p",
- handle);
-#endif
- handle->signalled=FALSE;
- }
- pthread_rwlock_unlock(&event_handle->rwlock);
- pthread_mutex_unlock(&event_handle->mutex);
-
- return(TRUE);
- }
+/* NB, always called with the shared handle lock held */
+static gboolean namedevent_own (gpointer handle)
+{
+ struct _WapiHandle_namedevent *namedevent_handle;
+ gboolean ok;
#ifdef DEBUG
- g_message(G_GNUC_PRETTY_FUNCTION
- ": event handle %p no longer signalled", handle);
+ g_message ("%s: owning named event handle %p", __func__, handle);
#endif
- /* Better luck next time */
-
- /* Drop the rwlock briefly so that another thread has
- * a chance to reset the event
- */
- pthread_rwlock_unlock(&event_handle->rwlock);
- goto again;
+ ok = _wapi_lookup_handle (handle, WAPI_HANDLE_NAMEDEVENT,
+ (gpointer *)&namedevent_handle);
+ if (ok == FALSE) {
+ g_warning ("%s: error looking up named event handle %p",
+ __func__, handle);
+ return(FALSE);
}
-
- /* Timeout or other error */
-#ifdef DEBUG
- g_message(G_GNUC_PRETTY_FUNCTION
- ": wait on event handle %p error: %s", handle,
- strerror(ret));
-#endif
-
- pthread_rwlock_unlock(&event_handle->rwlock);
- pthread_mutex_unlock(&event_handle->mutex);
+ if (namedevent_handle->manual == FALSE) {
+ g_assert (namedevent_handle->set_count > 0);
+
+ if (--namedevent_handle->set_count == 0) {
+ _wapi_shared_handle_set_signal_state (handle, FALSE);
+ }
+ }
- return(FALSE);
+ return (TRUE);
}
-
-static gboolean event_count_signalled(GPtrArray *handles, guint32 numhandles,
- gboolean waitall, guint32 *retcount)
+static gpointer event_create (WapiSecurityAttributes *security G_GNUC_UNUSED,
+ gboolean manual, gboolean initial)
{
- guint32 count, i;
- gboolean ret;
+ struct _WapiHandle_event event_handle = {0};
+ gpointer handle;
+ int thr_ret;
- /* Lock all the handles, with backoff */
-again:
- for(i=0; i<numhandles; i++) {
- struct _WapiHandle_event *event_handle;
-
- event_handle=g_ptr_array_index(handles, i);
-
- ret=pthread_mutex_trylock(&event_handle->mutex);
- if(ret!=0) {
- /* Bummer */
- while(i--) {
- event_handle=g_ptr_array_index(handles, i);
- pthread_mutex_unlock(&event_handle->mutex);
- }
+ /* Need to blow away any old errors here, because code tests
+ * for ERROR_ALREADY_EXISTS on success (!) to see if an event
+ * was freshly created
+ */
+ SetLastError (ERROR_SUCCESS);
- /* It's not possible for two threads calling
- * WaitForMultipleObjects to both be calling
- * this function simultaneously, because the
- * global event_signal_mutex is held.
- * Therefore any collision is with a single
- * lock from one of the functions that deal
- * with single event handles. It's just about
- * theoretically possible for the other
- * threads to keep locking an event in a tight
- * loop but eventually we will get the lock.
- */
- sched_yield();
-
- goto again;
- }
- }
-
#ifdef DEBUG
- g_message(G_GNUC_PRETTY_FUNCTION ": Locked all event handles");
+ g_message ("%s: Creating unnamed event", __func__);
#endif
- count=_wapi_handle_count_signalled(handles);
-
-#ifdef DEBUG
- g_message(G_GNUC_PRETTY_FUNCTION ": %d event handles signalled",
- count);
-#endif
+ event_handle.manual = manual;
+ event_handle.set_count = 0;
+
+ if (initial == TRUE) {
+ if (manual == FALSE) {
+ event_handle.set_count = 1;
+ }
+ }
- if((waitall==TRUE && count==numhandles) ||
- (waitall==FALSE && count>0)) {
- /* done */
- ret=TRUE;
- } else {
- ret=FALSE;
+ handle = _wapi_handle_new (WAPI_HANDLE_EVENT, &event_handle);
+ if (handle == _WAPI_HANDLE_INVALID) {
+ g_warning ("%s: error creating event handle", __func__);
+ SetLastError (ERROR_GEN_FAILURE);
+ return(NULL);
}
+
+ pthread_cleanup_push ((void(*)(void *))_wapi_handle_unlock_handle,
+ handle);
+ thr_ret = _wapi_handle_lock_handle (handle);
+ g_assert (thr_ret == 0);
- for(i=0; i<numhandles; i++) {
- struct _WapiHandle_event *event_handle;
-
- event_handle=g_ptr_array_index(handles, i);
-
- pthread_mutex_unlock(&event_handle->mutex);
+ if (initial == TRUE) {
+ _wapi_handle_set_signal_state (handle, TRUE, FALSE);
}
#ifdef DEBUG
- g_message(G_GNUC_PRETTY_FUNCTION ": Returning %d", ret);
+ g_message("%s: created new event handle %p", __func__, handle);
#endif
- *retcount=count;
- return(ret);
+ thr_ret = _wapi_handle_unlock_handle (handle);
+ g_assert (thr_ret == 0);
+ pthread_cleanup_pop (0);
+
+ return(handle);
}
-static guint32 event_wait_multiple(gpointer data)
+static gpointer namedevent_create (WapiSecurityAttributes *security G_GNUC_UNUSED,
+ gboolean manual, gboolean initial,
+ const gunichar2 *name G_GNUC_UNUSED)
{
- WaitQueueItem *item=(WaitQueueItem *)data;
- struct timespec timeout;
- guint32 iterations;
- guint32 numhandles, count, i;
- gboolean done;
- int ret;
-
- numhandles=item->handles[WAPI_HANDLE_EVENT]->len;
-
-#ifdef DEBUG
- g_message(G_GNUC_PRETTY_FUNCTION
- ": waiting on %d event handles for %d ms", numhandles,
- item->timeout);
-#endif
-
- /* First, check if any of the handles are already
- * signalled. If waitall is specified we only return if all
- * handles have been signalled.
+ struct _WapiHandle_namedevent namedevent_handle = {{{0}}, 0};
+ gpointer handle;
+ gchar *utf8_name;
+ int thr_ret;
+ gpointer ret = NULL;
+ guint32 namelen;
+ gint32 offset;
+
+ /* w32 seems to guarantee that opening named objects can't
+ * race each other
*/
- done=event_count_signalled(item->handles[WAPI_HANDLE_EVENT],
- numhandles, item->waitall, &count);
-
-#ifdef DEBUG
- g_message(G_GNUC_PRETTY_FUNCTION
- ": Preliminary check found %d handles signalled", count);
-#endif
+ thr_ret = _wapi_namespace_lock ();
+ g_assert (thr_ret == 0);
- if(done==TRUE) {
- item->waited[WAPI_HANDLE_EVENT]=TRUE;
- item->waitcount[WAPI_HANDLE_EVENT]=count;
-
- return(count);
- }
-
- /* We'll have to wait then */
+ /* Need to blow away any old errors here, because code tests
+ * for ERROR_ALREADY_EXISTS on success (!) to see if an event
+ * was freshly created
+ */
+ SetLastError (ERROR_SUCCESS);
- pthread_mutex_lock(&event_signal_mutex);
+ utf8_name = g_utf16_to_utf8 (name, -1, NULL, NULL, NULL);
- iterations=0;
- do {
- iterations++;
-
#ifdef DEBUG
- g_message(G_GNUC_PRETTY_FUNCTION ": Wait iteration %d",
- iterations);
+ g_message ("%s: Creating named event [%s]", __func__, utf8_name);
#endif
-
- /* If the timeout isnt INFINITE but greater than 1s,
- * split the timeout into 1s chunks.
- *
- * This is so that ResetEvent() wont block forever if
- * another thread is waiting on multiple events, with
- * some already signalled, and ResetEvent() wants to
- * reset one of the signalled ones. (1s is a bit of a
- * long wait too, this might need to be tuned.)
+
+ offset = _wapi_search_handle_namespace (WAPI_HANDLE_NAMEDEVENT,
+ utf8_name);
+ if (offset == -1) {
+ /* The name has already been used for a different
+ * object.
*/
+ SetLastError (ERROR_INVALID_HANDLE);
+ goto cleanup;
+ } else if (offset != 0) {
+ /* Not an error, but this is how the caller is
+ * informed that the event wasn't freshly created
+ */
+ SetLastError (ERROR_ALREADY_EXISTS);
+ }
+ /* Fall through to create the event handle. */
- if((item->timeout!=INFINITE) &&
- (item->timeout < (iterations*1000))) {
- _wapi_calc_timeout(
- &timeout, item->timeout-((iterations-1)*1000));
- } else {
- _wapi_calc_timeout(&timeout, 1000);
- }
-
- /* Acquire a read lock on all handles so that the
- * signal status can't be reset without us
- * noticing. (PulseEvent and ResetEvent will gain a
- * write lock before changing the status to
- * unsignalled, which will block while one or more
- * threads hold a read lock.)
+ if (offset == 0) {
+ /* A new named event, so create both the private and
+ * shared parts
*/
- for(i=0; i<numhandles; i++) {
- struct _WapiHandle_event *event_handle;
-
- event_handle=g_ptr_array_index(
- item->handles[WAPI_HANDLE_EVENT], i);
-
- pthread_rwlock_rdlock(&event_handle->rwlock);
+
+ if (strlen (utf8_name) < MAX_PATH) {
+ namelen = strlen (utf8_name);
+ } else {
+ namelen = MAX_PATH;
}
-
- ret=pthread_cond_timedwait(&event_signal_cond,
- &event_signal_mutex, &timeout);
-
- if(ret==0) {
- /* Condition was signalled, so hopefully an
- * event is signalled now. (It might not be
- * if it was an auto-reset event and someone
- * else got in before us.)
- */
- done=event_count_signalled(
- item->handles[WAPI_HANDLE_EVENT], numhandles,
- item->waitall, &count);
-#ifdef DEBUG
- g_message(G_GNUC_PRETTY_FUNCTION
- ": signal check found %d handles signalled",
- count);
-#endif
-
- if(done==TRUE) {
-#ifdef DEBUG
- g_message(G_GNUC_PRETTY_FUNCTION
- ": Returning wait success");
-#endif
+ memcpy (&namedevent_handle.sharedns.name, utf8_name, namelen);
- for(i=0; i<numhandles; i++) {
- struct _WapiHandle_event *event_handle;
-
- event_handle=g_ptr_array_index(item->handles[WAPI_HANDLE_EVENT], i);
-
- pthread_rwlock_unlock(&event_handle->rwlock);
- }
-
- item->waited[WAPI_HANDLE_EVENT]=TRUE;
- item->waitcount[WAPI_HANDLE_EVENT]=count;
-
- return(count);
+ namedevent_handle.manual = manual;
+ namedevent_handle.set_count = 0;
+
+ if (initial == TRUE) {
+ if (manual == FALSE) {
+ namedevent_handle.set_count = 1;
}
- } else {
-#ifdef DEBUG
- g_message(G_GNUC_PRETTY_FUNCTION ": Wait error %s",
- strerror(ret));
-#endif
}
-
-#ifdef DEBUG
- g_message(G_GNUC_PRETTY_FUNCTION
- ": Still waiting for more event handles");
-#endif
- /* Drop the rwlocks briefly so that another thread has
- * a chance to reset any of the events
+
+ handle = _wapi_handle_new (WAPI_HANDLE_NAMEDEVENT,
+ &namedevent_handle);
+ } else {
+ /* A new reference to an existing named event, so just
+ * create the private part
*/
- for(i=0; i<numhandles; i++) {
- struct _WapiHandle_event *event_handle;
-
- event_handle=g_ptr_array_index(
- item->handles[WAPI_HANDLE_EVENT], i);
-
- pthread_rwlock_unlock(&event_handle->rwlock);
- }
- } while((item->timeout==INFINITE) ||
- (item->timeout > (iterations * 1000)));
-
- /* Timeout or other error */
+ handle = _wapi_handle_new_from_offset (WAPI_HANDLE_NAMEDEVENT,
+ offset, TRUE);
+ }
- for(i=0; i<numhandles; i++) {
- struct _WapiHandle_event *event_handle;
-
- event_handle=g_ptr_array_index(
- item->handles[WAPI_HANDLE_EVENT], i);
-
- pthread_rwlock_unlock(&event_handle->rwlock);
+ if (handle == _WAPI_HANDLE_INVALID) {
+ g_warning ("%s: error creating event handle", __func__);
+ SetLastError (ERROR_GEN_FAILURE);
+ goto cleanup;
}
+ ret = handle;
- pthread_mutex_unlock(&event_signal_mutex);
+ if (offset == 0) {
+ /* Set the initial state, as this is a completely new
+ * handle
+ */
+ thr_ret = _wapi_handle_lock_shared_handles ();
+ g_assert (thr_ret == 0);
+
+ if (initial == TRUE) {
+ _wapi_shared_handle_set_signal_state (handle, TRUE);
+ }
+ _wapi_handle_unlock_shared_handles ();
+ }
+
#ifdef DEBUG
- g_message(G_GNUC_PRETTY_FUNCTION ": Returning wait failed");
+ g_message ("%s: returning event handle %p", __func__, handle);
#endif
+
+cleanup:
+ g_free (utf8_name);
+
+ _wapi_namespace_unlock (NULL);
- item->waited[WAPI_HANDLE_EVENT]=TRUE;
- item->waitcount[WAPI_HANDLE_MUTEX]=0;
-
- return(0);
+ return(ret);
+
}
+
/**
* CreateEvent:
* @security: Ignored for now.
*
* Return value: A new handle, or %NULL on error.
*/
-WapiHandle *CreateEvent(WapiSecurityAttributes *security G_GNUC_UNUSED, gboolean manual,
- gboolean initial, const guchar *name G_GNUC_UNUSED)
+gpointer CreateEvent(WapiSecurityAttributes *security G_GNUC_UNUSED,
+ gboolean manual, gboolean initial,
+ const gunichar2 *name G_GNUC_UNUSED)
+{
+ mono_once (&event_ops_once, event_ops_init);
+
+ if (name == NULL) {
+ return(event_create (security, manual, initial));
+ } else {
+ return(namedevent_create (security, manual, initial, name));
+ }
+}
+
+static gboolean event_pulse (gpointer handle)
{
struct _WapiHandle_event *event_handle;
- WapiHandle *handle;
+ gboolean ok;
+ int thr_ret;
+
+ ok = _wapi_lookup_handle (handle, WAPI_HANDLE_EVENT,
+ (gpointer *)&event_handle);
+ if (ok == FALSE) {
+ g_warning ("%s: error looking up event handle %p", __func__,
+ handle);
+ return(FALSE);
+ }
+
+ pthread_cleanup_push ((void(*)(void *))_wapi_handle_unlock_handle,
+ handle);
+ thr_ret = _wapi_handle_lock_handle (handle);
+ g_assert (thr_ret == 0);
+
+#ifdef DEBUG
+ g_message ("%s: Pulsing event handle %p", __func__, handle);
+#endif
+
+ if (event_handle->manual == TRUE) {
+ _wapi_handle_set_signal_state (handle, TRUE, TRUE);
+ } else {
+ event_handle->set_count = 1;
+ _wapi_handle_set_signal_state (handle, TRUE, FALSE);
+ }
+
+ thr_ret = _wapi_handle_unlock_handle (handle);
+ g_assert (thr_ret == 0);
- event_handle=(struct _WapiHandle_event *)g_new0(struct _WapiHandle_event, 1);
- handle=(WapiHandle *)event_handle;
- _WAPI_HANDLE_INIT(handle, WAPI_HANDLE_EVENT, event_ops);
+ pthread_cleanup_pop (0);
- pthread_mutex_init(&event_handle->mutex, NULL);
- pthread_cond_init(&event_handle->cond, NULL);
- pthread_rwlock_init(&event_handle->rwlock, NULL);
- event_handle->manual=manual;
+ if (event_handle->manual == TRUE) {
+ /* For a manual-reset event, we're about to try and
+ * get the handle lock again, so give other threads a
+ * chance
+ */
+ sched_yield ();
- if(initial==TRUE) {
- handle->signalled=TRUE;
+ /* Reset the handle signal state */
+ /* I'm not sure whether or not we need a barrier here
+ * to make sure that all threads waiting on the event
+ * have proceeded. Currently we rely on broadcasting
+ * a condition.
+ */
+#ifdef DEBUG
+ g_message ("%s: Obtained write lock on event handle %p",
+ __func__, handle);
+#endif
+
+ pthread_cleanup_push ((void(*)(void *))_wapi_handle_unlock_handle, handle);
+ thr_ret = _wapi_handle_lock_handle (handle);
+ g_assert (thr_ret == 0);
+
+ _wapi_handle_set_signal_state (handle, FALSE, FALSE);
+
+ thr_ret = _wapi_handle_unlock_handle (handle);
+ g_assert (thr_ret == 0);
+ pthread_cleanup_pop (0);
+ }
+
+ return(TRUE);
+}
+
+static gboolean namedevent_pulse (gpointer handle)
+{
+ struct _WapiHandle_namedevent *namedevent_handle;
+ gboolean ok;
+ int thr_ret;
+
+ ok = _wapi_lookup_handle (handle, WAPI_HANDLE_NAMEDEVENT,
+ (gpointer *)&namedevent_handle);
+ if (ok == FALSE) {
+ g_warning ("%s: error looking up named event handle %p",
+ __func__, handle);
+ return(FALSE);
}
+ thr_ret = _wapi_handle_lock_shared_handles ();
+ g_assert (thr_ret == 0);
+
#ifdef DEBUG
- g_message(G_GNUC_PRETTY_FUNCTION ": created new event handle %p",
- handle);
+ g_message ("%s: Pulsing named event handle %p", __func__, handle);
#endif
- return(handle);
+ if (namedevent_handle->manual == TRUE) {
+ _wapi_shared_handle_set_signal_state (handle, TRUE);
+ } else {
+ namedevent_handle->set_count = 1;
+ _wapi_shared_handle_set_signal_state (handle, TRUE);
+ }
+
+ _wapi_handle_unlock_shared_handles ();
+
+ if (namedevent_handle->manual == TRUE) {
+ /* For a manual-reset event, we're about to try and
+ * get the handle lock again, so give other processes
+ * a chance
+ */
+ _wapi_handle_spin (200);
+
+ /* Reset the handle signal state */
+ /* I'm not sure whether or not we need a barrier here
+ * to make sure that all threads waiting on the event
+ * have proceeded. Currently we rely on waiting for
+ * twice the shared handle poll interval.
+ */
+#ifdef DEBUG
+ g_message ("%s: Obtained write lock on event handle %p",
+ __func__, handle);
+#endif
+
+ thr_ret = _wapi_handle_lock_shared_handles ();
+ g_assert (thr_ret == 0);
+
+ _wapi_shared_handle_set_signal_state (handle, FALSE);
+
+ _wapi_handle_unlock_shared_handles ();
+ }
+
+ return(TRUE);
}
/**
* Return value: %TRUE on success, %FALSE otherwise. (Currently only
* ever returns %TRUE).
*/
-gboolean PulseEvent(WapiHandle *handle)
+gboolean PulseEvent(gpointer handle)
{
- struct _WapiHandle_event *event_handle=(struct _WapiHandle_event *)handle;
+ WapiHandleType type;
+
+ if (handle == NULL) {
+ SetLastError (ERROR_INVALID_HANDLE);
+ return(FALSE);
+ }
+
+ type = _wapi_handle_type (handle);
- pthread_mutex_lock(&event_handle->mutex);
+ if (event_ops[type].pulse == NULL) {
+ SetLastError (ERROR_INVALID_HANDLE);
+ return(FALSE);
+ }
+
+ return(event_ops[type].pulse (handle));
+}
+
+static gboolean event_reset (gpointer handle)
+{
+ struct _WapiHandle_event *event_handle;
+ gboolean ok;
+ int thr_ret;
+
+ ok = _wapi_lookup_handle (handle, WAPI_HANDLE_EVENT,
+ (gpointer *)&event_handle);
+ if (ok == FALSE) {
+ g_warning ("%s: error looking up event handle %p",
+ __func__, handle);
+ return(FALSE);
+ }
#ifdef DEBUG
- g_message(G_GNUC_PRETTY_FUNCTION ": Pulsing event handle %p", handle);
+ g_message ("%s: Resetting event handle %p", __func__, handle);
#endif
- handle->signalled=TRUE;
+ pthread_cleanup_push ((void(*)(void *))_wapi_handle_unlock_handle,
+ handle);
+ thr_ret = _wapi_handle_lock_handle (handle);
+ g_assert (thr_ret == 0);
- /* Tell everyone blocking on WaitForSingleObject */
- if(event_handle->manual==TRUE) {
- pthread_cond_broadcast(&event_handle->cond);
- } else {
- pthread_cond_signal(&event_handle->cond);
- }
- pthread_mutex_unlock(&event_handle->mutex);
-
+ if (_wapi_handle_issignalled (handle) == FALSE) {
#ifdef DEBUG
- g_message(G_GNUC_PRETTY_FUNCTION
- ": Informed single waits for event handle %p", handle);
+ g_message ("%s: No need to reset event handle %p", __func__,
+ handle);
#endif
-
- /* Tell everyone blocking on WaitForMultipleObjects */
- pthread_mutex_lock(&event_signal_mutex);
- pthread_cond_broadcast(&event_signal_cond);
- pthread_mutex_unlock(&event_signal_mutex);
-
+ } else {
#ifdef DEBUG
- g_message(G_GNUC_PRETTY_FUNCTION
- ": Informed multiple waits for event handles");
+ g_message ("%s: Obtained write lock on event handle %p",
+ __func__, handle);
#endif
+
+ _wapi_handle_set_signal_state (handle, FALSE, FALSE);
+ }
+
+ event_handle->set_count = 0;
+
+ thr_ret = _wapi_handle_unlock_handle (handle);
+ g_assert (thr_ret == 0);
- /* Reset the handle signal state */
+ pthread_cleanup_pop (0);
+
+ return(TRUE);
+}
- /* This rwlock blocks until no other thread holds a read lock.
- * This ensures that we can't reset the event until every
- * waiting thread has had a chance to examine it
- */
- pthread_rwlock_wrlock(&event_handle->rwlock);
+static gboolean namedevent_reset (gpointer handle)
+{
+ struct _WapiHandle_namedevent *namedevent_handle;
+ gboolean ok;
+ int thr_ret;
+
+ ok = _wapi_lookup_handle (handle, WAPI_HANDLE_NAMEDEVENT,
+ (gpointer *)&namedevent_handle);
+ if (ok == FALSE) {
+ g_warning ("%s: error looking up named event handle %p",
+ __func__, handle);
+ return(FALSE);
+ }
#ifdef DEBUG
- g_message(G_GNUC_PRETTY_FUNCTION
- ": Obtained write lock on event handle %p", handle);
+ g_message ("%s: Resetting named event handle %p", __func__, handle);
#endif
- handle->signalled=FALSE;
- pthread_rwlock_unlock(&event_handle->rwlock);
+ thr_ret = _wapi_handle_lock_shared_handles ();
+ g_assert (thr_ret == 0);
+
+ if (_wapi_handle_issignalled (handle) == FALSE) {
+#ifdef DEBUG
+ g_message ("%s: No need to reset named event handle %p",
+ __func__, handle);
+#endif
+ } else {
+#ifdef DEBUG
+ g_message ("%s: Obtained write lock on named event handle %p",
+ __func__, handle);
+#endif
+ _wapi_shared_handle_set_signal_state (handle, FALSE);
+ }
+
+ namedevent_handle->set_count = 0;
+
+ _wapi_handle_unlock_shared_handles ();
+
return(TRUE);
}
* Return value: %TRUE on success, %FALSE otherwise. (Currently only
* ever returns %TRUE).
*/
-gboolean ResetEvent(WapiHandle *handle)
+gboolean ResetEvent(gpointer handle)
+{
+ WapiHandleType type;
+
+ if (handle == NULL) {
+ SetLastError (ERROR_INVALID_HANDLE);
+ return(FALSE);
+ }
+
+ type = _wapi_handle_type (handle);
+
+ if (event_ops[type].reset == NULL) {
+ SetLastError (ERROR_INVALID_HANDLE);
+ return(FALSE);
+ }
+
+ return(event_ops[type].reset (handle));
+}
+
+static gboolean event_set (gpointer handle)
{
- struct _WapiHandle_event *event_handle=(struct _WapiHandle_event *)handle;
+ struct _WapiHandle_event *event_handle;
+ gboolean ok;
+ int thr_ret;
+
+ ok = _wapi_lookup_handle (handle, WAPI_HANDLE_EVENT,
+ (gpointer *)&event_handle);
+ if (ok == FALSE) {
+ g_warning ("%s: error looking up event handle %p", __func__,
+ handle);
+ return(FALSE);
+ }
+
+ pthread_cleanup_push ((void(*)(void *))_wapi_handle_unlock_handle,
+ handle);
+ thr_ret = _wapi_handle_lock_handle (handle);
+ g_assert (thr_ret == 0);
#ifdef DEBUG
- g_message(G_GNUC_PRETTY_FUNCTION ": Resetting event handle %p",
- handle);
+ g_message ("%s: Setting event handle %p", __func__, handle);
#endif
- /* Test for the current state, because another thread might be
- * waiting forever on an unsignalled event with the read lock
- * held. Theres no point going for the write lock if we dont
- * need it.
- */
- pthread_mutex_lock(&event_handle->mutex);
- if(handle->signalled==FALSE) {
+ if (event_handle->manual == TRUE) {
+ _wapi_handle_set_signal_state (handle, TRUE, TRUE);
+ } else {
+ event_handle->set_count = 1;
+ _wapi_handle_set_signal_state (handle, TRUE, FALSE);
+ }
-#ifdef DEBUG
- g_message(G_GNUC_PRETTY_FUNCTION
- ": No need to reset event handle %p", handle);
-#endif
+ thr_ret = _wapi_handle_unlock_handle (handle);
+ g_assert (thr_ret == 0);
+
+ pthread_cleanup_pop (0);
- pthread_mutex_unlock(&event_handle->mutex);
- return(TRUE);
+ return(TRUE);
+}
+
+static gboolean namedevent_set (gpointer handle)
+{
+ struct _WapiHandle_namedevent *namedevent_handle;
+ gboolean ok;
+ int thr_ret;
+
+ ok = _wapi_lookup_handle (handle, WAPI_HANDLE_NAMEDEVENT,
+ (gpointer *)&namedevent_handle);
+ if (ok == FALSE) {
+ g_warning ("%s: error looking up named event handle %p",
+ __func__, handle);
+ return(FALSE);
}
- pthread_mutex_unlock(&event_handle->mutex);
- pthread_rwlock_wrlock(&event_handle->rwlock);
+ thr_ret = _wapi_handle_lock_shared_handles ();
+ g_assert (thr_ret == 0);
#ifdef DEBUG
- g_message(G_GNUC_PRETTY_FUNCTION
- ": Obtained write lock on event handle %p", handle);
+ g_message ("%s: Setting named event handle %p", __func__, handle);
#endif
- handle->signalled=FALSE;
- pthread_rwlock_unlock(&event_handle->rwlock);
-
+ if (namedevent_handle->manual == TRUE) {
+ _wapi_shared_handle_set_signal_state (handle, TRUE);
+ } else {
+ namedevent_handle->set_count = 1;
+ _wapi_shared_handle_set_signal_state (handle, TRUE);
+ }
+
+ _wapi_handle_unlock_shared_handles ();
+
return(TRUE);
}
* Return value: %TRUE on success, %FALSE otherwise. (Currently only
* ever returns %TRUE).
*/
-gboolean SetEvent(WapiHandle *handle)
+gboolean SetEvent(gpointer handle)
+{
+ WapiHandleType type;
+
+ if (handle == NULL) {
+ SetLastError (ERROR_INVALID_HANDLE);
+ return(FALSE);
+ }
+
+ type = _wapi_handle_type (handle);
+
+ if (event_ops[type].set == NULL) {
+ SetLastError (ERROR_INVALID_HANDLE);
+ return(FALSE);
+ }
+
+ return(event_ops[type].set (handle));
+}
+
+gpointer OpenEvent (guint32 access G_GNUC_UNUSED, gboolean inherit G_GNUC_UNUSED, const gunichar2 *name)
{
- struct _WapiHandle_event *event_handle=(struct _WapiHandle_event *)handle;
+ gpointer handle;
+ gchar *utf8_name;
+ int thr_ret;
+ gpointer ret = NULL;
+ gint32 offset;
- pthread_mutex_lock(&event_handle->mutex);
+ mono_once (&event_ops_once, event_ops_init);
+
+ /* w32 seems to guarantee that opening named objects can't
+ * race each other
+ */
+ thr_ret = _wapi_namespace_lock ();
+ g_assert (thr_ret == 0);
+ utf8_name = g_utf16_to_utf8 (name, -1, NULL, NULL, NULL);
+
#ifdef DEBUG
- g_message(G_GNUC_PRETTY_FUNCTION ": Setting event handle %p", handle);
+ g_message ("%s: Opening named event [%s]", __func__, utf8_name);
#endif
-
- handle->signalled=TRUE;
- /* Tell everyone blocking on WaitForSingleObject */
- if(event_handle->manual==TRUE) {
- pthread_cond_broadcast(&event_handle->cond);
- } else {
- pthread_cond_signal(&event_handle->cond);
+ offset = _wapi_search_handle_namespace (WAPI_HANDLE_NAMEDEVENT,
+ utf8_name);
+ if (offset == -1) {
+ /* The name has already been used for a different
+ * object.
+ */
+ SetLastError (ERROR_INVALID_HANDLE);
+ goto cleanup;
+ } else if (offset == 0) {
+ /* This name doesn't exist */
+ SetLastError (ERROR_FILE_NOT_FOUND); /* yes, really */
+ goto cleanup;
}
- pthread_mutex_unlock(&event_handle->mutex);
-#ifdef DEBUG
- g_message(G_GNUC_PRETTY_FUNCTION
- ": Informed single waits for event handle %p", handle);
-#endif
+ /* A new reference to an existing named event, so just create
+ * the private part
+ */
+ handle = _wapi_handle_new_from_offset (WAPI_HANDLE_NAMEDEVENT, offset,
+ TRUE);
- /* Tell everyone blocking on WaitForMultipleObjects */
- pthread_mutex_lock(&event_signal_mutex);
- pthread_cond_broadcast(&event_signal_cond);
- pthread_mutex_unlock(&event_signal_mutex);
+ if (handle == _WAPI_HANDLE_INVALID) {
+ g_warning ("%s: error opening named event handle", __func__);
+ SetLastError (ERROR_GEN_FAILURE);
+ goto cleanup;
+ }
+ ret = handle;
#ifdef DEBUG
- g_message(G_GNUC_PRETTY_FUNCTION
- ": Informed multiple waits for event handles");
+ g_message ("%s: returning named event handle %p", __func__, handle);
#endif
+
+cleanup:
+ g_free (utf8_name);
+
+ _wapi_namespace_unlock (NULL);
- return(TRUE);
-}
+ return(ret);
+}