Merge pull request #725 from knocte/threadpool_init
[mono.git] / mono / io-layer / events.c
index 829f8b8e2433d87420b065bfb8abff33d68b2c2a..fa3ae9d637c6f1469fa08e95e3f4a4d25426420c 100644 (file)
+/*
+ * 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>
 
-#include "mono-mutex.h"
+#include <mono/io-layer/event-private.h>
 
-#undef DEBUG
+#include <mono/utils/mono-mutex.h>
+#if 0
+#define DEBUG(...) g_message(__VA_ARGS__)
+#else
+#define DEBUG(...)
+#endif
 
-/* 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;
-       mono_mutex_t mutex;
-       pthread_cond_t cond;
-       pthread_rwlock_t rwlock;
-       gboolean manual;
-};
+static void event_signal(gpointer handle);
+static gboolean event_own (gpointer handle);
 
-/* event_wait_multiple() uses the global condition to signal that an
- * event has been set
- */
-static mono_mutex_t event_signal_mutex = MONO_MUTEX_INITIALIZER;
-static pthread_cond_t event_signal_cond = PTHREAD_COND_INITIALIZER;
-
-static void event_close(WapiHandle *handle);
-static gboolean event_wait(WapiHandle *handle, WapiHandle *signal, guint32 ms);
-static guint32 event_wait_multiple(gpointer data);
-static void event_signal(WapiHandle *handle);
-
-static struct _WapiHandleOps event_ops = {
-       event_close,            /* close */
-       NULL,                   /* getfiletype */
-       NULL,                   /* readfile */
-       NULL,                   /* writefile */
-       NULL,                   /* flushfile */
-       NULL,                   /* seek */
-       NULL,                   /* setendoffile */
-       NULL,                   /* getfilesize */
-       NULL,                   /* getfiletime */
-       NULL,                   /* setfiletime */
-       event_wait,             /* wait */
-       event_wait_multiple,    /* wait_multiple */
+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 */
+};
+
+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;
-       
-#ifdef DEBUG
-       g_message(G_GNUC_PRETTY_FUNCTION ": closing event handle %p",
-                 event_handle);
-#endif
+       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},
+};
 
-       mono_mutex_destroy(&event_handle->mutex);
-       pthread_cond_destroy(&event_handle->cond);
-       pthread_rwlock_destroy(&event_handle->rwlock);
+void _wapi_event_details (gpointer handle_info)
+{
+       struct _WapiHandle_event *event = (struct _WapiHandle_event *)handle_info;
+       
+       g_print ("manual: %s", event->manual?"TRUE":"FALSE");
 }
 
-static gboolean event_wait(WapiHandle *handle, WapiHandle *signal, guint32 ms)
-{
-       struct _WapiHandle_event *event_handle=(struct _WapiHandle_event *)handle;
-       struct timespec timeout;
-       int ret;
+static mono_once_t event_ops_once=MONO_ONCE_INIT;
 
-#ifdef DEBUG
-       g_message(G_GNUC_PRETTY_FUNCTION
-                 ": waiting on event handle %p for %d ms", handle, ms);
-#endif
+static void event_ops_init (void)
+{
+       _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);
+}
 
-       mono_mutex_lock(&event_handle->mutex);
+static void event_signal(gpointer handle)
+{
+       SetEvent(handle);
+}
 
-       /* Signal this handle after we have obtained the event lock */
-       if(signal!=NULL) {
-               signal->ops->signal(signal);
+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);
        }
        
-       /* First check if the handle is already signalled */
-       if(handle->signalled==TRUE) {
-               /* If this is an auto-reset event, reset the state to
-                * unsignalled
-                */
-       
-#ifdef DEBUG
-               g_message(G_GNUC_PRETTY_FUNCTION
-                         ": event handle %p already signalled", handle);
-#endif
+       DEBUG("%s: owning event handle %p", __func__, handle);
 
-               if(event_handle->manual==FALSE) {
-#ifdef DEBUG
-                       g_message(G_GNUC_PRETTY_FUNCTION
-                                 ": resetting auto event handle %p", handle);
-#endif
-                       handle->signalled=FALSE;
-               }
-               mono_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=mono_cond_wait(&event_handle->cond,
-                                  &event_handle->mutex);
-       } else {
-               ret=mono_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);
-                       mono_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);
-#endif
+       DEBUG ("%s: owning named event handle %p", __func__, handle);
 
