[runtime] Use getrlimit () to obtain the size of the fd table instead of getdtablesiz...
[mono.git] / mono / io-layer / handles.c
index 48e2613c15e559a748aad90a226fb0364458f455..cb0033f5a1ba613a88c4f7a3b3b93f69ab764588 100644 (file)
@@ -4,7 +4,8 @@
  * Author:
  *     Dick Porter (dick@ximian.com)
  *
- * (C) 2002-2006 Novell, Inc.
+ * (C) 2002-2011 Novell, Inc.
+ * Copyright 2011 Xamarin Inc
  */
 
 #include <config.h>
 #include <pthread.h>
 #include <errno.h>
 #include <unistd.h>
+#include <signal.h>
 #include <string.h>
 #include <sys/types.h>
-#include <sys/socket.h>
-#include <sys/un.h>
-#include <sys/mman.h>
-#include <dirent.h>
+#ifdef HAVE_SYS_SOCKET_H
+#  include <sys/socket.h>
+#endif
+#ifdef HAVE_SYS_UN_H
+#  include <sys/un.h>
+#endif
+#ifdef HAVE_SYS_MMAN_H
+#  include <sys/mman.h>
+#endif
+#ifdef HAVE_DIRENT_H
+#  include <dirent.h>
+#endif
 #include <sys/stat.h>
-
-#include <mono/os/gc_wrapper.h>
+#ifdef HAVE_SYS_RESOURCE_H
+#  include <sys/resource.h>
+#endif
 
 #include <mono/io-layer/wapi.h>
 #include <mono/io-layer/wapi-private.h>
 #include <mono/io-layer/handles-private.h>
-#include <mono/io-layer/mono-mutex.h>
 #include <mono/io-layer/misc-private.h>
 #include <mono/io-layer/shared.h>
 #include <mono/io-layer/collection.h>
 #include <mono/io-layer/process-private.h>
 
-#undef DEBUG
+#include <mono/utils/mono-mutex.h>
 #undef DEBUG_REFS
 
+#if 0
+#define DEBUG(...) g_message(__VA_ARGS__)
+#else
+#define DEBUG(...)
+#endif
+
 static void (*_wapi_handle_ops_get_close_func (WapiHandleType type))(gpointer, gpointer);
 
 static WapiHandleCapability handle_caps[WAPI_HANDLE_COUNT]={0};
@@ -45,7 +61,9 @@ static struct _WapiHandleOps *handle_ops[WAPI_HANDLE_COUNT]={
        &_wapi_sem_ops,
        &_wapi_mutex_ops,
        &_wapi_event_ops,
+#ifndef DISABLE_SOCKETS
        &_wapi_socket_ops,
+#endif
        &_wapi_find_ops,
        &_wapi_process_ops,
        &_wapi_pipe_ops,
@@ -100,16 +118,41 @@ const char *_wapi_handle_typename[] = {
 
 struct _WapiHandleUnshared *_wapi_private_handles [_WAPI_PRIVATE_MAX_SLOTS];
 static guint32 _wapi_private_handle_count = 0;
+static guint32 _wapi_private_handle_slot_count = 0;
 
 struct _WapiHandleSharedLayout *_wapi_shared_layout = NULL;
+
+/*
+ * If SHM is enabled, this will point to shared memory, otherwise it will be NULL.
+ */
 struct _WapiFileShareLayout *_wapi_fileshare_layout = NULL;
 
+/*
+ * If SHM is disabled, this will point to a hash of _WapiFileShare structures, otherwise
+ * it will be NULL. We use this instead of _wapi_fileshare_layout to avoid allocating a
+ * 4MB array.
+ */
+static GHashTable *file_share_hash;
+static mono_mutex_t file_share_hash_mutex;
+
+#define file_share_hash_lock() mono_mutex_lock (&file_share_hash_mutex)
+#define file_share_hash_unlock() mono_mutex_unlock (&file_share_hash_mutex)
+
 guint32 _wapi_fd_reserve;
 
-mono_mutex_t _wapi_global_signal_mutex;
-pthread_cond_t _wapi_global_signal_cond;
+/* 
+ * This is an internal handle which is used for handling waiting for multiple handles.
+ * Threads which wait for multiple handles wait on this one handle, and when a handle
+ * is signalled, this handle is signalled too.
+ */
+static gpointer _wapi_global_signal_handle;
+
+/* Point to the mutex/cond inside _wapi_global_signal_handle */
+mono_mutex_t *_wapi_global_signal_mutex;
+pthread_cond_t *_wapi_global_signal_cond;
 
 int _wapi_sem_id;
+gboolean _wapi_has_shut_down = FALSE;
 
 /* Use this instead of getpid(), to cope with linuxthreads.  It's a
  * function rather than a variable lookup because we need to get at
@@ -118,6 +161,8 @@ int _wapi_sem_id;
 static pid_t _wapi_pid;
 static mono_once_t pid_init_once = MONO_ONCE_INIT;
 
+static void _wapi_handle_unref_full (gpointer handle, gboolean ignore_private_busy_handles);
+
 static void pid_init (void)
 {
        _wapi_pid = getpid ();
@@ -131,14 +176,12 @@ pid_t _wapi_getpid (void)
 }
 
 
-static mono_mutex_t scan_mutex = MONO_MUTEX_INITIALIZER;
+static mono_mutex_t scan_mutex;
 
 static void handle_cleanup (void)
 {
        int i, j, k;
        
-       _wapi_process_signal_self ();
-
        /* Every shared handle we were using ought really to be closed
         * by now, but to make sure just blow them all away.  The
         * exiting finalizer thread in particular races us to the
@@ -149,59 +192,69 @@ static void handle_cleanup (void)
        for(i = SLOT_INDEX (0); _wapi_private_handles[i] != NULL; i++) {
                for(j = SLOT_OFFSET (0); j < _WAPI_HANDLE_INITIAL_COUNT; j++) {
                        struct _WapiHandleUnshared *handle_data = &_wapi_private_handles[i][j];
-                       int type = handle_data->type;
-                       
-                       
-                       if (_WAPI_SHARED_HANDLE (type)) {
-                               gpointer handle = GINT_TO_POINTER (i*_WAPI_HANDLE_INITIAL_COUNT+j);
-                               
-                               if (type == WAPI_HANDLE_THREAD) {
-                                       /* Special-case thread handles
-                                        * because they need extra
-                                        * cleanup.  This also avoids
-                                        * a race condition between
-                                        * the application exit and
-                                        * the finalizer thread - if
-                                        * it finishes up between now
-                                        * and actual app termination
-                                        * it will find all its handle
-                                        * details have been blown
-                                        * away, so this sets those
-                                        * anyway.
-                                        */
-                                       _wapi_thread_set_termination_details (handle, 0);
-                               }
-                               
-                               for(k = handle_data->ref; k > 0; k--) {
-#ifdef DEBUG
-                                       g_message ("%s: unreffing %s handle %p", __func__, _wapi_handle_typename[type], handle);
-#endif
+                       gpointer handle = GINT_TO_POINTER (i*_WAPI_HANDLE_INITIAL_COUNT+j);
+
+                       for(k = handle_data->ref; k > 0; k--) {
+                               DEBUG ("%s: unreffing %s handle %p", __func__, _wapi_handle_typename[type], handle);
                                        
-                                       _wapi_handle_unref (handle);
-                               }
+                               _wapi_handle_unref_full (handle, TRUE);
                        }
                }
        }
        
        _wapi_shm_semaphores_remove ();
+
+       _wapi_shm_detach (WAPI_SHM_DATA);
+       _wapi_shm_detach (WAPI_SHM_FILESHARE);
+
+       if (file_share_hash) {
+               g_hash_table_destroy (file_share_hash);
+               mono_mutex_destroy (&file_share_hash_mutex);
+       }
+
+       for (i = 0; i < _WAPI_PRIVATE_MAX_SLOTS; ++i)
+               g_free (_wapi_private_handles [i]);
 }
 
