2005-05-26 Gonzalo Paniagua Javier <gonzalo@ximian.com>
[mono.git] / mono / io-layer / handles.c
index 8ee34395a5f30bba5ffab3f5a0fb6f0fc06bfc4c..4478bcbd731ee6b02ae56c79f85aba7f12c836a1 100644 (file)
@@ -33,6 +33,8 @@
 #undef DEBUG
 #undef DEBUG_REFS
 
+static void (*_wapi_handle_ops_get_close_func (WapiHandleType type))(gpointer, gpointer);
+
 static WapiHandleCapability handle_caps[WAPI_HANDLE_COUNT]={0};
 static struct _WapiHandleOps *handle_ops[WAPI_HANDLE_COUNT]={
        NULL,
@@ -82,7 +84,14 @@ const char *_wapi_handle_typename[] = {
        "Error!!"
 };
 
-struct _WapiHandleUnshared *_wapi_private_handles = NULL;
+/*
+ * We can hold _WAPI_PRIVATE_MAX_SLOTS * _WAPI_HANDLE_INITIAL_COUNT handles.
+ * If 4M handles are not enough... Oh, well... we will crash.
+ */
+#define SLOT_INDEX(x)  (x / _WAPI_HANDLE_INITIAL_COUNT)
+#define SLOT_OFFSET(x) (x % _WAPI_HANDLE_INITIAL_COUNT)
+
+struct _WapiHandleUnshared *_wapi_private_handles [_WAPI_PRIVATE_MAX_SLOTS];
 static guint32 _wapi_private_handle_count = 0;
 
 struct _WapiHandleSharedLayout *_wapi_shared_layout = NULL;
@@ -93,27 +102,31 @@ guint32 _wapi_fd_reserve;
 mono_mutex_t _wapi_global_signal_mutex;
 pthread_cond_t _wapi_global_signal_cond;
 
+int _wapi_sem_id;
+
+static mono_mutex_t scan_mutex = MONO_MUTEX_INITIALIZER;
+
 static mono_once_t shared_init_once = MONO_ONCE_INIT;
 static void shared_init (void)
 {
        int thr_ret;
+       int idx = 0;
        
        _wapi_fd_reserve = getdtablesize();
 
-       _wapi_private_handle_count = _WAPI_HANDLE_INITIAL_COUNT;
-       
-       while(_wapi_fd_reserve > _wapi_private_handle_count) {
+       do {
+               _wapi_private_handles [idx++] = g_new0 (struct _WapiHandleUnshared,
+                                                       _WAPI_HANDLE_INITIAL_COUNT);
+
                _wapi_private_handle_count += _WAPI_HANDLE_INITIAL_COUNT;
-       }
+       } while(_wapi_fd_reserve > _wapi_private_handle_count);
        
-       _wapi_private_handles = g_new0 (struct _WapiHandleUnshared,
-                                       _wapi_private_handle_count);
-
-
-       _wapi_shared_layout = _wapi_shm_attach ();
+       _wapi_shared_layout = _wapi_shm_attach (WAPI_SHM_DATA);
        g_assert (_wapi_shared_layout != NULL);
+
+       _wapi_shm_semaphores_init ();
        
-       _wapi_fileshare_layout = _wapi_fileshare_shm_attach ();
+       _wapi_fileshare_layout = _wapi_shm_attach (WAPI_SHM_FILESHARE);
        g_assert (_wapi_fileshare_layout != NULL);
        
        _wapi_collection_init ();
@@ -173,12 +186,12 @@ static guint32 _wapi_handle_new_shared_offset (guint32 offset)
        
 again:
        /* FIXME: expandable array */
-       /* FIXME: leave a few slots at the end so that there's always
-        * space to move a handle.  (Leave the space in the offset
-        * table too, so we don't have to keep track of inter-segment
+       /* leave a few slots at the end so that there's always space
+        * to move a handle.  (We leave the space in the offset table
+        * too, so we don't have to keep track of inter-segment
         * offsets.)
         */
-       for(i = last; i <_WAPI_HANDLE_INITIAL_COUNT; i++) {
+       for(i = last; i <_WAPI_HANDLE_INITIAL_COUNT - _WAPI_HEADROOM; i++) {
                struct _WapiHandleSharedMetadata *meta = &_wapi_shared_layout->metadata[i];
                
                if(meta->offset == 0) {
@@ -222,10 +235,11 @@ static guint32 _wapi_handle_new_shared (WapiHandleType type,
        /* Leave the first slot empty as a guard */
 again:
        /* FIXME: expandable array */
-       /* FIXME: leave a few slots at the end so that there's always
-        * space to move a handle
+       /* Leave a few slots at the end so that there's always space
+        * to move a handle
         */
-       for(offset = last; offset <_WAPI_HANDLE_INITIAL_COUNT; offset++) {
+       for(offset = last; offset <_WAPI_HANDLE_INITIAL_COUNT - _WAPI_HEADROOM;
+           offset++) {
                struct _WapiHandleShared *handle = &_wapi_shared_layout->handles[offset];
                
                if(handle->type == WAPI_HANDLE_UNUSED) {
@@ -265,8 +279,9 @@ again:
 static guint32 _wapi_handle_new_internal (WapiHandleType type,
                                          gpointer handle_specific)
 {
-       guint32 i;
+       guint32 i, k, count;
        static guint32 last = 0;
+       gboolean retry = FALSE;
        
        /* A linear scan should be fast enough.  Start from the last
         * allocation, assuming that handles are allocated more often
@@ -276,21 +291,27 @@ static guint32 _wapi_handle_new_internal (WapiHandleType type,
        
        if (last < _wapi_fd_reserve) {
                last = _wapi_fd_reserve;
+       } else {
+               retry = TRUE;
        }
-       
+
 again:
-       for(i = last; i <_wapi_private_handle_count; i++) {
-               struct _WapiHandleUnshared *handle = &_wapi_private_handles[i];
-               
-               if(handle->type == WAPI_HANDLE_UNUSED) {
-                       last = i + 1;
+       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];
+
+                       if(handle->type == WAPI_HANDLE_UNUSED) {
+                               last = count + 1;
                        
-                       _wapi_handle_init (handle, type, handle_specific);
-                       return(i);
+                               _wapi_handle_init (handle, type, handle_specific);
+                               return (count);
+                       }
+                       count++;
                }
        }
 
-       if(last > _wapi_fd_reserve) {
+       if(retry && last > _wapi_fd_reserve) {
                /* Try again from the beginning */
                last = _wapi_fd_reserve;
                goto again;
@@ -303,7 +324,6 @@ again:
 
 gpointer _wapi_handle_new (WapiHandleType type, gpointer handle_specific)
 {
-       static mono_mutex_t scan_mutex = MONO_MUTEX_INITIALIZER;
        guint32 handle_idx = 0;
        gpointer handle;
        int thr_ret;
@@ -324,16 +344,10 @@ gpointer _wapi_handle_new (WapiHandleType type, gpointer handle_specific)
                
        while ((handle_idx = _wapi_handle_new_internal (type, handle_specific)) == 0) {
                /* Try and expand the array, and have another go */
-               _wapi_private_handles = g_renew (struct _WapiHandleUnshared,
-                                                _wapi_private_handles,
-                                                _wapi_private_handle_count +
-                                                _WAPI_HANDLE_INITIAL_COUNT);
-               memset (_wapi_private_handles +
-                       (_wapi_private_handle_count *
-                        sizeof(struct _WapiHandleUnshared)), '\0',
-                       (_WAPI_HANDLE_INITIAL_COUNT *
-                        sizeof(struct _WapiHandleUnshared)));
-               
+               int idx = SLOT_INDEX (_wapi_private_handle_count);
+               _wapi_private_handles [idx] = g_new0 (struct _WapiHandleUnshared,
+                                               _WAPI_HANDLE_INITIAL_COUNT);
+
                _wapi_private_handle_count += _WAPI_HANDLE_INITIAL_COUNT;
        }
                
@@ -359,19 +373,24 @@ gpointer _wapi_handle_new (WapiHandleType type, gpointer handle_specific)
                        _wapi_handle_collect ();
                        offset = _wapi_handle_new_shared (type,
                                                          handle_specific);
-                       /* FIXME: grow the arrays */
-                       g_assert (offset != 0);
+                       if (offset == 0) {
+                               /* FIXME: grow the arrays */
+                               return (_WAPI_HANDLE_INVALID);
+                       }
                }
                
                ref = _wapi_handle_new_shared_offset (offset);
                if (ref == 0) {
                        _wapi_handle_collect ();
                        ref = _wapi_handle_new_shared_offset (offset);
-                       /* FIXME: grow the arrays */
-                       g_assert (ref != 0);
+
+                       if (ref == 0) {
+                               /* FIXME: grow the arrays */
+                               return (_WAPI_HANDLE_INVALID);
+                       }
                }
                
-               _wapi_private_handles[handle_idx].u.shared.offset = ref;
+               _WAPI_PRIVATE_HANDLES(handle_idx).u.shared.offset = ref;
 #ifdef DEBUG
                g_message ("%s: New shared handle at offset 0x%x", __func__,
                           ref);
@@ -381,43 +400,51 @@ gpointer _wapi_handle_new (WapiHandleType type, gpointer handle_specific)
        return(handle);
 }
 
-gpointer _wapi_handle_new_for_existing_ns (WapiHandleType type,
-                                          gpointer handle_specific,
-                                          guint32 offset)
+gpointer _wapi_handle_new_from_offset (WapiHandleType type, guint32 offset)
 {
-       static mono_mutex_t scan_mutex = MONO_MUTEX_INITIALIZER;
        guint32 handle_idx = 0;
        gpointer handle;
-       int thr_ret;
+       int thr_ret, i, k;
        
        mono_once (&shared_init_once, shared_init);
        
 #ifdef DEBUG
-       g_message ("%s: Creating new handle of type %s", __func__,
-                  _wapi_handle_typename[type]);
+       g_message ("%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));
        g_assert(offset != 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];
+               
+                       if (handle_data->type == type &&
+                           handle_data->u.shared.offset == offset) {
+                               handle = GUINT_TO_POINTER (i * _WAPI_HANDLE_INITIAL_COUNT + k);
+                               _wapi_handle_ref (handle);
+
+#ifdef DEBUG
+                               g_message ("%s: Returning old handle %p referencing 0x%x", __func__, handle, offset);
+#endif
+                               return (handle);
+                       }
+               }
+       }
+
        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);
-               
-       while ((handle_idx = _wapi_handle_new_internal (type, handle_specific)) == 0) {
+       
+       while ((handle_idx = _wapi_handle_new_internal (type, NULL)) == 0) {
                /* Try and expand the array, and have another go */
-               _wapi_private_handles = g_renew (struct _WapiHandleUnshared,
-                                                _wapi_private_handles,
-                                                _wapi_private_handle_count +
-                                                _WAPI_HANDLE_INITIAL_COUNT);
-               memset (_wapi_private_handles +
-                       (_wapi_private_handle_count *
-                        sizeof(struct _WapiHandleUnshared)), '\0',
-                       (_WAPI_HANDLE_INITIAL_COUNT *
-                        sizeof(struct _WapiHandleUnshared)));
-               
+               int idx = SLOT_INDEX (_wapi_private_handle_count);
+               _wapi_private_handles [idx] = g_new0 (struct _WapiHandleUnshared,
+                                               _WAPI_HANDLE_INITIAL_COUNT);
+
                _wapi_private_handle_count += _WAPI_HANDLE_INITIAL_COUNT;
        }
                
@@ -430,7 +457,7 @@ gpointer _wapi_handle_new_for_existing_ns (WapiHandleType type,
        
        handle = GUINT_TO_POINTER (handle_idx);
                
-       _wapi_private_handles[handle_idx].u.shared.offset = offset;
+       _WAPI_PRIVATE_HANDLES(handle_idx).u.shared.offset = offset;
 
 #ifdef DEBUG
        g_message ("%s: Allocated new handle %p referencing 0x%x", __func__,
@@ -463,7 +490,7 @@ gpointer _wapi_handle_new_fd (WapiHandleType type, int fd,
                return(GUINT_TO_POINTER (_WAPI_HANDLE_INVALID));
        }
 
-       handle = &_wapi_private_handles[fd];
+       handle = &_WAPI_PRIVATE_HANDLES(fd);
        
        if (handle->type != WAPI_HANDLE_UNUSED) {
 #ifdef DEBUG
@@ -489,27 +516,39 @@ gboolean _wapi_lookup_handle (gpointer handle, WapiHandleType type,
        struct _WapiHandleUnshared *handle_data;
        guint32 handle_idx = GPOINTER_TO_UINT(handle);
 
-       handle_data = &_wapi_private_handles[handle_idx];
+       handle_data = &_WAPI_PRIVATE_HANDLES(handle_idx);
        
-       if(handle_data->type != type) {
+       if (handle_data->type != type) {
                return(FALSE);
        }
 
-       if(handle_specific == NULL) {
+       if (handle_specific == NULL) {
                return(FALSE);
        }
        
        if (_WAPI_SHARED_HANDLE(type)) {
-               struct _WapiHandle_shared_ref *ref = &handle_data->u.shared;
+               struct _WapiHandle_shared_ref *ref;
                struct _WapiHandleShared *shared_handle_data;
                struct _WapiHandleSharedMetadata *shared_meta;
-
-               shared_meta = &_wapi_shared_layout->metadata[ref->offset];
-               shared_handle_data = &_wapi_shared_layout->handles[shared_meta->offset];
+               guint32 offset;
+                       
+               /* Unsafe, because we don't want the handle to vanish
+                * while we're checking it
+                */
+               _WAPI_HANDLE_COLLECTION_UNSAFE;
                
-               g_assert(shared_handle_data->type == type);
+               do {
+                       ref = &handle_data->u.shared;
+                       shared_meta = &_wapi_shared_layout->metadata[ref->offset];
+                       offset = shared_meta->offset;
+                       shared_handle_data = &_wapi_shared_layout->handles[offset];
                
-               *handle_specific = &shared_handle_data->u;
+                       g_assert(shared_handle_data->type == type);
+
+                       *handle_specific = &shared_handle_data->u;
+               } while (offset != shared_meta->offset);
+
+               _WAPI_HANDLE_COLLECTION_SAFE;
        } else {
                *handle_specific = &handle_data->u;
        }
@@ -534,7 +573,7 @@ gboolean _wapi_copy_handle (gpointer handle, WapiHandleType type,
                   _wapi_handle_typename[type]);
 #endif
 
-       handle_data = &_wapi_private_handles[handle_idx];
+       handle_data = &_WAPI_PRIVATE_HANDLES(handle_idx);
        
        if(handle_data->type != type) {
 #ifdef DEBUG
@@ -553,8 +592,6 @@ gboolean _wapi_copy_handle (gpointer handle, WapiHandleType type,
                return(FALSE);
        }
        
-       _WAPI_HANDLE_COLLECTION_UNSAFE;
-       
        do {
                ref = &handle_data->u.shared;
                shared_meta = &_wapi_shared_layout->metadata[ref->offset];
@@ -567,8 +604,6 @@ gboolean _wapi_copy_handle (gpointer handle, WapiHandleType type,
                       sizeof(struct _WapiHandleShared));
        } while (offset != shared_meta->offset);
        
-       _WAPI_HANDLE_COLLECTION_SAFE;
-       
 #ifdef DEBUG
        g_message ("%s: OK", __func__);
 #endif
@@ -576,8 +611,8 @@ gboolean _wapi_copy_handle (gpointer handle, WapiHandleType type,
        return(TRUE);
 }
 
-void _wapi_replace_handle (gpointer handle, WapiHandleType type,
-                          struct _WapiHandleShared *handle_specific)
+gboolean _wapi_replace_handle (gpointer handle, WapiHandleType type,
+                              struct _WapiHandleShared *handle_specific)
 {
        struct _WapiHandleShared *shared_handle_data;
        struct _WapiHandleSharedMetadata *shared_meta;
@@ -590,9 +625,9 @@ void _wapi_replace_handle (gpointer handle, WapiHandleType type,
 #endif
 
        g_assert(_WAPI_SHARED_HANDLE(type));
-       g_assert(_wapi_private_handles[handle_idx].type == type);
+       g_assert(_WAPI_PRIVATE_HANDLES(handle_idx).type == type);
        
-       ref = _wapi_private_handles[handle_idx].u.shared.offset;
+       ref = _WAPI_PRIVATE_HANDLES(handle_idx).u.shared.offset;
        shared_meta = &_wapi_shared_layout->metadata[ref];
        
        do {
@@ -602,8 +637,11 @@ void _wapi_replace_handle (gpointer handle, WapiHandleType type,
                        _wapi_handle_collect ();
                        new_off = _wapi_handle_new_shared (type, 
                                                           handle_specific);
-                       /* FIXME: grow the arrays */
-                       g_assert (new_off != 0);
+
+                       if (new_off == 0) {
+                               /* FIXME: grow the arrays */
+                               return (FALSE);
+                       }
                }
                
                shared_handle_data = &_wapi_shared_layout->handles[new_off];
@@ -623,76 +661,48 @@ void _wapi_replace_handle (gpointer handle, WapiHandleType type,
        g_message ("%s: handle at 0x%x is now found at 0x%x", __func__, ref,
                   new_off);
 #endif
+
+       return (TRUE);
 }
 
-gboolean _wapi_try_replace_handle (gpointer handle, WapiHandleType type,
-                                  struct _WapiHandleShared *handle_specific)
+void
+_wapi_handle_foreach (WapiHandleType type,
+                       gboolean (*on_each)(gpointer test, gpointer user),
+                       gpointer user_data)
 {
-       struct _WapiHandleShared *shared_handle_data;
-       struct _WapiHandleSharedMetadata *shared_meta;
-       guint32 handle_idx = GPOINTER_TO_UINT(handle);
-       guint32 old_off, new_off, ref;
-       gboolean ret;
-       
-#ifdef DEBUG
-       g_message ("%s: Trying to replace handle %p of type %s", __func__,
-                  handle, _wapi_handle_typename[type]);
-#endif
-
-       g_assert(_WAPI_SHARED_HANDLE(type));
-       g_assert(_wapi_private_handles[handle_idx].type == type);
-       
-       ref = _wapi_private_handles[handle_idx].u.shared.offset;
-       shared_meta = &_wapi_shared_layout->metadata[ref];
-       
-       old_off = shared_meta->offset;
-       new_off = _wapi_handle_new_shared (type, handle_specific);
-
-       if (new_off == 0) {
-               _wapi_handle_collect ();
-               new_off = _wapi_handle_new_shared (type, handle_specific);
-       
-               /* FIXME: grow the arrays */
-               g_assert (new_off != 0);
-       }
-       
-       shared_handle_data = &_wapi_shared_layout->handles[new_off];
-
-#ifdef DEBUG
-       g_message ("%s: Old offset: 0x%x, trying to move to 0x%x", __func__,
-                  old_off, new_off);
-#endif
-
-       memcpy (shared_handle_data, handle_specific,
-               sizeof(struct _WapiHandleShared));
-       
-       ret = (InterlockedCompareExchange (&shared_meta->offset, new_off,
-                                          old_off) == old_off);
+       struct _WapiHandleUnshared *handle_data = NULL;
+       gpointer ret = NULL;
+       guint32 i, k;
+       int thr_ret;
 
-       if (ret) {
-               /* An entry can't become fresh again (its going to be
-                * collected eventually), so no need for atomic ops
-                * here.
-                */
-               _wapi_shared_layout->handles[old_off].stale = TRUE;
-       }
+       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);
 
-#ifdef DEBUG
-       if (ret) {
-               g_message ("%s: handle at 0x%x is now found at 0x%x", __func__,
-                          ref, new_off);
-       } else {
-               g_message ("%s: handle at 0x%x already updated", __func__,
-                          ref);
+       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;
+                       }
+               }
        }
-#endif
 
-       return(ret);
+       thr_ret = mono_mutex_unlock (&scan_mutex);
+       g_assert (thr_ret == 0);
+       pthread_cleanup_pop (0);
 }
 
-/* This will only find shared handles that have already been opened by
- * this process.  To look up shared handles by name, use
- * _wapi_search_handle_namespace
+/* This might list some shared handles twice if they are already
+ * opened by this process, and the check function returns FALSE the
+ * first time.  Shared handles that are created during the search are
+ * unreffed if the check function returns FALSE, so callers must not
+ * rely on the handle persisting (unless the check function returns
+ * TRUE)
  */
 gpointer _wapi_search_handle (WapiHandleType type,
                              gboolean (*check)(gpointer test, gpointer user),
@@ -700,61 +710,107 @@ gpointer _wapi_search_handle (WapiHandleType type,
                              gpointer *handle_specific)
 {
        struct _WapiHandleUnshared *handle_data = NULL;
-       guint32 i;
+       gpointer ret = NULL;
+       guint32 i, k;
+       gboolean found = FALSE;
+
 
-       for(i = 0; i < _wapi_private_handle_count; i++) {
-               handle_data = &_wapi_private_handles[i];
+       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];
                
-               if(handle_data->type == type) {
-                       if(check (GUINT_TO_POINTER (i), user_data) == TRUE) {
-                               break;
+                       if (handle_data->type == type) {
+                               ret = GUINT_TO_POINTER (i * _WAPI_HANDLE_INITIAL_COUNT + k);
+                               if (check (ret, user_data) == TRUE) {
+                                       found = TRUE;
+                                       break;
+                               }
                        }
                }
        }
 
-       if(i == _wapi_private_handle_count) {
-               return(GUINT_TO_POINTER (0));
+       if (!found) {
+               /* Not found yet, so search the shared memory too */
+#ifdef DEBUG
+               g_message ("%s: Looking at other shared handles...", __func__);
+#endif
+
+               for (i = 0; i < _WAPI_HANDLE_INITIAL_COUNT; i++) {
+                       struct _WapiHandleShared *shared;
+                       struct _WapiHandleSharedMetadata *meta;
+                       WapiHandleType shared_type;
+
+                       _WAPI_HANDLE_COLLECTION_UNSAFE;
+
+                       meta = &_wapi_shared_layout->metadata[i];
+                       shared = &_wapi_shared_layout->handles[meta->offset];
+                       shared_type = shared->type;
+                       
+                       _WAPI_HANDLE_COLLECTION_SAFE;
+                       
+                       if (shared_type == type) {
+                               ret = _wapi_handle_new_from_offset (type, i);
+
+#ifdef DEBUG
+                               g_message ("%s: Opened tmp handle %p (type %s) from offset %d", __func__, ret, _wapi_handle_typename[type], meta->offset);
+#endif
+
+                               if (check (ret, user_data) == TRUE) {
+                                       found = TRUE;
+                                       handle_data = &_WAPI_PRIVATE_HANDLES(GPOINTER_TO_UINT(ret));
+                                       
+                                       break;
+                               }
+                               
+                               /* This isn't the handle we're looking
+                                * for, so drop the reference we took
+                                * in _wapi_handle_new_from_offset ()
+                                */
+                               _wapi_handle_unref (ret);
+                       }
+               }
+       }
+       
+       if (!found) {
+               goto done;
        }
        
        if(handle_specific != NULL) {
                if (_WAPI_SHARED_HANDLE(type)) {
-                       struct _WapiHandle_shared_ref *ref = &handle_data->u.shared;
+                       struct _WapiHandle_shared_ref *ref ;
                        struct _WapiHandleShared *shared_handle_data;
                        struct _WapiHandleSharedMetadata *shared_meta;
+                       guint32 offset, now;
                        
-                       shared_meta = &_wapi_shared_layout->metadata[ref->offset];
-                       shared_handle_data = &_wapi_shared_layout->handles[shared_meta->offset];
+                       /* Unsafe, because we don't want the handle to
+                        * vanish while we're checking it
+                        */
+                       _WAPI_HANDLE_COLLECTION_UNSAFE;
+
+                       do {
+                               ref = &handle_data->u.shared;
+                               shared_meta = &_wapi_shared_layout->metadata[ref->offset];
+                               offset = shared_meta->offset;
+                               shared_handle_data = &_wapi_shared_layout->handles[offset];
                        
-                       g_assert(shared_handle_data->type == type);
+                               g_assert(shared_handle_data->type == type);
                        
-                       *handle_specific = &shared_handle_data->u;
+                               *handle_specific = &shared_handle_data->u;
+                       } while (offset != shared_meta->offset);
+
+                       /* Make sure this handle doesn't vanish in the
+                        * next collection
+                        */
+                       now = (guint32)(time (NULL) & 0xFFFFFFFF);
+                       InterlockedExchange (&shared_meta->timestamp, now);
+
+                       _WAPI_HANDLE_COLLECTION_SAFE;
                } else {
                        *handle_specific = &handle_data->u;
                }
        }
-       
-       return(GUINT_TO_POINTER (i));
-}
-
-/* This signature makes it easier to use in pthread cleanup handlers */
-int _wapi_namespace_timestamp_release (gpointer nowptr)
-{
-       guint32 now = GPOINTER_TO_UINT(nowptr);
-       
-       return (_wapi_timestamp_release (&_wapi_shared_layout->namespace_check,
-                                        now));
-}
 
-int _wapi_namespace_timestamp (guint32 now)
-{
-       int ret;
-       
-       do {
-               ret = _wapi_timestamp_exclusion (&_wapi_shared_layout->namespace_check, now);
-               /* sleep for a bit */
-               _wapi_handle_spin (100);
-       } while (ret == EBUSY);
-       
+done:
        return(ret);
 }
 
@@ -770,7 +826,6 @@ gint32 _wapi_search_handle_namespace (WapiHandleType type,
        gint32 ret = 0;
        
        g_assert(_WAPI_SHARED_HANDLE(type));
-       g_assert(_wapi_shared_layout->namespace_check != 0);
        
 #ifdef DEBUG
        g_message ("%s: Lookup for handle named [%s] type %s", __func__,
@@ -829,13 +884,25 @@ done:
 void _wapi_handle_ref (gpointer handle)
 {
        guint32 idx = GPOINTER_TO_UINT(handle);
+       guint32 now = (guint32)(time (NULL) & 0xFFFFFFFF);
+       struct _WapiHandleUnshared *handle_data = &_WAPI_PRIVATE_HANDLES(idx);
        
-       InterlockedIncrement (&_wapi_private_handles[idx].ref);
-       /* Do shared part */
+       InterlockedIncrement (&handle_data->ref);
+
+       /* It's possible for processes to exit before getting around
+        * to updating timestamps in the collection thread, so if a
+        * shared handle is reffed do the timestamp here as well just
+        * to make sure.
+        */
+       if (_WAPI_SHARED_HANDLE(handle_data->type)) {
+               struct _WapiHandleSharedMetadata *shared_meta = &_wapi_shared_layout->metadata[handle_data->u.shared.offset];
+               
+               InterlockedExchange (&shared_meta->timestamp, now);
+       }
        
 #ifdef DEBUG_REFS
        g_message ("%s: handle %p ref now %d", __func__, handle,
-                  _wapi_private_handles[idx].ref);
+                  _WAPI_PRIVATE_HANDLES(idx).ref);
 #endif
 }
 
@@ -851,46 +918,63 @@ void _wapi_handle_unref (gpointer handle)
         * could lock a mutex, but I'm not sure that allowing a handle
         * reference to reach 0 isn't an application bug anyway.
         */
-       destroy = (InterlockedDecrement (&_wapi_private_handles[idx].ref) ==0);
+       destroy = (InterlockedDecrement (&_WAPI_PRIVATE_HANDLES(idx).ref) ==0);
        
 #ifdef DEBUG_REFS
        g_message ("%s: handle %p ref now %d (destroy %s)", __func__, handle,
-                  _wapi_private_handles[idx].ref, destroy?"TRUE":"FALSE");
+                  _WAPI_PRIVATE_HANDLES(idx).ref, destroy?"TRUE":"FALSE");
 #endif
        
        if(destroy==TRUE) {
+               /* Need to copy the handle info, reset the slot in the
+                * array, and _only then_ call the close function to
+                * avoid race conditions (eg file descriptors being
+                * closed, and another file being opened getting the
+                * same fd racing the memset())
+                */
+               struct _WapiHandleUnshared handle_data;
+               WapiHandleType type = _WAPI_PRIVATE_HANDLES(idx).type;
+               void (*close_func)(gpointer, gpointer) = _wapi_handle_ops_get_close_func (type);
+
 #ifdef DEBUG
                g_message ("%s: Destroying handle %p", __func__, handle);
 #endif
                
-               _wapi_handle_ops_close (handle);
+               memcpy (&handle_data, &_WAPI_PRIVATE_HANDLES(idx),
+                       sizeof (struct _WapiHandleUnshared));
 
-               memset (&_wapi_private_handles[idx].u, '\0',
-                       sizeof(_wapi_private_handles[idx].u));
+               memset (&_WAPI_PRIVATE_HANDLES(idx).u, '\0',
+                       sizeof(_WAPI_PRIVATE_HANDLES(idx).u));
 
-               _wapi_private_handles[idx].type = WAPI_HANDLE_UNUSED;
+               _WAPI_PRIVATE_HANDLES(idx).type = WAPI_HANDLE_UNUSED;
                
-               /* Destroy the mutex and cond var.  We hope nobody
-                * tried to grab them between the handle unlock and
-                * now, but pthreads doesn't have a
-                * "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);
+               if (!_WAPI_SHARED_HANDLE(type)) {
+                       /* Destroy the mutex and cond var.  We hope nobody
+                        * tried to grab them between the handle unlock and
+                        * now, but pthreads doesn't have a
+                        * "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);
+               }
 
                /* The garbage collector will take care of shared data
                 * if this is a shared handle
                 */
+               
+               if (close_func != NULL) {
+                       close_func (handle, &handle_data.u);
+               }
        }
 }
 
 void _wapi_handle_register_capabilities (WapiHandleType type,
                                         WapiHandleCapability caps)
 {
-       handle_caps[type]=caps;
+       handle_caps[type] = caps;
 }
 
 gboolean _wapi_handle_test_capabilities (gpointer handle,
@@ -899,7 +983,7 @@ gboolean _wapi_handle_test_capabilities (gpointer handle,
        guint32 idx = GPOINTER_TO_UINT(handle);
        WapiHandleType type;
 
-       type = _wapi_private_handles[idx].type;
+       type = _WAPI_PRIVATE_HANDLES(idx).type;
 
 #ifdef DEBUG
        g_message ("%s: testing 0x%x against 0x%x (%d)", __func__,
@@ -909,16 +993,26 @@ gboolean _wapi_handle_test_capabilities (gpointer handle,
        return((handle_caps[type] & caps) != 0);
 }
 
-void _wapi_handle_ops_close (gpointer handle)
+static void (*_wapi_handle_ops_get_close_func (WapiHandleType type))(gpointer, gpointer)
+{
+       if (handle_ops[type] != NULL &&
+           handle_ops[type]->close != NULL) {
+               return (handle_ops[type]->close);
+       }
+
+       return (NULL);
+}
+
+void _wapi_handle_ops_close (gpointer handle, gpointer data)
 {
        guint32 idx = GPOINTER_TO_UINT(handle);
        WapiHandleType type;
 
-       type = _wapi_private_handles[idx].type;
+       type = _WAPI_PRIVATE_HANDLES(idx).type;
 
        if (handle_ops[type] != NULL &&
            handle_ops[type]->close != NULL) {
-               handle_ops[type]->close (handle);
+               handle_ops[type]->close (handle, data);
        }
 }
 
@@ -927,7 +1021,7 @@ void _wapi_handle_ops_signal (gpointer handle)
        guint32 idx = GPOINTER_TO_UINT(handle);
        WapiHandleType type;
 
-       type = _wapi_private_handles[idx].type;
+       type = _WAPI_PRIVATE_HANDLES(idx).type;
 
        if (handle_ops[type] != NULL && handle_ops[type]->signal != NULL) {
                handle_ops[type]->signal (handle);
@@ -939,7 +1033,7 @@ gboolean _wapi_handle_ops_own (gpointer handle)
        guint32 idx = GPOINTER_TO_UINT(handle);
        WapiHandleType type;
        
-       type = _wapi_private_handles[idx].type;
+       type = _WAPI_PRIVATE_HANDLES(idx).type;
 
        if (handle_ops[type] != NULL && handle_ops[type]->own_handle != NULL) {
                return(handle_ops[type]->own_handle (handle));
@@ -953,7 +1047,7 @@ gboolean _wapi_handle_ops_isowned (gpointer handle)
        guint32 idx = GPOINTER_TO_UINT(handle);
        WapiHandleType type;
 
-       type = _wapi_private_handles[idx].type;
+       type = _WAPI_PRIVATE_HANDLES(idx).type;
 
        if (handle_ops[type] != NULL && handle_ops[type]->is_owned != NULL) {
                return(handle_ops[type]->is_owned (handle));
@@ -962,6 +1056,22 @@ gboolean _wapi_handle_ops_isowned (gpointer handle)
        }
 }
 
+guint32 _wapi_handle_ops_special_wait (gpointer handle, guint32 timeout)
+{
+       guint32 idx = GPOINTER_TO_UINT(handle);
+       WapiHandleType type;
+       
+       type = _WAPI_PRIVATE_HANDLES(idx).type;
+       
+       if (handle_ops[type] != NULL &&
+           handle_ops[type]->special_wait != NULL) {
+               return(handle_ops[type]->special_wait (handle, timeout));
+       } else {
+               return(WAIT_FAILED);
+       }
+}
+
+
 /**
  * CloseHandle:
  * @handle: The handle to release
@@ -975,10 +1085,6 @@ gboolean _wapi_handle_ops_isowned (gpointer handle)
  */
 gboolean CloseHandle(gpointer handle)
 {
-       if (handle == NULL) {
-               return(FALSE);
-       }
-
        _wapi_handle_unref (handle);
        
        return(TRUE);
@@ -997,40 +1103,20 @@ gboolean _wapi_handle_count_signalled_handles (guint32 numhandles,
        
        /* Lock all the handles, with backoff */
 again:
+       thr_ret = _wapi_handle_lock_shared_handles ();
+       g_assert (thr_ret == 0);
+       
        for(i=0; i<numhandles; i++) {
                gpointer handle = handles[i];
                guint32 idx = GPOINTER_TO_UINT(handle);
-               guint32 now = (guint32)(time(NULL) & 0xFFFFFFFF);
 
 #ifdef DEBUG
                g_message ("%s: attempting to lock %p", __func__, handle);
 #endif
 
-               type = _wapi_private_handles[idx].type;
+               type = _WAPI_PRIVATE_HANDLES(idx).type;
 
-               if (_WAPI_SHARED_HANDLE(type)) {
-                       /* We don't lock shared handles, but we need
-                        * to be able to simultaneously check the
-                        * signal state of all handles in the array
-                        *
-                        * We do this by atomically putting the
-                        * least-significant 32 bits of time(2) into
-                        * the 'checking' field if it is zero.  If it
-                        * isn't zero, then it means that either
-                        * another thread is looking at this handle
-                        * right now, or someone crashed here.  Assume
-                        * that if the time value is more than 10
-                        * seconds old, its a crash and override it.
-                        * 10 seconds should be enough for anyone...
-                        *
-                        * If the time value is within 10 seconds,
-                        * back off and try again as per the
-                        * non-shared case.
-                        */
-                       thr_ret = _wapi_timestamp_exclusion (&WAPI_SHARED_HANDLE_METADATA(handle).checking, now);
-               } else {
-                       thr_ret = _wapi_handle_trylock_handle (handle);
-               }
+               thr_ret = _wapi_handle_trylock_handle (handle);
                
                if (thr_ret != 0) {
                        /* Bummer */
@@ -1040,16 +1126,14 @@ again:
                                   handle, strerror (thr_ret));
 #endif
 
+                       thr_ret = _wapi_handle_unlock_shared_handles ();
+                       g_assert (thr_ret == 0);
+                       
                        while (i--) {
                                handle = handles[i];
                                idx = GPOINTER_TO_UINT(handle);
 
-                               if (_WAPI_SHARED_HANDLE(type)) {
-                                       /* Reset the checking field */
-                                       thr_ret = _wapi_timestamp_release (&WAPI_SHARED_HANDLE_METADATA(handle).checking, now);
-                               } else{
-                                       thr_ret = _wapi_handle_unlock_handle (handle);
-                               }
+                               thr_ret = _wapi_handle_unlock_handle (handle);
                                g_assert (thr_ret == 0);
                        }
 
@@ -1085,7 +1169,7 @@ again:
                gpointer handle = handles[i];
                guint32 idx = GPOINTER_TO_UINT(handle);
                
-               type = _wapi_private_handles[idx].type;
+               type = _WAPI_PRIVATE_HANDLES(idx).type;
 
                _wapi_handle_ref (handle);
                
@@ -1098,7 +1182,7 @@ again:
                   (_WAPI_SHARED_HANDLE(type) &&
                    WAPI_SHARED_HANDLE_METADATA(handle).signalled == TRUE) ||
                   (!_WAPI_SHARED_HANDLE(type) &&
-                   _wapi_private_handles[idx].signalled == TRUE)) {
+                   _WAPI_PRIVATE_HANDLES(idx).signalled == TRUE)) {
                        count++;
                        
 #ifdef DEBUG
@@ -1136,334 +1220,123 @@ void _wapi_handle_unlock_handles (guint32 numhandles, gpointer *handles)
        guint32 i;
        int thr_ret;
        
+       thr_ret = _wapi_handle_unlock_shared_handles ();
+       g_assert (thr_ret == 0);
+       
        for(i=0; i<numhandles; i++) {
                gpointer handle = handles[i];
-               guint32 idx = GPOINTER_TO_UINT(handle);
-               WapiHandleType type = _wapi_private_handles[idx].type;
                
 #ifdef DEBUG
                g_message ("%s: unlocking handle %p", __func__, handle);
 #endif
 
-               if (_WAPI_SHARED_HANDLE(type)) {
-                       WAPI_SHARED_HANDLE_METADATA(handle).checking = 0;
-               } else {
-                       thr_ret = mono_mutex_unlock (&_wapi_private_handles[idx].signal_mutex);
-                       g_assert (thr_ret == 0);
-               }
+               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)
+{
+       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);
+       } else {
+               ret=mono_cond_timedwait (cond, mutex, &fake_timeout);
 
-               _wapi_handle_unref (handle);
+               /* 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)
 {
-       return(mono_cond_wait (&_wapi_global_signal_cond,
-                              &_wapi_global_signal_mutex));
+       return timedwait_signal_poll_cond (&_wapi_global_signal_cond, &_wapi_global_signal_mutex, NULL);
 }
 
 int _wapi_handle_timedwait_signal (struct timespec *timeout)
 {
-       return(mono_cond_timedwait (&_wapi_global_signal_cond,
-                                   &_wapi_global_signal_mutex,
-                                   timeout));
+       return timedwait_signal_poll_cond (&_wapi_global_signal_cond, &_wapi_global_signal_mutex, timeout);
 }
 
 int _wapi_handle_wait_signal_poll_share (void)
 {
-       struct timespec fake_timeout;
-       guint32 signal_count = _wapi_shared_layout->signal_count;
-       int ret;
-       
 #ifdef DEBUG
        g_message ("%s: poll private and shared handles", __func__);
 #endif
-
-       while(1) {
-               _wapi_calc_timeout (&fake_timeout, 100);
        
-               ret = mono_cond_timedwait (&_wapi_global_signal_cond,
-                                          &_wapi_global_signal_mutex,
-                                          &fake_timeout);
-       
-               /* Check the shared signal counter */
-               if (ret == ETIMEDOUT) {
-                       if (signal_count != _wapi_shared_layout->signal_count) {
-#ifdef DEBUG
-                               g_message ("%s: A shared handle was signalled",
-                                          __func__);
-#endif
-
-                               return (0);
-                       }
-               } else {
-                       /* This will be 0 indicating a private handle
-                        * was signalled, or an error
-                        */
-#ifdef DEBUG
-                       g_message ("%s: returning: %d", __func__, ret);
-#endif
-
-                       return (ret);
-               }
-
-               /* If timeout and no shared handle was signalled, go
-                * round again
-                */
-       }
+       return timedwait_signal_poll_cond (&_wapi_global_signal_cond, &_wapi_global_signal_mutex, NULL);
 }
 
 int _wapi_handle_timedwait_signal_poll_share (struct timespec *timeout)
 {
-       struct timespec fake_timeout;
-       guint32 signal_count = _wapi_shared_layout->signal_count;
-       int ret;
-       
 #ifdef DEBUG
        g_message ("%s: poll private and shared handles", __func__);
 #endif
        
-       do {
-               _wapi_calc_timeout (&fake_timeout, 100);
-       
-               if ((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 */
-
-#ifdef DEBUG
-                       g_message ("%s: last few ms", __func__);
-#endif
-
-                       ret = mono_cond_timedwait (&_wapi_global_signal_cond,
-                                                  &_wapi_global_signal_mutex,
-                                                  timeout);
-               } else {
-                       ret = mono_cond_timedwait (&_wapi_global_signal_cond,
-                                                  &_wapi_global_signal_mutex,
-                                                  &fake_timeout);
-
-                       /* Mask the fake timeout, this will cause
-                        * another poll if the shared counter hasn't
-                        * changed
-                        */
-                       if (ret == ETIMEDOUT) {
-                               ret = 0;
-                       }
-               }
-
-               if (ret != ETIMEDOUT) {
-                       /* Either a private handle was signalled, or
-                        * an error
-                        */
-#ifdef DEBUG
-                       g_message ("%s: returning: %d", __func__, ret);
-#endif
-                       return (ret);
-               }
-
-               /* Check the shared signal counter */
-               if (signal_count != _wapi_shared_layout->signal_count) {
-#ifdef DEBUG
-                               g_message ("%s: A shared handle was signalled",
-                                          __func__);
-#endif
-                       return (0);
-               }
-       } while (ret != ETIMEDOUT);
-
-#ifdef DEBUG
-       g_message ("%s: returning ETIMEDOUT", __func__);
-#endif
-
-       return (ret);
+       return timedwait_signal_poll_cond (&_wapi_global_signal_cond, &_wapi_global_signal_mutex, timeout);
 }
 
 int _wapi_handle_wait_signal_handle (gpointer handle)
 {
-       guint32 idx = GPOINTER_TO_UINT(handle);
-       
 #ifdef DEBUG
        g_message ("%s: waiting for %p", __func__, handle);
 #endif
        
-       if (_WAPI_SHARED_HANDLE (_wapi_handle_type (handle))) {
-               while(1) {
-                       if (WAPI_SHARED_HANDLE_METADATA(handle).signalled == TRUE) {
-                               return (0);
-                       }
-                       
-                       _wapi_handle_spin (100);
-               }
-       } else {
-               return(mono_cond_wait (&_wapi_private_handles[idx].signal_cond,
-                                      &_wapi_private_handles[idx].signal_mutex));
-       }
+       return _wapi_handle_timedwait_signal_handle (handle, NULL);
 }
 
 int _wapi_handle_timedwait_signal_handle (gpointer handle,
                                          struct timespec *timeout)
 {
-       guint32 idx = GPOINTER_TO_UINT(handle);
-       
 #ifdef DEBUG
        g_message ("%s: waiting for %p (type %s)", __func__, handle,
                   _wapi_handle_typename[_wapi_handle_type (handle)]);
 #endif
        
        if (_WAPI_SHARED_HANDLE (_wapi_handle_type (handle))) {
-               struct timespec fake_timeout;
-
-               while (1) {
-                       if (WAPI_SHARED_HANDLE_METADATA(handle).signalled == TRUE) {
-                               return (0);
-                       }
-               
+               if (WAPI_SHARED_HANDLE_METADATA(handle).signalled == TRUE) {
+                       return (0);
+               }
+               if (timeout != NULL) {
+                       struct timespec fake_timeout;
                        _wapi_calc_timeout (&fake_timeout, 100);
                
                        if ((fake_timeout.tv_sec > timeout->tv_sec) ||
-                           (fake_timeout.tv_sec == timeout->tv_sec &&
-                            fake_timeout.tv_nsec > timeout->tv_nsec)) {
+                               (fake_timeout.tv_sec == timeout->tv_sec &&
+                                fake_timeout.tv_nsec > timeout->tv_nsec)) {
                                /* FIXME: Real timeout is less than
                                 * 100ms time, but is it really worth
                                 * calculating to the exact ms?
                                 */
                                _wapi_handle_spin (100);
-                               
+
                                if (WAPI_SHARED_HANDLE_METADATA(handle).signalled == TRUE) {
                                        return (0);
                                } else {
                                        return (ETIMEDOUT);
                                }
-                       } else {
-                               _wapi_handle_spin (100);
-                       }
-               }
-       } else {
-               return(mono_cond_timedwait (&_wapi_private_handles[idx].signal_cond, &_wapi_private_handles[idx].signal_mutex, timeout));
-       }
-}
-
-gboolean _wapi_handle_process_fork (guint32 cmd, guint32 env, guint32 dir,
-                                   gboolean inherit, guint32 flags,
-                                   gpointer stdin_handle,
-                                   gpointer stdout_handle,
-                                   gpointer stderr_handle,
-                                   gpointer *process_handle,
-                                   gpointer *thread_handle, guint32 *pid,
-                                   guint32 *tid)
-{
-#if 0
-       WapiHandleRequest fork_proc={0};
-       WapiHandleResponse fork_proc_resp={0};
-       int in_fd, out_fd, err_fd;
-       
-       if(shared!=TRUE) {
-               return(FALSE);
-       }
-
-       fork_proc.type=WapiHandleRequestType_ProcessFork;
-       fork_proc.u.process_fork.cmd=cmd;
-       fork_proc.u.process_fork.env=env;
-       fork_proc.u.process_fork.dir=dir;
-       fork_proc.u.process_fork.stdin_handle=GPOINTER_TO_UINT (stdin_handle);
-       fork_proc.u.process_fork.stdout_handle=GPOINTER_TO_UINT (stdout_handle);
-       fork_proc.u.process_fork.stderr_handle=GPOINTER_TO_UINT (stderr_handle);
-       fork_proc.u.process_fork.inherit=inherit;
-       fork_proc.u.process_fork.flags=flags;
-       
-       in_fd = GPOINTER_TO_UINT (stdin_handle);
-       out_fd = GPOINTER_TO_UINT (stdout_handle);
-       err_fd = GPOINTER_TO_UINT (stderr_handle);
-
-       if(in_fd==-1 || out_fd==-1 || err_fd==-1) {
-               /* We were given duff handles */
-               /* FIXME: error code */
-               return(FALSE);
-       }
-       
-       _wapi_daemon_request_response_with_fds (daemon_sock, &fork_proc,
-                                               &fork_proc_resp, in_fd,
-                                               out_fd, err_fd);
-       if(fork_proc_resp.type==WapiHandleResponseType_ProcessFork) {
-               *process_handle=GUINT_TO_POINTER (fork_proc_resp.u.process_fork.process_handle);
-               *thread_handle=GUINT_TO_POINTER (fork_proc_resp.u.process_fork.thread_handle);
-               *pid=fork_proc_resp.u.process_fork.pid;
-               *tid=fork_proc_resp.u.process_fork.tid;
-
-               /* If there was an internal error, the handles will be
-                * 0.  If there was an error forking or execing, the
-                * handles will have values, and process_handle's
-                * exec_errno will be set, and the handle will be
-                * signalled immediately.
-                */
-               if(*process_handle==0 || *thread_handle==0) {
-                       return(FALSE);
-               } else {
-                       /* This call returns new handles, so we need to do
-                        * a little bookkeeping
-                        */
-                       if (_wapi_private_data != NULL) {
-                               guint32 segment, idx;
-
-                               _wapi_handle_segment (*process_handle,
-                                                     &segment, &idx);
-                               _wapi_handle_ensure_mapped (segment);
-                               _wapi_handle_get_private_segment (segment)->handles[idx].type = WAPI_HANDLE_PROCESS;
-
-                               _wapi_handle_segment (*thread_handle,
-                                                     &segment, &idx);
-                               _wapi_handle_ensure_mapped (segment);
-                               _wapi_handle_get_private_segment (segment)->handles[idx].type = WAPI_HANDLE_THREAD;
                        }
-
-                       return(TRUE);
                }
+               _wapi_handle_spin (100);
+               return (0);
+               
        } else {
-               g_warning ("%s: bogus daemon response, type %d", __func__,
-                          fork_proc_resp.type);
-               g_assert_not_reached ();
-       }
-       
-       return(FALSE);
-#else
-       return(FALSE);
-#endif
-}
-
-gboolean
-_wapi_handle_process_kill (pid_t process, guint32 signo, gint *errnum)
-{
-#if 0
-       WapiHandleRequest killproc = {0};
-       WapiHandleResponse killprocresp = {0};
-       gint result;
-       
-       if (shared != TRUE) {
-               if (errnum) *errnum = EINVAL;
-               return FALSE;
-       }
-
-       killproc.type = WapiHandleRequestType_ProcessKill;
-       killproc.u.process_kill.pid = process;
-       killproc.u.process_kill.signo = signo;
-       
-       _wapi_daemon_request_response (daemon_sock, &killproc, &killprocresp);
-
-       if (killprocresp.type != WapiHandleResponseType_ProcessKill) {
-               g_warning ("%s: bogus daemon response, type %d", __func__,
-                          killprocresp.type);
-               g_assert_not_reached ();
+               guint32 idx = GPOINTER_TO_UINT(handle);
+               return timedwait_signal_poll_cond (&_WAPI_PRIVATE_HANDLES(idx).signal_cond, &_WAPI_PRIVATE_HANDLES(idx).signal_mutex, timeout);
        }
-
-       result = killprocresp.u.process_kill.err;
-       if (result != 0 && errnum != NULL)
-               *errnum = (result == FALSE) ? result : 0;
-       
-       return (result == 0);
-#else
-       return(FALSE);
-#endif
 }
 
 gboolean _wapi_handle_get_or_set_share (dev_t device, ino_t inode,
@@ -1484,7 +1357,7 @@ gboolean _wapi_handle_get_or_set_share (dev_t device, ino_t inode,
        _WAPI_HANDLE_COLLECTION_UNSAFE;
        
        /* Prevent new entries racing with us */
-       thr_ret = _wapi_timestamp_exclusion (&_wapi_fileshare_layout->share_check, now);
+       thr_ret = _wapi_shm_sem_lock (_WAPI_SHARED_SEM_SHARE);
        g_assert (thr_ret == 0);
        
        /* If a linear scan gets too slow we'll have to fit a hash
@@ -1537,21 +1410,46 @@ gboolean _wapi_handle_get_or_set_share (dev_t device, ino_t inode,
                        
                        file_share->device = device;
                        file_share->inode = inode;
+                       file_share->opened_by_pid = 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 (&(*share_info)->timestamp, now);
+       }
        
-       thr_ret = _wapi_timestamp_release (&_wapi_fileshare_layout->share_check, now);
-       g_assert (thr_ret == 0);
+       thr_ret = _wapi_shm_sem_unlock (_WAPI_SHARED_SEM_SHARE);
 
        _WAPI_HANDLE_COLLECTION_SAFE;
 
        return(exists);
 }
 
+/* If we don't have the info in /proc, check if the process that
+ * opened this share info is still there (it's not a perfect method,
+ * due to pid reuse)
+ */
+static void _wapi_handle_check_share_by_pid (struct _WapiFileShare *share_info)
+{
+       if (kill (share_info->opened_by_pid, 0) == -1 &&
+           (errno == ESRCH ||
+            errno == EPERM)) {
+               /* It's gone completely (or there's a new process
+                * owned by someone else) so mark this share info as
+                * dead
+                */
+#ifdef DEBUG
+               g_message ("%s: Didn't find it, destroying entry", __func__);
+#endif
+
+               memset (share_info, '\0', sizeof(struct _WapiFileShare));
+       }
+}
+
 /* Scan /proc/<pids>/fd/ for open file descriptors to the file in
  * question.  If there are none, reset the share info.
  *
@@ -1559,18 +1457,16 @@ gboolean _wapi_handle_get_or_set_share (dev_t device, ino_t inode,
  * implement their own ways of finding out if a particular file is
  * open by a process.
  */
-void _wapi_handle_check_share (struct _WapiFileShare *share_info)
+void _wapi_handle_check_share (struct _WapiFileShare *share_info, int fd)
 {
-       DIR *proc_dir;
-       struct dirent *proc_entry;
-       gboolean found = FALSE;
+       gboolean found = FALSE, proc_fds = FALSE;
        pid_t self = getpid();
        int pid;
-       guint32 now = (guint32)(time(NULL) & 0xFFFFFFFF);
-       int thr_ret;
+       int thr_ret, i;
        
-       proc_dir = opendir ("/proc");
-       if (proc_dir == NULL) {
+       /* If there is no /proc, there's nothing more we can do here */
+       if (access ("/proc", F_OK) == -1) {
+               _wapi_handle_check_share_by_pid (share_info);
                return;
        }
        
@@ -1580,20 +1476,29 @@ void _wapi_handle_check_share (struct _WapiFileShare *share_info)
        _WAPI_HANDLE_COLLECTION_UNSAFE;
        
        /* Prevent new entries racing with us */
-       thr_ret = _wapi_timestamp_exclusion (&_wapi_fileshare_layout->share_check, now);
+       thr_ret = _wapi_shm_sem_lock (_WAPI_SHARED_SEM_SHARE);
        g_assert (thr_ret == 0);
 
-       while ((proc_entry = readdir (proc_dir)) != NULL) {
-               /* We only care about numerically-named directories */
-               pid = atoi (proc_entry->d_name);
-               if (pid != 0 && pid != self) {
-                       /* Look in /proc/<pid>/fd/ but ignore
-                        * ourselves, as we have the file open too
-                        */
+       for (i = 0; i < _WAPI_HANDLE_INITIAL_COUNT; i++) {
+               struct _WapiHandleShared *shared;
+               struct _WapiHandleSharedMetadata *meta;
+               struct _WapiHandle_process *process_handle;
+
+               meta = &_wapi_shared_layout->metadata[i];
+               shared = &_wapi_shared_layout->handles[meta->offset];
+               
+               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);
                        
@@ -1601,13 +1506,21 @@ void _wapi_handle_check_share (struct _WapiFileShare *share_info)
                        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, "..")) {
+                                   !strcmp (fd_entry->d_name, "..") ||
+                                   (pid == self &&
+                                    fd == atoi (fd_entry->d_name))) {
                                        continue;
                                }
 
@@ -1630,10 +1543,10 @@ void _wapi_handle_check_share (struct _WapiFileShare *share_info)
                        closedir (fd_dir);
                }
        }
-       
-       closedir (proc_dir);
 
-       if (found == FALSE) {
+       if (proc_fds == FALSE) {
+               _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__);
@@ -1642,8 +1555,7 @@ void _wapi_handle_check_share (struct _WapiFileShare *share_info)
                memset (share_info, '\0', sizeof(struct _WapiFileShare));
        }
 
-       thr_ret = _wapi_timestamp_release (&_wapi_fileshare_layout->share_check, now);
-       g_assert (thr_ret == 0);
+       thr_ret = _wapi_shm_sem_unlock (_WAPI_SHARED_SEM_SHARE);
 
        _WAPI_HANDLE_COLLECTION_SAFE;
 }
@@ -1651,20 +1563,24 @@ void _wapi_handle_check_share (struct _WapiFileShare *share_info)
 void _wapi_handle_dump (void)
 {
        struct _WapiHandleUnshared *handle_data;
-       guint32 i;
+       guint32 i, k;
 
-       for (i = 0; i < _wapi_private_handle_count; i++) {
-               handle_data = &_wapi_private_handles[i];
+       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 == WAPI_HANDLE_UNUSED) {
-                       continue;
-               }
+                       if (handle_data->type == WAPI_HANDLE_UNUSED) {
+                               continue;
+                       }
                
-               g_print ("%3x [%7s] %s %d ", i,
-                        _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");
+               }
        }
 }
 
@@ -1677,36 +1593,59 @@ static void _wapi_shared_details (gpointer handle_info)
 
 void _wapi_handle_update_refs (void)
 {
-       guint32 i;
+       guint32 i, k;
+       int thr_ret;
        
-       for (i = 0; i < _wapi_private_handle_count; i++) {
-               struct _WapiHandleUnshared *handle = &_wapi_private_handles[i];
-               guint32 now = (guint32)(time (NULL) & 0xFFFFFFFF);
+       _WAPI_HANDLE_COLLECTION_UNSAFE;
 
-               if (_WAPI_SHARED_HANDLE(handle->type)) {
-                       struct _WapiHandleSharedMetadata *shared_meta;
-                       
-                       shared_meta = &_wapi_shared_layout->metadata[handle->u.shared.offset];
+       /* Prevent file share entries racing with us */
+       thr_ret = _wapi_shm_sem_lock (_WAPI_SHARED_SEM_SHARE);
+       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 = &_wapi_private_handles [i][k];
+                       guint32 now = (guint32)(time (NULL) & 0xFFFFFFFF);
 
+                       if (_WAPI_SHARED_HANDLE(handle->type)) {
+                               struct _WapiHandleSharedMetadata *shared_meta;
+                               
 #ifdef DEBUG
-                       g_message ("%s: (%d) Updating timstamp of handle 0x%x",
-                                  __func__, getpid(),
-                                  handle->u.shared.offset);
+                               g_message ("%s: (%d) handle 0x%x is SHARED (%s)", __func__,
+                                          getpid (), i * _WAPI_HANDLE_INITIAL_COUNT + k, _wapi_handle_typename[handle->type]);
 #endif
 
-                       InterlockedExchange (&shared_meta->timestamp, now);
-               } else if (handle->type == WAPI_HANDLE_FILE) {
-                       struct _WapiHandle_file *file_handle = &handle->u.file;
-                       
-                       g_assert (file_handle->share_info != NULL);
+                               shared_meta = &_wapi_shared_layout->metadata[handle->u.shared.offset];
 
 #ifdef DEBUG
-                       g_message ("%s: (%d) Inc refs on fileshare 0x%x",
-                                  __func__, getpid(),
-                                  (file_handle->share_info - &_wapi_fileshare_layout->share_info[0]) / sizeof(struct _WapiFileShare));
+                               g_message ("%s: (%d) Updating timestamp of handle 0x%x",
+                                          __func__, getpid(),
+                                          handle->u.shared.offset);
 #endif
 
-                       InterlockedExchange (&file_handle->share_info->timestamp, now);
+                               InterlockedExchange (&shared_meta->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__,
+                                          getpid (), i * _WAPI_HANDLE_INITIAL_COUNT + k);
+#endif
+                               
+                               g_assert (file_handle->share_info != NULL);
+
+#ifdef DEBUG
+                               g_message ("%s: (%d) Inc refs on fileshare 0x%x",
+                                          __func__, getpid(),
+                                          (file_handle->share_info - &_wapi_fileshare_layout->share_info[0]) / sizeof(struct _WapiFileShare));
+#endif
+
+                               InterlockedExchange (&file_handle->share_info->timestamp, now);
+                       }
                }
        }
+       
+       thr_ret = _wapi_shm_sem_unlock (_WAPI_SHARED_SEM_SHARE);
+
+       _WAPI_HANDLE_COLLECTION_SAFE;
 }