-               /* 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);
-       mono_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(WaitQueueItem *item, 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(
-                       item->handles[WAPI_HANDLE_EVENT], i);
-               
-               ret=mono_mutex_trylock(&event_handle->mutex);
-               if(ret!=0) {
-                       /* Bummer */
-                       while(i--) {
-                               event_handle=g_ptr_array_index(
-                                       item->handles[WAPI_HANDLE_EVENT], i);
-                               mono_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);
+
+       DEBUG ("%s: Creating unnamed event", __func__);
+       
+       event_handle.manual = manual;
+       event_handle.set_count = 0;
 
-                       /* 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;
+       if (initial == TRUE) {
+               if (manual == FALSE) {
+                       event_handle.set_count = 1;
                }
        }
        
-#ifdef DEBUG
-       g_message(G_GNUC_PRETTY_FUNCTION ": Locked all event handles");
-#endif
-       
-       count=_wapi_handle_count_signalled(item, WAPI_HANDLE_EVENT);
-       
-#ifdef DEBUG
-       g_message(G_GNUC_PRETTY_FUNCTION ": %d event handles signalled",
-                 count);
-#endif
-       
-       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(
-                       item->handles[WAPI_HANDLE_EVENT], i);
-               
-               mono_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);
-#endif
+       DEBUG("%s: created new event handle %p", __func__, handle);
 
-       *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, 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);
-       }
+       /* 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);
        
-       /* We'll have to wait then */
+       utf8_name = g_utf16_to_utf8 (name, -1, NULL, NULL, NULL);
        
-       mono_mutex_lock(&event_signal_mutex);
+       DEBUG ("%s: Creating named event [%s]", __func__, utf8_name);
        
-       iterations=0;
-       do {
-               iterations++;
-               
-#ifdef DEBUG
-               g_message(G_GNUC_PRETTY_FUNCTION ": Wait iteration %d",
-                         iterations);
-#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=mono_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, 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
                }
+               
+               handle = _wapi_handle_new (WAPI_HANDLE_NAMEDEVENT,
+                                          &namedevent_handle);
+       } else {
+               /* 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);
+       }
+       
+       if (handle == _WAPI_HANDLE_INVALID) {
+               g_warning ("%s: error creating event handle", __func__);
+               SetLastError (ERROR_GEN_FAILURE);
+               goto cleanup;
+       }
+       ret = handle;
 
-#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
+       if (offset == 0) {
+               /* Set the initial state, as this is a completely new
+                * handle
                 */
-               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);
+               thr_ret = _wapi_handle_lock_shared_handles ();
+               g_assert (thr_ret == 0);
+       
+               if (initial == TRUE) {
+                       _wapi_shared_handle_set_signal_state (handle, TRUE);
                }
-       } while((item->timeout==INFINITE) ||
-               (item->timeout > (iterations * 1000)));
 
-       /* Timeout or other error */
-       
-       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);
+               _wapi_handle_unlock_shared_handles ();
        }
+       
+       DEBUG ("%s: returning event handle %p", __func__, handle);
 
-       mono_mutex_unlock(&event_signal_mutex);
+cleanup:
+       g_free (utf8_name);
 
-#ifdef DEBUG
-       g_message(G_GNUC_PRETTY_FUNCTION ": Returning wait failed");
-#endif
-       
-       item->waited[WAPI_HANDLE_EVENT]=TRUE;
-       item->waitcount[WAPI_HANDLE_MUTEX]=0;
+       _wapi_namespace_unlock (NULL);
        
-       return(0);
-}
+       return(ret);
 
-static void event_signal(WapiHandle *handle)
-{
-       ResetEvent(handle);
 }
 