-static mono_once_t shared_init_once = MONO_ONCE_INIT;
-static void shared_init (void)
+/*
+ * wapi_init:
+ *
+ *   Initialize the io-layer.
+ */
+void
+wapi_init (void)
 {
-       int thr_ret;
-       int idx = 0;
-       
        g_assert ((sizeof (handle_ops) / sizeof (handle_ops[0]))
                  == WAPI_HANDLE_COUNT);
        
+#ifdef HAVE_GETRLIMIT
+       {
+               struct rlimit limit;
+               int res;
+
+               res = getrlimit (RLIMIT_NOFILE, &limit);
+               g_assert (res == 0);
+               _wapi_fd_reserve = limit.rlim_cur;
+       }
+#else
        _wapi_fd_reserve = getdtablesize();
+#endif
+
+       /* This is needed by the code in _wapi_handle_new_internal */
+       _wapi_fd_reserve = (_wapi_fd_reserve + (_WAPI_HANDLE_INITIAL_COUNT - 1)) & ~(_WAPI_HANDLE_INITIAL_COUNT - 1);
 
        do {
+               /* 
+                * The entries in _wapi_private_handles reserved for fds are allocated lazily to 
+                * save memory.
+                */
+               /*
                _wapi_private_handles [idx++] = g_new0 (struct _WapiHandleUnshared,
                                                        _WAPI_HANDLE_INITIAL_COUNT);
+               */
 
                _wapi_private_handle_count += _WAPI_HANDLE_INITIAL_COUNT;
+               _wapi_private_handle_slot_count ++;
        } while(_wapi_fd_reserve > _wapi_private_handle_count);
 
        _wapi_shm_semaphores_init ();
@@ -209,16 +262,25 @@ static void shared_init (void)
        _wapi_shared_layout = _wapi_shm_attach (WAPI_SHM_DATA);
        g_assert (_wapi_shared_layout != NULL);
        
-       _wapi_fileshare_layout = _wapi_shm_attach (WAPI_SHM_FILESHARE);
-       g_assert (_wapi_fileshare_layout != NULL);
-       
-       _wapi_collection_init ();
-       
-       thr_ret = pthread_cond_init(&_wapi_global_signal_cond, NULL);
-       g_assert (thr_ret == 0);
+       if (_wapi_shm_enabled ()) {
+               /* This allocates a 4mb array, so do it only if SHM is enabled */
+               _wapi_fileshare_layout = _wapi_shm_attach (WAPI_SHM_FILESHARE);
+               g_assert (_wapi_fileshare_layout != NULL);
+       }
        
-       thr_ret = mono_mutex_init(&_wapi_global_signal_mutex, NULL);
-       g_assert (thr_ret == 0);
+#if !defined (DISABLE_SHARED_HANDLES)
+       if (_wapi_shm_enabled ())
+               _wapi_collection_init ();
+#endif
+       _wapi_io_init ();
+       mono_mutex_init (&scan_mutex);
+
+       _wapi_global_signal_handle = _wapi_handle_new (WAPI_HANDLE_EVENT, NULL);
+
+       _wapi_global_signal_cond = &_WAPI_PRIVATE_HANDLES (GPOINTER_TO_UINT (_wapi_global_signal_handle)).signal_cond;
+       _wapi_global_signal_mutex = &_WAPI_PRIVATE_HANDLES (GPOINTER_TO_UINT (_wapi_global_signal_handle)).signal_mutex;
+
+       wapi_processes_init ();
 
        /* Using g_atexit here instead of an explicit function call in
         * a cleanup routine lets us cope when a third-party library
@@ -228,10 +290,24 @@ static void shared_init (void)
        g_atexit (handle_cleanup);
 }
 
+void
+wapi_cleanup (void)
+{
+       g_assert (_wapi_has_shut_down == FALSE);
+       
+       _wapi_has_shut_down = TRUE;
+
+       _wapi_error_cleanup ();
+       _wapi_thread_cleanup ();
+       wapi_processes_cleanup ();
+}
+
 static void _wapi_handle_init_shared (struct _WapiHandleShared *handle,
                                      WapiHandleType type,
                                      gpointer handle_specific)
 {
+       g_assert (_wapi_has_shut_down == FALSE);
+       
        handle->type = type;
        handle->timestamp = (guint32)(time (NULL) & 0xFFFFFFFF);
        handle->signalled = FALSE;
@@ -242,10 +318,59 @@ static void _wapi_handle_init_shared (struct _WapiHandleShared *handle,
        }
 }
 
+static size_t _wapi_handle_struct_size (WapiHandleType type)
+{
+       size_t type_size;
+
+       switch (type) {
+               case WAPI_HANDLE_FILE: case WAPI_HANDLE_CONSOLE: case WAPI_HANDLE_PIPE:
+                       type_size = sizeof (struct _WapiHandle_file);
+                       break;
+               case WAPI_HANDLE_THREAD:
+                       type_size = sizeof (struct _WapiHandle_thread);
+                       break;
+               case WAPI_HANDLE_SEM:
+                       type_size = sizeof (struct _WapiHandle_sem);
+                       break;
+               case WAPI_HANDLE_MUTEX:
+                       type_size = sizeof (struct _WapiHandle_mutex);
+                       break;
+               case WAPI_HANDLE_EVENT:
+                       type_size = sizeof (struct _WapiHandle_event);
+                       break;
+               case WAPI_HANDLE_SOCKET:
+                       type_size = sizeof (struct _WapiHandle_socket);
+                       break;
+               case WAPI_HANDLE_FIND:
+                       type_size = sizeof (struct _WapiHandle_find);
+                       break;
+               case WAPI_HANDLE_PROCESS:
+                       type_size = sizeof (struct _WapiHandle_process);
+                       break;
+               case WAPI_HANDLE_NAMEDMUTEX:
+                       type_size = sizeof (struct _WapiHandle_namedmutex);
+                       break;
+               case WAPI_HANDLE_NAMEDSEM:
+                       type_size = sizeof (struct _WapiHandle_namedsem);
+                       break;
+               case WAPI_HANDLE_NAMEDEVENT:
+                       type_size = sizeof (struct _WapiHandle_namedevent);
+                       break;
+
+               default:
+                       g_error ("Unknown WapiHandleType: %d\n", type);
+       }
+
+       return type_size;
+}
+
 static void _wapi_handle_init (struct _WapiHandleUnshared *handle,
                               WapiHandleType type, gpointer handle_specific)
 {
        int thr_ret;
+       int type_size;
+       
+       g_assert (_wapi_has_shut_down == FALSE);
        
        handle->type = type;
        handle->signalled = FALSE;
@@ -255,12 +380,13 @@ static void _wapi_handle_init (struct _WapiHandleUnshared *handle,
                thr_ret = pthread_cond_init (&handle->signal_cond, NULL);
                g_assert (thr_ret == 0);
                                
-               thr_ret = mono_mutex_init (&handle->signal_mutex, NULL);
+               thr_ret = mono_mutex_init (&handle->signal_mutex);
                g_assert (thr_ret == 0);
 
                if (handle_specific != NULL) {
+                       type_size = _wapi_handle_struct_size (type);
                        memcpy (&handle->u, handle_specific,
-                               sizeof (handle->u));
+                               type_size);
                }
        }
 }
@@ -272,6 +398,8 @@ static guint32 _wapi_handle_new_shared (WapiHandleType type,
        static guint32 last = 1;
        int thr_ret;
        
+       g_assert (_wapi_has_shut_down == FALSE);
+       
        /* Leave the first slot empty as a guard */
 again:
        /* FIXME: expandable array */
@@ -327,6 +455,8 @@ static guint32 _wapi_handle_new_internal (WapiHandleType type,
        static guint32 last = 0;
        gboolean retry = FALSE;
        
+       g_assert (_wapi_has_shut_down == FALSE);
+       
        /* A linear scan should be fast enough.  Start from the last
         * allocation, assuming that handles are allocated more often
         * than they're freed. Leave the space reserved for file
@@ -341,17 +471,19 @@ static guint32 _wapi_handle_new_internal (WapiHandleType type,
 
 again:
        count = last;
-       for(i = SLOT_INDEX (count); _wapi_private_handles [i] != NULL; i++) {
-               for (k = SLOT_OFFSET (count); k < _WAPI_HANDLE_INITIAL_COUNT; k++) {
-                       struct _WapiHandleUnshared *handle = &_wapi_private_handles [i][k];
+       for(i = SLOT_INDEX (count); i < _wapi_private_handle_slot_count; i++) {
+               if (_wapi_private_handles [i]) {
+                       for (k = SLOT_OFFSET (count); k < _WAPI_HANDLE_INITIAL_COUNT; k++) {
+                               struct _WapiHandleUnshared *handle = &_wapi_private_handles [i][k];
 
-                       if(handle->type == WAPI_HANDLE_UNUSED) {
-                               last = count + 1;
+                               if(handle->type == WAPI_HANDLE_UNUSED) {
+                                       last = count + 1;
                        
-                               _wapi_handle_init (handle, type, handle_specific);
-                               return (count);
+                                       _wapi_handle_init (handle, type, handle_specific);
+                                       return (count);
+                               }
+                               count++;
                        }
-                       count++;
                }
        }
 
@@ -366,23 +498,20 @@ again:
        return(0);
 }
 
-gpointer _wapi_handle_new (WapiHandleType type, gpointer handle_specific)
+gpointer 
+_wapi_handle_new (WapiHandleType type, gpointer handle_specific)
 {
        guint32 handle_idx = 0;
        gpointer handle;
        int thr_ret;
-       
-       mono_once (&shared_init_once, shared_init);
-       
-#ifdef DEBUG
-       g_message ("%s: Creating new handle of type %s", __func__,
+
+       g_assert (_wapi_has_shut_down == FALSE);
+               
+       DEBUG ("%s: Creating new handle of type %s", __func__,
                   _wapi_handle_typename[type]);
-#endif
 
        g_assert(!_WAPI_FD_HANDLE(type));
        
-       pthread_cleanup_push ((void(*)(void *))mono_mutex_unlock_in_cleanup,
-                             (void *)&scan_mutex);
        thr_ret = mono_mutex_lock (&scan_mutex);
        g_assert (thr_ret == 0);
                
@@ -392,16 +521,16 @@ gpointer _wapi_handle_new (WapiHandleType type, gpointer handle_specific)
                if (idx >= _WAPI_PRIVATE_MAX_SLOTS) {
                        break;
                }
-               
+
                _wapi_private_handles [idx] = g_new0 (struct _WapiHandleUnshared,
                                                _WAPI_HANDLE_INITIAL_COUNT);
 
                _wapi_private_handle_count += _WAPI_HANDLE_INITIAL_COUNT;
+               _wapi_private_handle_slot_count ++;
        }
        
        thr_ret = mono_mutex_unlock (&scan_mutex);
        g_assert (thr_ret == 0);
-       pthread_cleanup_pop (0);
 
        if (handle_idx == 0) {
                /* We ran out of slots */
@@ -414,9 +543,7 @@ gpointer _wapi_handle_new (WapiHandleType type, gpointer handle_specific)
        
        handle = GUINT_TO_POINTER (handle_idx);
 
-#ifdef DEBUG
-       g_message ("%s: Allocated new handle %p", __func__, handle);
-#endif
+       DEBUG ("%s: Allocated new handle %p", __func__, handle);
        
        if (_WAPI_SHARED_HANDLE(type)) {
                /* Add the shared section too */
@@ -434,10 +561,8 @@ gpointer _wapi_handle_new (WapiHandleType type, gpointer handle_specific)
                }
                
                _WAPI_PRIVATE_HANDLES(handle_idx).u.shared.offset = ref;
-#ifdef DEBUG
-               g_message ("%s: New shared handle at offset 0x%x", __func__,
+               DEBUG ("%s: New shared handle at offset 0x%x", __func__,
                           ref);
-#endif
        }
                
 done:
@@ -451,14 +576,11 @@ gpointer _wapi_handle_new_from_offset (WapiHandleType type, guint32 offset,
        gpointer handle = INVALID_HANDLE_VALUE;
        int thr_ret, i, k;
        struct _WapiHandleShared *shared;
-       guint32 now = (guint32)(time (NULL) & 0xFFFFFFFF);
        
-       mono_once (&shared_init_once, shared_init);
-
-#ifdef DEBUG
-       g_message ("%s: Creating new handle of type %s to offset %d", __func__,
+       g_assert (_wapi_has_shut_down == FALSE);
+       
+       DEBUG ("%s: Creating new handle of type %s to offset %d", __func__,
                   _wapi_handle_typename[type], offset);
-#endif
 
        g_assert(!_WAPI_FD_HANDLE(type));
        g_assert(_WAPI_SHARED_HANDLE(type));
@@ -466,23 +588,24 @@ gpointer _wapi_handle_new_from_offset (WapiHandleType type, guint32 offset,
 
        shared = &_wapi_shared_layout->handles[offset];
        if (timestamp) {
+               guint32 now = (guint32)(time (NULL) & 0xFFFFFFFF);
                /* Bump up the timestamp for this offset */
                InterlockedExchange ((gint32 *)&shared->timestamp, now);
        }
                
-       pthread_cleanup_push ((void(*)(void *))mono_mutex_unlock_in_cleanup,
-                             (void *)&scan_mutex);
        thr_ret = mono_mutex_lock (&scan_mutex);
        g_assert (thr_ret == 0);
 
-       for (i = SLOT_INDEX (0); _wapi_private_handles [i] != NULL; i++) {
-               for (k = SLOT_OFFSET (0); k < _WAPI_HANDLE_INITIAL_COUNT; k++) {
-                       struct _WapiHandleUnshared *handle_data = &_wapi_private_handles [i][k];
+       for (i = SLOT_INDEX (0); i < _wapi_private_handle_slot_count; i++) {
+               if (_wapi_private_handles [i]) {
+                       for (k = SLOT_OFFSET (0); k < _WAPI_HANDLE_INITIAL_COUNT; k++) {
+                               struct _WapiHandleUnshared *handle_data = &_wapi_private_handles [i][k];
                
-                       if (handle_data->type == type &&
-                           handle_data->u.shared.offset == offset) {
-                               handle = GUINT_TO_POINTER (i * _WAPI_HANDLE_INITIAL_COUNT + k);
-                               goto first_pass_done;
+                               if (handle_data->type == type &&
+                                       handle_data->u.shared.offset == offset) {
+                                       handle = GUINT_TO_POINTER (i * _WAPI_HANDLE_INITIAL_COUNT + k);
+                                       goto first_pass_done;
+                               }
                        }
                }
        }
@@ -490,15 +613,12 @@ gpointer _wapi_handle_new_from_offset (WapiHandleType type, guint32 offset,
 first_pass_done:
        thr_ret = mono_mutex_unlock (&scan_mutex);
        g_assert (thr_ret == 0);
-       pthread_cleanup_pop (0);
 
        if (handle != INVALID_HANDLE_VALUE) {
                _wapi_handle_ref (handle);
 
-#ifdef DEBUG
-               g_message ("%s: Returning old handle %p referencing 0x%x",
+               DEBUG ("%s: Returning old handle %p referencing 0x%x",
                           __func__, handle, offset);
-#endif
                return (handle);
        }
 
@@ -508,24 +628,18 @@ first_pass_done:
        
        if (shared->type == WAPI_HANDLE_UNUSED) {
                /* Someone deleted this handle while we were working */
-#ifdef DEBUG
-               g_message ("%s: Handle at 0x%x unused", __func__, offset);
-#endif
+               DEBUG ("%s: Handle at 0x%x unused", __func__, offset);
                goto done;
        }
 
        if (shared->type != type) {
-#ifdef DEBUG
-               g_message ("%s: Wrong type at %d 0x%x! Found %s wanted %s",
+               DEBUG ("%s: Wrong type at %d 0x%x! Found %s wanted %s",
                           __func__, offset, offset,
                           _wapi_handle_typename[shared->type],
                           _wapi_handle_typename[type]);
-#endif
                goto done;
        }
        
-       pthread_cleanup_push ((void(*)(void *))mono_mutex_unlock_in_cleanup,
-                             (void *)&scan_mutex);
        thr_ret = mono_mutex_lock (&scan_mutex);
        g_assert (thr_ret == 0);
        
@@ -536,11 +650,11 @@ first_pass_done:
                                                _WAPI_HANDLE_INITIAL_COUNT);
 
                _wapi_private_handle_count += _WAPI_HANDLE_INITIAL_COUNT;
+               _wapi_private_handle_slot_count ++;
        }
                
        thr_ret = mono_mutex_unlock (&scan_mutex);
        g_assert (thr_ret == 0);
-       pthread_cleanup_pop (0);
                
        /* Make sure we left the space for fd mappings */
        g_assert (handle_idx >= _wapi_fd_reserve);
@@ -550,9 +664,7 @@ first_pass_done:
        _WAPI_PRIVATE_HANDLES(handle_idx).u.shared.offset = offset;
        InterlockedIncrement ((gint32 *)&shared->handle_refs);
        
-#ifdef DEBUG
-       g_message ("%s: Allocated new handle %p referencing 0x%x (shared refs %d)", __func__, handle, offset, shared->handle_refs);
-#endif
+       DEBUG ("%s: Allocated new handle %p referencing 0x%x (shared refs %d)", __func__, handle, offset, shared->handle_refs);
        
 done:
        _wapi_handle_unlock_shared_handles ();
@@ -560,44 +672,58 @@ done:
        return(handle);
 }
 
+static void
+init_handles_slot (int idx)
+{
+       int thr_ret;
+
+       thr_ret = mono_mutex_lock (&scan_mutex);
+       g_assert (thr_ret == 0);
+
+       if (_wapi_private_handles [idx] == NULL) {
+               _wapi_private_handles [idx] = g_new0 (struct _WapiHandleUnshared,
+                                                                                         _WAPI_HANDLE_INITIAL_COUNT);
+               g_assert (_wapi_private_handles [idx]);
+       }
+
+       thr_ret = mono_mutex_unlock (&scan_mutex);
+       g_assert (thr_ret == 0);
+}
+
 gpointer _wapi_handle_new_fd (WapiHandleType type, int fd,
                              gpointer handle_specific)
 {
        struct _WapiHandleUnshared *handle;
        int thr_ret;
        
-       mono_once (&shared_init_once, shared_init);
+       g_assert (_wapi_has_shut_down == FALSE);
        
-#ifdef DEBUG
-       g_message ("%s: Creating new handle of type %s", __func__,
+       DEBUG ("%s: Creating new handle of type %s", __func__,
                   _wapi_handle_typename[type]);
-#endif
        
        g_assert(_WAPI_FD_HANDLE(type));
        g_assert(!_WAPI_SHARED_HANDLE(type));
        
        if (fd >= _wapi_fd_reserve) {
-#ifdef DEBUG
-               g_message ("%s: fd %d is too big", __func__, fd);
-#endif
+               DEBUG ("%s: fd %d is too big", __func__, fd);
 
                return(GUINT_TO_POINTER (_WAPI_HANDLE_INVALID));
        }
 
+       /* Initialize the array entries on demand */
+       if (_wapi_private_handles [SLOT_INDEX (fd)] == NULL)
+               init_handles_slot (SLOT_INDEX (fd));
+
        handle = &_WAPI_PRIVATE_HANDLES(fd);
        
        if (handle->type != WAPI_HANDLE_UNUSED) {
-#ifdef DEBUG
-               g_message ("%s: fd %d is already in use!", __func__, fd);
-#endif
+               DEBUG ("%s: fd %d is already in use!", __func__, fd);
                /* FIXME: clean up this handle?  We can't do anything
                 * with the fd, cos thats the new one
                 */
        }
 
-#ifdef DEBUG
-       g_message ("%s: Assigning new fd handle %d", __func__, fd);
-#endif
+       DEBUG ("%s: Assigning new fd handle %d", __func__, fd);
 
        /* Prevent file share entries racing with us, when the file
         * handle is only half initialised
@@ -621,6 +747,10 @@ gboolean _wapi_lookup_handle (gpointer handle, WapiHandleType type,
        if (!_WAPI_PRIVATE_VALID_SLOT (handle_idx)) {
                return(FALSE);
        }
+
+       /* Initialize the array entries on demand */
+       if (_wapi_private_handles [SLOT_INDEX (handle_idx)] == NULL)
+               init_handles_slot (SLOT_INDEX (handle_idx));
        
        handle_data = &_WAPI_PRIVATE_HANDLES(handle_idx);
        
@@ -663,26 +793,25 @@ _wapi_handle_foreach (WapiHandleType type,
        guint32 i, k;
        int thr_ret;
 
-       pthread_cleanup_push ((void(*)(void *))mono_mutex_unlock_in_cleanup,
-                             (void *)&scan_mutex);
        thr_ret = mono_mutex_lock (&scan_mutex);
        g_assert (thr_ret == 0);
 
-       for (i = SLOT_INDEX (0); _wapi_private_handles [i] != NULL; i++) {
-               for (k = SLOT_OFFSET (0); k < _WAPI_HANDLE_INITIAL_COUNT; k++) {
-                       handle_data = &_wapi_private_handles [i][k];
-               
-                       if (handle_data->type == type) {
-                               ret = GUINT_TO_POINTER (i * _WAPI_HANDLE_INITIAL_COUNT + k);
-                               if (on_each (ret, user_data) == TRUE)
-                                       break;
+       for (i = SLOT_INDEX (0); i < _wapi_private_handle_slot_count; i++) {
+               if (_wapi_private_handles [i]) {
+                       for (k = SLOT_OFFSET (0); k < _WAPI_HANDLE_INITIAL_COUNT; k++) {
+                               handle_data = &_wapi_private_handles [i][k];
+                       
+                               if (handle_data->type == type) {
+                                       ret = GUINT_TO_POINTER (i * _WAPI_HANDLE_INITIAL_COUNT + k);
+                                       if (on_each (ret, user_data) == TRUE)
+                                               break;
+                               }
                        }
                }
        }
 
        thr_ret = mono_mutex_unlock (&scan_mutex);
        g_assert (thr_ret == 0);
-       pthread_cleanup_pop (0);
 }
 
 /* This might list some shared handles twice if they are already
@@ -691,6 +820,7 @@ _wapi_handle_foreach (WapiHandleType type,
  * unreffed if the check function returns FALSE, so callers must not
  * rely on the handle persisting (unless the check function returns
  * TRUE)
+ * The caller owns the returned handle.
  */
 gpointer _wapi_search_handle (WapiHandleType type,
                              gboolean (*check)(gpointer test, gpointer user),
@@ -699,32 +829,32 @@ gpointer _wapi_search_handle (WapiHandleType type,
                              gboolean search_shared)
 {
        struct _WapiHandleUnshared *handle_data = NULL;
-       struct _WapiHandleShared *shared;
+       struct _WapiHandleShared *shared = NULL;
        gpointer ret = NULL;
        guint32 i, k;
        gboolean found = FALSE;
        int thr_ret;
 
-       pthread_cleanup_push ((void(*)(void *))mono_mutex_unlock_in_cleanup,
-                             (void *)&scan_mutex);
        thr_ret = mono_mutex_lock (&scan_mutex);
        g_assert (thr_ret == 0);
        
-       for (i = SLOT_INDEX (0); !found && _wapi_private_handles [i] != NULL; i++) {
-               for (k = SLOT_OFFSET (0); k < _WAPI_HANDLE_INITIAL_COUNT; k++) {
-                       handle_data = &_wapi_private_handles [i][k];
+       for (i = SLOT_INDEX (0); !found && i < _wapi_private_handle_slot_count; i++) {
+               if (_wapi_private_handles [i]) {
+                       for (k = SLOT_OFFSET (0); k < _WAPI_HANDLE_INITIAL_COUNT; k++) {
+                               handle_data = &_wapi_private_handles [i][k];
                
-                       if (handle_data->type == type) {
-                               ret = GUINT_TO_POINTER (i * _WAPI_HANDLE_INITIAL_COUNT + k);
-                               if (check (ret, user_data) == TRUE) {
-                                       _wapi_handle_ref (ret);
-                                       found = TRUE;
+                               if (handle_data->type == type) {
+                                       ret = GUINT_TO_POINTER (i * _WAPI_HANDLE_INITIAL_COUNT + k);
+                                       if (check (ret, user_data) == TRUE) {
+                                               _wapi_handle_ref (ret);
+                                               found = TRUE;
 
-                                       if (_WAPI_SHARED_HANDLE (type)) {
-                                               shared = &_wapi_shared_layout->handles[i];
-                                       }
+                                               if (_WAPI_SHARED_HANDLE (type)) {
+                                                       shared = &_wapi_shared_layout->handles[i];
+                                               }
                                        
-                                       break;
+                                               break;
+                                       }
                                }
                        }
                }
@@ -732,13 +862,10 @@ gpointer _wapi_search_handle (WapiHandleType type,
 
        thr_ret = mono_mutex_unlock (&scan_mutex);
        g_assert (thr_ret == 0);
-       pthread_cleanup_pop (0);
 
        if (!found && search_shared && _WAPI_SHARED_HANDLE (type)) {
                /* Not found yet, so search the shared memory too */
-#ifdef DEBUG
-               g_message ("%s: Looking at other shared handles...", __func__);
-#endif
+               DEBUG ("%s: Looking at other shared handles...", __func__);
 
                for (i = 0; i < _WAPI_HANDLE_INITIAL_COUNT; i++) {
                        shared = &_wapi_shared_layout->handles[i];
@@ -759,9 +886,7 @@ gpointer _wapi_search_handle (WapiHandleType type,
                                        continue;
                                }
                                
-#ifdef DEBUG
-                               g_message ("%s: Opened tmp handle %p (type %s) from offset %d", __func__, ret, _wapi_handle_typename[type], i);
-#endif
+                               DEBUG ("%s: Opened tmp handle %p (type %s) from offset %d", __func__, ret, _wapi_handle_typename[type], i);
 
                                /* It's possible that the shared part
                                 * of this handle has now been blown
@@ -838,10 +963,8 @@ gint32 _wapi_search_handle_namespace (WapiHandleType type,
        
        g_assert(_WAPI_SHARED_HANDLE(type));
        
-#ifdef DEBUG
-       g_message ("%s: Lookup for handle named [%s] type %s", __func__,
+       DEBUG ("%s: Lookup for handle named [%s] type %s", __func__,
                   utf8_name, _wapi_handle_typename[type]);
-#endif
 
        /* Do a handle collection before starting to look, so that any
         * stale cruft gets removed
@@ -864,28 +987,20 @@ gint32 _wapi_search_handle_namespace (WapiHandleType type,
                        continue;
                }
 
-#ifdef DEBUG
-               g_message ("%s: found a shared namespace handle at 0x%x (type %s)", __func__, i, _wapi_handle_typename[shared_handle_data->type]);
-#endif
+               DEBUG ("%s: found a shared namespace handle at 0x%x (type %s)", __func__, i, _wapi_handle_typename[shared_handle_data->type]);
 
                sharedns=(WapiSharedNamespace *)&shared_handle_data->u;
                        
-#ifdef DEBUG
-               g_message ("%s: name is [%s]", __func__, sharedns->name);
-#endif
+               DEBUG ("%s: name is [%s]", __func__, sharedns->name);
 
                if (strcmp (sharedns->name, utf8_name) == 0) {
                        if (shared_handle_data->type != type) {
                                /* Its the wrong type, so fail now */
-#ifdef DEBUG
-                               g_message ("%s: handle 0x%x matches name but is wrong type: %s", __func__, i, _wapi_handle_typename[shared_handle_data->type]);
-#endif
+                               DEBUG ("%s: handle 0x%x matches name but is wrong type: %s", __func__, i, _wapi_handle_typename[shared_handle_data->type]);
                                ret = -1;
                                goto done;
                        } else {
-#ifdef DEBUG
-                               g_message ("%s: handle 0x%x matches name and type", __func__, i);
-#endif
+                               DEBUG ("%s: handle 0x%x matches name and type", __func__, i);
                                ret = i;
                                goto done;
                        }
@@ -901,7 +1016,6 @@ done:
 void _wapi_handle_ref (gpointer handle)
 {
        guint32 idx = GPOINTER_TO_UINT(handle);
-       guint32 now = (guint32)(time (NULL) & 0xFFFFFFFF);
        struct _WapiHandleUnshared *handle_data;
 
        if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
@@ -925,7 +1039,7 @@ void _wapi_handle_ref (gpointer handle)
         */
        if (_WAPI_SHARED_HANDLE(handle_data->type)) {
                struct _WapiHandleShared *shared_data = &_wapi_shared_layout->handles[handle_data->u.shared.offset];
-               
+               guint32 now = (guint32)(time (NULL) & 0xFFFFFFFF);
                InterlockedExchange ((gint32 *)&shared_data->timestamp, now);
        }
        
@@ -938,10 +1052,10 @@ void _wapi_handle_ref (gpointer handle)
 }
 
 /* The handle must not be locked on entry to this function */
-void _wapi_handle_unref (gpointer handle)
+static void _wapi_handle_unref_full (gpointer handle, gboolean ignore_private_busy_handles)
 {
        guint32 idx = GPOINTER_TO_UINT(handle);
-       gboolean destroy = FALSE;
+       gboolean destroy = FALSE, early_exit = FALSE;
        int thr_ret;
 
        if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
@@ -990,12 +1104,9 @@ void _wapi_handle_unref (gpointer handle)
                        g_assert (thr_ret == 0);
                }
                
-               pthread_cleanup_push ((void(*)(void *))mono_mutex_unlock_in_cleanup, (void *)&scan_mutex);
                thr_ret = mono_mutex_lock (&scan_mutex);
 
-#ifdef DEBUG
-               g_message ("%s: Destroying handle %p", __func__, handle);
-#endif
+               DEBUG ("%s: Destroying handle %p", __func__, handle);
                
                memcpy (&handle_data, &_WAPI_PRIVATE_HANDLES(idx),
                        sizeof (struct _WapiHandleUnshared));
@@ -1012,10 +1123,19 @@ void _wapi_handle_unref (gpointer handle)
                         * "unlock_and_destroy" atomic function.
                         */
                        thr_ret = mono_mutex_destroy (&_WAPI_PRIVATE_HANDLES(idx).signal_mutex);
-                       g_assert (thr_ret == 0);
-                               
-                       thr_ret = pthread_cond_destroy (&_WAPI_PRIVATE_HANDLES(idx).signal_cond);
-                       g_assert (thr_ret == 0);
+                       /*WARNING gross hack to make cleanup not crash when exiting without the whole runtime teardown.*/
+                       if (thr_ret == EBUSY && ignore_private_busy_handles) {
+                               early_exit = TRUE;
+                       } else {
+                               if (thr_ret != 0)
+                                       g_error ("Error destroying handle %p mutex due to %d\n", handle, thr_ret);
+
+                               thr_ret = pthread_cond_destroy (&_WAPI_PRIVATE_HANDLES(idx).signal_cond);
+                               if (thr_ret == EBUSY && ignore_private_busy_handles)
+                                       early_exit = TRUE;
+                               else if (thr_ret != 0)
+                                       g_error ("Error destroying handle %p cond var due to %d\n", handle, thr_ret);
+                       }
                } else {
                        struct _WapiHandleShared *shared = &_wapi_shared_layout->handles[handle_data.u.shared.offset];
 
@@ -1039,8 +1159,9 @@ void _wapi_handle_unref (gpointer handle)
 
                thr_ret = mono_mutex_unlock (&scan_mutex);
                g_assert (thr_ret == 0);
-               pthread_cleanup_pop (0);
 
+               if (early_exit)
+                       return;
                if (is_shared) {
                        _wapi_handle_unlock_shared_handles ();
                }
@@ -1055,6 +1176,11 @@ void _wapi_handle_unref (gpointer handle)
        }
 }
 
+void _wapi_handle_unref (gpointer handle)
+{
+       _wapi_handle_unref_full (handle, FALSE);
+}
+
 void _wapi_handle_register_capabilities (WapiHandleType type,
                                         WapiHandleCapability caps)
 {
@@ -1073,10 +1199,8 @@ gboolean _wapi_handle_test_capabilities (gpointer handle,
        
        type = _WAPI_PRIVATE_HANDLES(idx).type;
 
-#ifdef DEBUG
-       g_message ("%s: testing 0x%x against 0x%x (%d)", __func__,
+       DEBUG ("%s: testing 0x%x against 0x%x (%d)", __func__,
                   handle_caps[type], caps, handle_caps[type] & caps);
-#endif
        
        return((handle_caps[type] & caps) != 0);
 }
@@ -1160,7 +1284,7 @@ gboolean _wapi_handle_ops_isowned (gpointer handle)
        }
 }
 
-guint32 _wapi_handle_ops_special_wait (gpointer handle, guint32 timeout)
+guint32 _wapi_handle_ops_special_wait (gpointer handle, guint32 timeout, gboolean alertable)
 {
        guint32 idx = GPOINTER_TO_UINT(handle);
        WapiHandleType type;
@@ -1173,7 +1297,7 @@ guint32 _wapi_handle_ops_special_wait (gpointer handle, guint32 timeout)
        
        if (handle_ops[type] != NULL &&
            handle_ops[type]->special_wait != NULL) {
-               return(handle_ops[type]->special_wait (handle, timeout));
+               return(handle_ops[type]->special_wait (handle, timeout, alertable));
        } else {
                return(WAIT_FAILED);
        }
@@ -1222,6 +1346,10 @@ gboolean CloseHandle(gpointer handle)
                        return(FALSE);
                }
        }
+       if (handle == _WAPI_HANDLE_INVALID){
+               SetLastError (ERROR_INVALID_PARAMETER);
+               return(FALSE);
+       }
        
        _wapi_handle_unref (handle);
        
@@ -1243,7 +1371,7 @@ gboolean DuplicateHandle (gpointer srcprocess, gpointer src,
        if (src == _WAPI_PROCESS_CURRENT) {
                *target = _wapi_process_duplicate ();
        } else if (src == _WAPI_THREAD_CURRENT) {
-               *target = _wapi_thread_duplicate ();
+               g_assert_not_reached ();
        } else {
                _wapi_handle_ref (src);
                *target = src;
@@ -1272,9 +1400,7 @@ again:
                gpointer handle = handles[i];
                guint32 idx = GPOINTER_TO_UINT(handle);
 
-#ifdef DEBUG
-               g_message ("%s: attempting to lock %p", __func__, handle);
-#endif
+               DEBUG ("%s: attempting to lock %p", __func__, handle);
 
                type = _WAPI_PRIVATE_HANDLES(idx).type;
 
@@ -1283,10 +1409,8 @@ again:
                if (thr_ret != 0) {
                        /* Bummer */
                        
-#ifdef DEBUG
-                       g_message ("%s: attempt failed for %p: %s", __func__,
+                       DEBUG ("%s: attempt failed for %p: %s", __func__,
                                   handle, strerror (thr_ret));
-#endif
 
                        thr_ret = _wapi_handle_unlock_shared_handles ();
                        g_assert (thr_ret == 0);
@@ -1310,19 +1434,15 @@ again:
                                iter=1;
                        }
                        
-#ifdef DEBUG
-                       g_message ("%s: Backing off for %d ms", __func__,
+                       DEBUG ("%s: Backing off for %d ms", __func__,
                                   iter*10);
-#endif
                        _wapi_handle_spin (10 * iter);
                        
                        goto again;
                }
        }
        
-#ifdef DEBUG
-       g_message ("%s: Locked all handles", __func__);
-#endif
+       DEBUG ("%s: Locked all handles", __func__);
 
        count=0;
        *lowest=numhandles;
@@ -1333,11 +1453,7 @@ again:
                
                type = _WAPI_PRIVATE_HANDLES(idx).type;
 
-               _wapi_handle_ref (handle);
-               
-#ifdef DEBUG
-               g_message ("%s: Checking handle %p", __func__, handle);
-#endif
+               DEBUG ("%s: Checking handle %p", __func__, handle);
 
                if(((_wapi_handle_test_capabilities (handle, WAPI_HANDLE_CAP_OWN)==TRUE) &&
                    (_wapi_handle_ops_isowned (handle) == TRUE)) ||
@@ -1347,19 +1463,15 @@ again:
                    _WAPI_PRIVATE_HANDLES(idx).signalled == TRUE)) {
                        count++;
                        
-#ifdef DEBUG
-                       g_message ("%s: Handle %p signalled", __func__,
+                       DEBUG ("%s: Handle %p signalled", __func__,
                                   handle);
-#endif
                        if(*lowest>i) {
                                *lowest=i;
                        }
                }
        }
        
-#ifdef DEBUG
-       g_message ("%s: %d event handles signalled", __func__, count);
-#endif
+       DEBUG ("%s: %d event handles signalled", __func__, count);
 
        if ((waitall == TRUE && count == numhandles) ||
            (waitall == FALSE && count > 0)) {
@@ -1368,9 +1480,7 @@ again:
                ret=FALSE;
        }
        
-#ifdef DEBUG
-       g_message ("%s: Returning %d", __func__, ret);
-#endif
+       DEBUG ("%s: Returning %d", __func__, ret);
 
        *retcount=count;
        
@@ -1388,67 +1498,68 @@ void _wapi_handle_unlock_handles (guint32 numhandles, gpointer *handles)
        for(i=0; i<numhandles; i++) {
                gpointer handle = handles[i];
                
-#ifdef DEBUG
-               g_message ("%s: unlocking handle %p", __func__, handle);
-#endif
+               DEBUG ("%s: unlocking handle %p", __func__, handle);
 
                thr_ret = _wapi_handle_unlock_handle (handle);
                g_assert (thr_ret == 0);
        }
 }
 
-static int timedwait_signal_poll_cond (pthread_cond_t *cond, mono_mutex_t *mutex, struct timespec *timeout)
+static int timedwait_signal_poll_cond (pthread_cond_t *cond, mono_mutex_t *mutex, struct timespec *timeout, gboolean alertable)
 {
        struct timespec fake_timeout;
        int ret;
-       
-       _wapi_calc_timeout (&fake_timeout, 100);
-       
-       if (timeout != NULL && ((fake_timeout.tv_sec > timeout->tv_sec) ||
-          (fake_timeout.tv_sec == timeout->tv_sec &&
-               fake_timeout.tv_nsec > timeout->tv_nsec))) {
-               /* Real timeout is less than 100ms time */
-               ret=mono_cond_timedwait (cond, mutex, timeout);
+
+       if (!alertable) {
+               if (timeout)
+                       ret=mono_cond_timedwait (cond, mutex, timeout);
+               else
+                       ret=mono_cond_wait (cond, mutex);
        } else {
-               ret=mono_cond_timedwait (cond, mutex, &fake_timeout);
+               _wapi_calc_timeout (&fake_timeout, 100);
+       
+               if (timeout != NULL && ((fake_timeout.tv_sec > timeout->tv_sec) ||
+                                                               (fake_timeout.tv_sec == timeout->tv_sec &&
+                                                                fake_timeout.tv_nsec > timeout->tv_nsec))) {
+                       /* Real timeout is less than 100ms time */
+                       ret=mono_cond_timedwait (cond, mutex, timeout);
+               } else {
+                       ret=mono_cond_timedwait (cond, mutex, &fake_timeout);
 
-               /* Mask the fake timeout, this will cause
-                * another poll if the cond was not really signaled
-                */
-               if (ret==ETIMEDOUT) {
-                       ret=0;
+                       /* Mask the fake timeout, this will cause
+                        * another poll if the cond was not really signaled
+                        */
+                       if (ret==ETIMEDOUT) {
+                               ret=0;
+                       }
                }
        }
        
        return(ret);
 }
 
-int _wapi_handle_wait_signal (void)
+int _wapi_handle_wait_signal (gboolean poll)
 {
-       return timedwait_signal_poll_cond (&_wapi_global_signal_cond, &_wapi_global_signal_mutex, NULL);
+       return _wapi_handle_timedwait_signal_handle (_wapi_global_signal_handle, NULL, TRUE, poll);
 }
 
-int _wapi_handle_timedwait_signal (struct timespec *timeout)
+int _wapi_handle_timedwait_signal (struct timespec *timeout, gboolean poll)
 {
-       return timedwait_signal_poll_cond (&_wapi_global_signal_cond, &_wapi_global_signal_mutex, timeout);
+       return _wapi_handle_timedwait_signal_handle (_wapi_global_signal_handle, timeout, TRUE, poll);
 }
 
-int _wapi_handle_wait_signal_handle (gpointer handle)
+int _wapi_handle_wait_signal_handle (gpointer handle, gboolean alertable)
 {
-#ifdef DEBUG
-       g_message ("%s: waiting for %p", __func__, handle);
-#endif
+       DEBUG ("%s: waiting for %p", __func__, handle);
        
-       return _wapi_handle_timedwait_signal_handle (handle, NULL);
+       return _wapi_handle_timedwait_signal_handle (handle, NULL, alertable, FALSE);
 }
 
 int _wapi_handle_timedwait_signal_handle (gpointer handle,
-                                         struct timespec *timeout)
+                                                                                 struct timespec *timeout, gboolean alertable, gboolean poll)
 {
-#ifdef DEBUG
-       g_message ("%s: waiting for %p (type %s)", __func__, handle,
+       DEBUG ("%s: waiting for %p (type %s)", __func__, handle,
                   _wapi_handle_typename[_wapi_handle_type (handle)]);
-#endif
        
        if (_WAPI_SHARED_HANDLE (_wapi_handle_type (handle))) {
                if (WAPI_SHARED_HANDLE_DATA(handle).signalled == TRUE) {
@@ -1479,10 +1590,63 @@ int _wapi_handle_timedwait_signal_handle (gpointer handle,
                
        } else {
                guint32 idx = GPOINTER_TO_UINT(handle);
-               return timedwait_signal_poll_cond (&_WAPI_PRIVATE_HANDLES(idx).signal_cond, &_WAPI_PRIVATE_HANDLES(idx).signal_mutex, timeout);
+               int res;
+               pthread_cond_t *cond;
+               mono_mutex_t *mutex;
+
+               if (alertable && !wapi_thread_set_wait_handle (handle))
+                       return 0;
+
+               cond = &_WAPI_PRIVATE_HANDLES (idx).signal_cond;
+               mutex = &_WAPI_PRIVATE_HANDLES (idx).signal_mutex;
+
+               if (poll) {
+                       /* This is needed when waiting for process handles */
+                       res = timedwait_signal_poll_cond (cond, mutex, timeout, alertable);
+               } else {
+                       if (timeout)
+                               res = mono_cond_timedwait (cond, mutex, timeout);
+                       else
+                               res = mono_cond_wait (cond, mutex);
+               }
+
+               if (alertable)
+                       wapi_thread_clear_wait_handle (handle);
+
+               return res;
        }
 }
 
+void
+_wapi_free_share_info (_WapiFileShare *share_info)
+{
+       if (!_wapi_shm_enabled ()) {
+               file_share_hash_lock ();
+               g_hash_table_remove (file_share_hash, share_info);
+               file_share_hash_unlock ();
+               /* The hashtable dtor frees share_info */
+       } else {
+               memset (share_info, '\0', sizeof(struct _WapiFileShare));
+       }
+}
+
+static gint
+wapi_share_info_equal (gconstpointer ka, gconstpointer kb)
+{
+       const _WapiFileShare *s1 = ka;
+       const _WapiFileShare *s2 = kb;
+
+       return (s1->device == s2->device && s1->inode == s2->inode) ? 1 : 0;
+}
+
+static guint
+wapi_share_info_hash (gconstpointer data)
+{
+       const _WapiFileShare *s = data;
+
+       return s->inode;
+}
+
 gboolean _wapi_handle_get_or_set_share (dev_t device, ino_t inode,
                                        guint32 new_sharemode,
                                        guint32 new_access,
@@ -1503,55 +1667,36 @@ gboolean _wapi_handle_get_or_set_share (dev_t device, ino_t inode,
        /* Prevent new entries racing with us */
        thr_ret = _wapi_shm_sem_lock (_WAPI_SHARED_SEM_FILESHARE);
        g_assert (thr_ret == 0);
-       
-       /* If a linear scan gets too slow we'll have to fit a hash
-        * table onto the shared mem backing store
-        */
-       *share_info = NULL;
-       for (i = 0; i <= _wapi_fileshare_layout->hwm; i++) {
-               file_share = &_wapi_fileshare_layout->share_info[i];
 
-               /* Make a note of an unused slot, in case we need to
-                * store share info
+       if (!_wapi_shm_enabled ()) {
+               _WapiFileShare tmp;
+
+               /*
+                * Instead of allocating a 4MB array, we use a hash table to keep track of this
+                * info. This is needed even if SHM is disabled, to track sharing inside
+                * the current process.
                 */
-               if (first_unused == -1 && file_share->handle_refs == 0) {
-                       first_unused = i;
-                       continue;
+               if (!file_share_hash) {
+                       file_share_hash = g_hash_table_new_full (wapi_share_info_hash, wapi_share_info_equal, NULL, g_free);
+                       mono_mutex_init_recursive (&file_share_hash_mutex);
                }
-               
-               if (file_share->handle_refs == 0) {
-                       continue;
-               }
-               
-               if (file_share->device == device &&
-                   file_share->inode == inode) {
+                       
+               tmp.device = device;
+               tmp.inode = inode;
+
+               file_share_hash_lock ();
+
+               file_share = g_hash_table_lookup (file_share_hash, &tmp);
+               if (file_share) {
                        *old_sharemode = file_share->sharemode;
                        *old_access = file_share->access;
                        *share_info = file_share;
                        
-                       /* Increment the reference count while we
-                        * still have sole access to the shared area.
-                        * This makes the increment atomic wrt
-                        * collections
-                        */
                        InterlockedIncrement ((gint32 *)&file_share->handle_refs);
-                       
                        exists = TRUE;
-                       break;
-               }
-       }
-       
-       if (!exists) {
-               if (i == _WAPI_FILESHARE_SIZE && first_unused == -1) {
-                       /* No more space */
                } else {
-                       if (first_unused == -1) {
-                               file_share = &_wapi_fileshare_layout->share_info[++i];
-                               _wapi_fileshare_layout->hwm = i;
-                       } else {
-                               file_share = &_wapi_fileshare_layout->share_info[first_unused];
-                       }
-                       
+                       file_share = g_new0 (_WapiFileShare, 1);
+
                        file_share->device = device;
                        file_share->inode = inode;
                        file_share->opened_by_pid = _wapi_getpid ();
@@ -1559,11 +1704,73 @@ gboolean _wapi_handle_get_or_set_share (dev_t device, ino_t inode,
                        file_share->access = new_access;
                        file_share->handle_refs = 1;
                        *share_info = file_share;
+
+                       g_hash_table_insert (file_share_hash, file_share, file_share);
                }
-       }
 
-       if (*share_info != NULL) {
-               InterlockedExchange ((gint32 *)&(*share_info)->timestamp, now);
+               file_share_hash_unlock ();
+       } else {
+               /* If a linear scan gets too slow we'll have to fit a hash
+                * table onto the shared mem backing store
+                */
+               *share_info = NULL;
+               for (i = 0; i <= _wapi_fileshare_layout->hwm; i++) {
+                       file_share = &_wapi_fileshare_layout->share_info[i];
+
+                       /* Make a note of an unused slot, in case we need to
+                        * store share info
+                        */
+                       if (first_unused == -1 && file_share->handle_refs == 0) {
+                               first_unused = i;
+                               continue;
+                       }
+               
+                       if (file_share->handle_refs == 0) {
+                               continue;
+                       }
+               
+                       if (file_share->device == device &&
+                               file_share->inode == inode) {
+                               *old_sharemode = file_share->sharemode;
+                               *old_access = file_share->access;
+                               *share_info = file_share;
+                       
+                               /* Increment the reference count while we
+                                * still have sole access to the shared area.
+                                * This makes the increment atomic wrt
+                                * collections
+                                */
+                               InterlockedIncrement ((gint32 *)&file_share->handle_refs);
+                       
+                               exists = TRUE;
+                               break;
+                       }
+               }
+       
+               if (!exists) {
+                       if (i == _WAPI_FILESHARE_SIZE && first_unused == -1) {
+                               /* No more space */
+                       } else {
+                               if (first_unused == -1) {
+                                       file_share = &_wapi_fileshare_layout->share_info[++i];
+                                       _wapi_fileshare_layout->hwm = i;
+                               } else {
+                                       file_share = &_wapi_fileshare_layout->share_info[first_unused];
+                               }
+                       
+                               file_share->device = device;
+                               file_share->inode = inode;
+                               file_share->opened_by_pid = _wapi_getpid ();
+                               file_share->sharemode = new_sharemode;
+                               file_share->access = new_access;
+                               file_share->handle_refs = 1;
+                               *share_info = file_share;
+                       }
+               }
+
+               if (*share_info != NULL) {
+                       InterlockedExchange ((gint32 *)&(*share_info)->timestamp, now);
+               }
        }
        
        thr_ret = _wapi_shm_sem_unlock (_WAPI_SHARED_SEM_FILESHARE);
@@ -1579,6 +1786,9 @@ gboolean _wapi_handle_get_or_set_share (dev_t device, ino_t inode,
  */
 static void _wapi_handle_check_share_by_pid (struct _WapiFileShare *share_info)
 {
+#if defined(__native_client__)
+       g_assert_not_reached ();
+#else
        if (kill (share_info->opened_by_pid, 0) == -1 &&
            (errno == ESRCH ||
             errno == EPERM)) {
@@ -1586,14 +1796,14 @@ static void _wapi_handle_check_share_by_pid (struct _WapiFileShare *share_info)
                 * owned by someone else) so mark this share info as
                 * dead
                 */
-#ifdef DEBUG
-               g_message ("%s: Didn't find it, destroying entry", __func__);
-#endif
+               DEBUG ("%s: Didn't find it, destroying entry", __func__);
 
-               memset (share_info, '\0', sizeof(struct _WapiFileShare));
+               _wapi_free_share_info (share_info);
        }
+#endif
 }
 
+#ifdef __linux__
 /* Scan /proc/<pids>/fd/ for open file descriptors to the file in
  * question.  If there are none, reset the share info.
  *
@@ -1629,83 +1839,20 @@ void _wapi_handle_check_share (struct _WapiFileShare *share_info, int fd)
         * See bugs 75764 and 75891
         */
        for (i = 0; i < _wapi_fd_reserve; i++) {
-               struct _WapiHandleUnshared *handle = &_WAPI_PRIVATE_HANDLES(i);
-
-               if (i != fd &&
-                   handle->type == WAPI_HANDLE_FILE) {
-                       struct _WapiHandle_file *file_handle = &handle->u.file;
+               if (_wapi_private_handles [SLOT_INDEX (i)]) {
+                       struct _WapiHandleUnshared *handle = &_WAPI_PRIVATE_HANDLES(i);
 
-                       if (file_handle->share_info == share_info) {
-#ifdef DEBUG
-                               g_message ("%s: handle 0x%x has this file open!",
-                                          __func__, i);
-#endif
-
-                               goto done;
-                       }
-               }
-       }
-
-       for (i = 0; i < _WAPI_HANDLE_INITIAL_COUNT; i++) {
-               struct _WapiHandleShared *shared;
-               struct _WapiHandle_process *process_handle;
-
-               shared = &_wapi_shared_layout->handles[i];
-               
-               if (shared->type == WAPI_HANDLE_PROCESS) {
-                       DIR *fd_dir;
-                       struct dirent *fd_entry;
-                       char subdir[_POSIX_PATH_MAX];
-
-                       process_handle = &shared->u.process;
-                       pid = process_handle->id;
-               
-                       /* Look in /proc/<pid>/fd/ but ignore
-                        * /proc/<our pid>/fd/<fd>, as we have the
-                        * file open too
-                        */
-                       g_snprintf (subdir, _POSIX_PATH_MAX, "/proc/%d/fd",
-                                   pid);
-                       
-                       fd_dir = opendir (subdir);
-                       if (fd_dir == NULL) {
-                               continue;
-                       }
-
-#ifdef DEBUG
-                       g_message ("%s: Looking in %s", __func__, subdir);
-#endif
-                       
-                       proc_fds = TRUE;
-                       
-                       while ((fd_entry = readdir (fd_dir)) != NULL) {
-                               char path[_POSIX_PATH_MAX];
-                               struct stat link_stat;
-                               
-                               if (!strcmp (fd_entry->d_name, ".") ||
-                                   !strcmp (fd_entry->d_name, "..") ||
-                                   (pid == self &&
-                                    fd == atoi (fd_entry->d_name))) {
-                                       continue;
-                               }
+                       if (i != fd &&
+                               handle->type == WAPI_HANDLE_FILE) {
+                               struct _WapiHandle_file *file_handle = &handle->u.file;
 
-                               g_snprintf (path, _POSIX_PATH_MAX,
-                                           "/proc/%d/fd/%s", pid,
-                                           fd_entry->d_name);
-                               
-                               stat (path, &link_stat);
-                               if (link_stat.st_dev == share_info->device &&
-                                   link_stat.st_ino == share_info->inode) {
-#ifdef DEBUG
-                                       g_message ("%s:  Found it at %s",
-                                                  __func__, path);
-#endif
+                               if (file_handle->share_info == share_info) {
+                                       DEBUG ("%s: handle 0x%x has this file open!",
+                                                          __func__, i);
 
-                                       found = TRUE;
+                                       goto done;
                                }
                        }
-                       
-                       closedir (fd_dir);
                }
        }
 
@@ -1713,11 +1860,9 @@ void _wapi_handle_check_share (struct _WapiFileShare *share_info, int fd)
                _wapi_handle_check_share_by_pid (share_info);
        } else if (found == FALSE) {
                /* Blank out this entry, as it is stale */
-#ifdef DEBUG
-               g_message ("%s: Didn't find it, destroying entry", __func__);
-#endif
+               DEBUG ("%s: Didn't find it, destroying entry", __func__);
 
-               memset (share_info, '\0', sizeof(struct _WapiFileShare));
+               _wapi_free_share_info (share_info);
        }
 
 done:
@@ -1725,6 +1870,29 @@ done:
 
        _wapi_handle_unlock_shared_handles ();
 }
+#else
+//
+// Other implementations (non-Linux)
+//
+void _wapi_handle_check_share (struct _WapiFileShare *share_info, int fd)
+{
+       int thr_ret;
+       
+       /* Prevents entries from expiring under us if we remove this
+        * one */
+       thr_ret = _wapi_handle_lock_shared_handles ();
+       g_assert (thr_ret == 0);
+       
+       /* Prevent new entries racing with us */
+       thr_ret = _wapi_shm_sem_lock (_WAPI_SHARED_SEM_FILESHARE);
+       g_assert (thr_ret == 0);
+       
+       _wapi_handle_check_share_by_pid (share_info);
+
+       thr_ret = _wapi_shm_sem_unlock (_WAPI_SHARED_SEM_FILESHARE);
+       _wapi_handle_unlock_shared_handles ();
+}
+#endif
 
 void _wapi_handle_dump (void)
 {
@@ -1732,32 +1900,31 @@ void _wapi_handle_dump (void)
        guint32 i, k;
        int thr_ret;
        
-       pthread_cleanup_push ((void(*)(void *))mono_mutex_unlock_in_cleanup,
-                             (void *)&scan_mutex);
        thr_ret = mono_mutex_lock (&scan_mutex);
        g_assert (thr_ret == 0);
        
-       for(i = SLOT_INDEX (0); _wapi_private_handles [i] != NULL; i++) {
-               for (k = SLOT_OFFSET (0); k < _WAPI_HANDLE_INITIAL_COUNT; k++) {
-                       handle_data = &_wapi_private_handles [i][k];
+       for(i = SLOT_INDEX (0); i < _wapi_private_handle_slot_count; i++) {
+               if (_wapi_private_handles [i]) {
+                       for (k = SLOT_OFFSET (0); k < _WAPI_HANDLE_INITIAL_COUNT; k++) {
+                               handle_data = &_wapi_private_handles [i][k];
 
-                       if (handle_data->type == WAPI_HANDLE_UNUSED) {
-                               continue;
-                       }
+                               if (handle_data->type == WAPI_HANDLE_UNUSED) {
+                                       continue;
+                               }
                
-                       g_print ("%3x [%7s] %s %d ",
-                                i * _WAPI_HANDLE_INITIAL_COUNT + k,
-                                _wapi_handle_typename[handle_data->type],
-                                handle_data->signalled?"Sg":"Un",
-                                handle_data->ref);
-                       handle_details[handle_data->type](&handle_data->u);
-                       g_print ("\n");
+                               g_print ("%3x [%7s] %s %d ",
+                                                i * _WAPI_HANDLE_INITIAL_COUNT + k,
+                                                _wapi_handle_typename[handle_data->type],
+                                                handle_data->signalled?"Sg":"Un",
+                                                handle_data->ref);
+                               handle_details[handle_data->type](&handle_data->u);
+                               g_print ("\n");
+                       }
                }
        }
 
        thr_ret = mono_mutex_unlock (&scan_mutex);
        g_assert (thr_ret == 0);
-       pthread_cleanup_pop (0);
 }
 
 static void _wapi_shared_details (gpointer handle_info)
@@ -1780,49 +1947,40 @@ void _wapi_handle_update_refs (void)
        thr_ret = _wapi_shm_sem_lock (_WAPI_SHARED_SEM_FILESHARE);
        g_assert(thr_ret == 0);
 
-       pthread_cleanup_push ((void(*)(void *))mono_mutex_unlock_in_cleanup,
-                             (void *)&scan_mutex);
        thr_ret = mono_mutex_lock (&scan_mutex);
        
-       for(i = SLOT_INDEX (0); _wapi_private_handles [i] != NULL; i++) {
-               for (k = SLOT_OFFSET (0); k < _WAPI_HANDLE_INITIAL_COUNT; k++) {
-                       struct _WapiHandleUnshared *handle = &_wapi_private_handles [i][k];
+       for(i = SLOT_INDEX (0); i < _wapi_private_handle_slot_count; i++) {
+               if (_wapi_private_handles [i]) {
+                       for (k = SLOT_OFFSET (0); k < _WAPI_HANDLE_INITIAL_COUNT; k++) {
+                               struct _WapiHandleUnshared *handle = &_wapi_private_handles [i][k];
 
-                       if (_WAPI_SHARED_HANDLE(handle->type)) {
-                               struct _WapiHandleShared *shared_data;
+                               if (_WAPI_SHARED_HANDLE(handle->type)) {
+                                       struct _WapiHandleShared *shared_data;
                                
-#ifdef DEBUG
-                               g_message ("%s: (%d) handle 0x%x is SHARED (%s)", __func__, _wapi_getpid (), i * _WAPI_HANDLE_INITIAL_COUNT + k, _wapi_handle_typename[handle->type]);
-#endif
+                                       DEBUG ("%s: (%d) handle 0x%x is SHARED (%s)", __func__, _wapi_getpid (), i * _WAPI_HANDLE_INITIAL_COUNT + k, _wapi_handle_typename[handle->type]);
 
-                               shared_data = &_wapi_shared_layout->handles[handle->u.shared.offset];
+                                       shared_data = &_wapi_shared_layout->handles[handle->u.shared.offset];
 
-#ifdef DEBUG
-                               g_message ("%s: (%d) Updating timestamp of handle 0x%x", __func__, _wapi_getpid (), handle->u.shared.offset);
-#endif
+                                       DEBUG ("%s: (%d) Updating timestamp of handle 0x%x", __func__, _wapi_getpid (), handle->u.shared.offset);
 
-                               InterlockedExchange ((gint32 *)&shared_data->timestamp, now);
-                       } else if (handle->type == WAPI_HANDLE_FILE) {
-                               struct _WapiHandle_file *file_handle = &handle->u.file;
+                                       InterlockedExchange ((gint32 *)&shared_data->timestamp, now);
+                               } else if (handle->type == WAPI_HANDLE_FILE) {
+                                       struct _WapiHandle_file *file_handle = &handle->u.file;
                                
-#ifdef DEBUG
-                               g_message ("%s: (%d) handle 0x%x is FILE", __func__, _wapi_getpid (), i * _WAPI_HANDLE_INITIAL_COUNT + k);
-#endif
+                                       DEBUG ("%s: (%d) handle 0x%x is FILE", __func__, _wapi_getpid (), i * _WAPI_HANDLE_INITIAL_COUNT + k);
                                
-                               g_assert (file_handle->share_info != NULL);
+                                       g_assert (file_handle->share_info != NULL);
 
-#ifdef DEBUG
-                               g_message ("%s: (%d) Inc refs on fileshare 0x%x", __func__, _wapi_getpid (), (file_handle->share_info - &_wapi_fileshare_layout->share_info[0]) / sizeof(struct _WapiFileShare));
-#endif
+                                       DEBUG ("%s: (%d) Inc refs on fileshare 0x%x", __func__, _wapi_getpid (), (file_handle->share_info - &_wapi_fileshare_layout->share_info[0]) / sizeof(struct _WapiFileShare));
 
-                               InterlockedExchange ((gint32 *)&file_handle->share_info->timestamp, now);
+                                       InterlockedExchange ((gint32 *)&file_handle->share_info->timestamp, now);
+                               }
                        }
                }
        }
 
        thr_ret = mono_mutex_unlock (&scan_mutex);
        g_assert (thr_ret == 0);
-       pthread_cleanup_pop (0);
        
        thr_ret = _wapi_shm_sem_unlock (_WAPI_SHARED_SEM_FILESHARE);