+
 /**
  * CreateEvent:
  * @security: Ignored for now.
@@ -468,31 +337,135 @@ static void event_signal(WapiHandle *handle)
  *
  * 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);
+       }
        
-       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_push ((void(*)(void *))_wapi_handle_unlock_handle,
+                             handle);
+       thr_ret = _wapi_handle_lock_handle (handle);
+       g_assert (thr_ret == 0);
+
+       DEBUG ("%s: Pulsing event handle %p", __func__, handle);
+
+       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);
+       
+       pthread_cleanup_pop (0);
        
-       mono_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.
+                */
+               DEBUG ("%s: Obtained write lock on event handle %p",
+                          __func__, handle);
+
+               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);
        }
        
-#ifdef DEBUG
-       g_message(G_GNUC_PRETTY_FUNCTION ": created new event handle %p",
-                 handle);
-#endif
+       thr_ret = _wapi_handle_lock_shared_handles ();
+       g_assert (thr_ret == 0);
 
-       return(handle);
+       DEBUG ("%s: Pulsing named event handle %p", __func__, 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.
+                */
+               DEBUG ("%s: Obtained write lock on event handle %p",
+                          __func__, handle);
+
+               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);
 }
 
 /**
@@ -510,57 +483,99 @@ WapiHandle *CreateEvent(WapiSecurityAttributes *security G_GNUC_UNUSED, gboolean
  * 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);
+       }
        
-       mono_mutex_lock(&event_handle->mutex);
+       type = _wapi_handle_type (handle);
+       
+       if (event_ops[type].pulse == NULL) {
+               SetLastError (ERROR_INVALID_HANDLE);
+               return(FALSE);
+       }
+       
+       return(event_ops[type].pulse (handle));
+}
 
-#ifdef DEBUG
-       g_message(G_GNUC_PRETTY_FUNCTION ": Pulsing event handle %p", handle);
-#endif
+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);
+       }
 
-       handle->signalled=TRUE;
+       DEBUG ("%s: Resetting event handle %p", __func__, handle);
+
+       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);
+       if (_wapi_handle_issignalled (handle) == FALSE) {
+               DEBUG ("%s: No need to reset event handle %p", __func__,
+                          handle);
        } else {
-               pthread_cond_signal(&event_handle->cond);
-       }
-       mono_mutex_unlock(&event_handle->mutex);
+               DEBUG ("%s: Obtained write lock on event handle %p",
+                          __func__, handle);
 
-#ifdef DEBUG
-       g_message(G_GNUC_PRETTY_FUNCTION
-                 ": Informed single waits for event handle %p", handle);
-#endif
+               _wapi_handle_set_signal_state (handle, FALSE, FALSE);
+       }
        
-       /* Tell everyone blocking on WaitForMultipleObjects */
-       mono_mutex_lock(&event_signal_mutex);
-       pthread_cond_broadcast(&event_signal_cond);
-       mono_mutex_unlock(&event_signal_mutex);
-
-#ifdef DEBUG
-       g_message(G_GNUC_PRETTY_FUNCTION
-                 ": Informed multiple waits for event handles");
-#endif
+       event_handle->set_count = 0;
+       
+       thr_ret = _wapi_handle_unlock_handle (handle);
+       g_assert (thr_ret == 0);
+       
+       pthread_cleanup_pop (0);
        
-       /* Reset the handle signal state */
+       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);
-#endif
+       DEBUG ("%s: Resetting named event handle %p", __func__, handle);
 
-       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) {
+               DEBUG ("%s: No need to reset named event handle %p",
+                          __func__, handle);
+       } else {
+               DEBUG ("%s: Obtained write lock on named event handle %p",
+                          __func__, handle);
 
+               _wapi_shared_handle_set_signal_state (handle, FALSE);
+       }
+       
+       namedevent_handle->set_count = 0;
+       
+       _wapi_handle_unlock_shared_handles ();
+       
        return(TRUE);
 }
 
@@ -573,43 +588,89 @@ gboolean PulseEvent(WapiHandle *handle)
  * Return value: %TRUE on success, %FALSE otherwise.  (Currently only
  * ever returns %TRUE).
  */
-gboolean ResetEvent(WapiHandle *handle)
+gboolean ResetEvent(gpointer handle)
 {
-       struct _WapiHandle_event *event_handle=(struct _WapiHandle_event *)handle;
-
-#ifdef DEBUG
-       g_message(G_GNUC_PRETTY_FUNCTION ": Resetting event handle %p",
-                 handle);
-#endif
+       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));
+}
 
-       /* 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.
-        */
-       mono_mutex_lock(&event_handle->mutex);
-       if(handle->signalled==FALSE) {
+static gboolean event_set (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);
+       }
+       
+       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
-                         ": No need to reset event handle %p", handle);
-#endif
+       DEBUG ("%s: Setting event handle %p", __func__, handle);
 
-               mono_mutex_unlock(&event_handle->mutex);
-               return(TRUE);
+       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);
        }
-       mono_mutex_unlock(&event_handle->mutex);
+
+       thr_ret = _wapi_handle_unlock_handle (handle);
+       g_assert (thr_ret == 0);
        
-       pthread_rwlock_wrlock(&event_handle->rwlock);
+       pthread_cleanup_pop (0);
 
-#ifdef DEBUG
-       g_message(G_GNUC_PRETTY_FUNCTION
-                 ": Obtained write lock on event handle %p", handle);
-#endif
+       return(TRUE);
+}
 
-       handle->signalled=FALSE;
-       pthread_rwlock_unlock(&event_handle->rwlock);
+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);
+       }
        
+       thr_ret = _wapi_handle_lock_shared_handles ();
+       g_assert (thr_ret == 0);
+
+       DEBUG ("%s: Setting named event handle %p", __func__, 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 ();
+
        return(TRUE);
 }
 
@@ -627,41 +688,79 @@ gboolean ResetEvent(WapiHandle *handle)
  * Return value: %TRUE on success, %FALSE otherwise.  (Currently only
  * ever returns %TRUE).
  */
-gboolean SetEvent(WapiHandle *handle)
+gboolean SetEvent(gpointer handle)
 {
-       struct _WapiHandle_event *event_handle=(struct _WapiHandle_event *)handle;
+       WapiHandleType type;
+       
+       if (handle == NULL) {
+               SetLastError (ERROR_INVALID_HANDLE);
+               return(FALSE);
+       }
        
-       mono_mutex_lock(&event_handle->mutex);
+       type = _wapi_handle_type (handle);
+       
+       if (event_ops[type].set == NULL) {
+               SetLastError (ERROR_INVALID_HANDLE);
+               return(FALSE);
+       }
+       
+       return(event_ops[type].set (handle));
+}
 
-#ifdef DEBUG
-       g_message(G_GNUC_PRETTY_FUNCTION ": Setting event handle %p", handle);
-#endif
+gpointer OpenEvent (guint32 access G_GNUC_UNUSED, gboolean inherit G_GNUC_UNUSED, const gunichar2 *name)
+{
+       gpointer handle;
+       gchar *utf8_name;
+       int thr_ret;
+       gpointer ret = NULL;
+       gint32 offset;
+       
+       mono_once (&event_ops_once, event_ops_init);
 
-       handle->signalled=TRUE;
+       /* 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);
        
-       /* Tell everyone blocking on WaitForSingleObject */
-       if(event_handle->manual==TRUE) {
-               pthread_cond_broadcast(&event_handle->cond);
-       } else {
-               pthread_cond_signal(&event_handle->cond);
+       DEBUG ("%s: Opening named event [%s]", __func__, utf8_name);
+       
+       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;
        }
-       mono_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 */
-       mono_mutex_lock(&event_signal_mutex);
-       pthread_cond_broadcast(&event_signal_cond);
-       mono_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");
-#endif
+       DEBUG ("%s: returning named event handle %p", __func__, handle);
+
+cleanup:
+       g_free (utf8_name);
+
+       _wapi_namespace_unlock (NULL);
        
-       return(TRUE);
-}
+       return(ret);
 
+}