More locking for file shares
[mono.git] / mono / io-layer / handles.c
index 769235fe76d89584bcd65bc2fac0881b1a63f1fa..c388ba1d60ac701704b278738c637bbc23ded37e 100644 (file)
@@ -17,6 +17,8 @@
 #include <sys/socket.h>
 #include <sys/un.h>
 #include <sys/mman.h>
+#include <dirent.h>
+#include <sys/stat.h>
 
 #include <mono/os/gc_wrapper.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/shared.h>
 #include <mono/io-layer/misc-private.h>
-#include <mono/io-layer/daemon-messages.h>
+#include <mono/io-layer/shared.h>
+#include <mono/io-layer/collection.h>
 
 #undef DEBUG
-#undef HEAVY_DEBUG /* This will print handle counts on every handle created */
-
-/* Shared threads don't seem to work yet */
-#undef _POSIX_THREAD_PROCESS_SHARED
-
-/*
- * This flag _MUST_ remain set to FALSE in the daemon process.  When
- * we exec()d a standalone daemon, that happened because shared_init()
- * didnt get called in the daemon process.  Now we just fork() without
- * exec(), we need to ensure that the fork() happens when shared is
- * still FALSE.
- *
- * This is further complicated by the second attempt to start the
- * daemon if the connect() fails.
- */
-static gboolean shared=FALSE;
+#undef DEBUG_REFS
 
 static WapiHandleCapability handle_caps[WAPI_HANDLE_COUNT]={0};
 static struct _WapiHandleOps *handle_ops[WAPI_HANDLE_COUNT]={
@@ -59,1212 +46,940 @@ static struct _WapiHandleOps *handle_ops[WAPI_HANDLE_COUNT]={
        &_wapi_find_ops,
        &_wapi_process_ops,
        &_wapi_pipe_ops,
+       &_wapi_namedmutex_ops,
+};
+
+static void _wapi_shared_details (gpointer handle_info);
+
+static void (*handle_details[WAPI_HANDLE_COUNT])(gpointer) = {
+       NULL,
+       _wapi_file_details,
+       _wapi_console_details,
+       _wapi_shared_details,   /* thread */
+       _wapi_sem_details,
+       _wapi_mutex_details,
+       _wapi_event_details,
+       NULL,                   /* Nothing useful to see in a socket handle */
+       NULL,                   /* Nothing useful to see in a find handle */
+       _wapi_shared_details,   /* process */
+       _wapi_pipe_details,
+       _wapi_shared_details,   /* namedmutex */
+};
+
+const char *_wapi_handle_typename[] = {
+       "Unused",
+       "File",
+       "Console",
+       "Thread",
+       "Sem",
+       "Mutex",
+       "Event",
+       "Socket",
+       "Find",
+       "Process",
+       "Pipe",
+       "N.Mutex",
+       "Error!!"
 };
 
-static int daemon_sock;
+struct _WapiHandleUnshared *_wapi_private_handles = NULL;
+static guint32 _wapi_private_handle_count = 0;
 
-static pthread_mutexattr_t mutex_shared_attr;
-static pthread_condattr_t cond_shared_attr;
+struct _WapiHandleSharedLayout *_wapi_shared_layout = NULL;
+struct _WapiFileShareLayout *_wapi_fileshare_layout = NULL;
 
-struct _WapiHandleShared_list **_wapi_shared_data=NULL;
-struct _WapiHandleScratch *_wapi_shared_scratch=NULL;
-struct _WapiHandlePrivate_list **_wapi_private_data=NULL;
-pthread_mutex_t _wapi_shared_mutex=PTHREAD_MUTEX_INITIALIZER;
+guint32 _wapi_fd_reserve;
 
-/* This holds the length of the _wapi_shared_data and
- * _wapi_private_data arrays, so we know if a segment is off the end
- * of the array, requiring a realloc
- */
-guint32 _wapi_shm_mapped_segments;
+mono_mutex_t _wapi_global_signal_mutex;
+pthread_cond_t _wapi_global_signal_cond;
 
+static mono_once_t shared_init_once = MONO_ONCE_INIT;
 static void shared_init (void)
 {
-       struct sockaddr_un shared_socket_address;
-       gboolean tried_once=FALSE;
-       int ret;
        int thr_ret;
        
-       _wapi_shared_data=g_new0 (struct _WapiHandleShared_list *, 1);
-       _wapi_private_data=g_new0 (struct _WapiHandlePrivate_list *, 1);
-       
-attach_again:
+       _wapi_fd_reserve = getdtablesize();
 
-#ifndef DISABLE_SHARED_HANDLES
-       if(getenv ("MONO_DISABLE_SHM"))
-#endif
-       {
-               shared=FALSE;
-#ifndef DISABLE_SHARED_HANDLES
-       } else {
-               /* Ensure that shared==FALSE while _wapi_shm_attach()
-                * calls fork()
-                */
-               shared=FALSE;
-               
-               shared=_wapi_shm_attach (&_wapi_shared_data[0],
-                                        &_wapi_shared_scratch);
-               if(shared==FALSE) {
-                       g_warning (
-                               "Failed to attach shared memory! "
-                               "Falling back to non-shared handles\n"
-                               "See: http://www.go-mono.com/issues.html#wapi for details");
-               }
-#endif /* DISABLE_SHARED_HANDLES */
-       }
+       _wapi_private_handle_count = _WAPI_HANDLE_INITIAL_COUNT;
        
-
-       if(shared==TRUE) {
-               daemon_sock=socket (PF_UNIX, SOCK_STREAM, 0);
-               shared_socket_address.sun_family=AF_UNIX;
-               memcpy (shared_socket_address.sun_path,
-                       _wapi_shared_data[0]->daemon, MONO_SIZEOF_SUNPATH);
-               ret=connect (daemon_sock,
-                            (struct sockaddr *)&shared_socket_address,
-                            sizeof(struct sockaddr_un));
-               if(ret==-1) {
-                       if(tried_once==TRUE) {
-                               g_warning (G_GNUC_PRETTY_FUNCTION
-                                          ": connect to daemon failed: %s",
-                                          g_strerror (errno));
-                               /* Fall back to private handles */
-                               shared=FALSE;
-                       } else {
-                               /* It's possible that the daemon
-                                * crashed without destroying the
-                                * shared memory segment (thus fooling
-                                * subsequent processes into thinking
-                                * the daemon is still active).
-                                * 
-                                * Destroy the shared memory segment
-                                * and try once more.  This won't
-                                * break running apps, but no new apps
-                                * will be able to see the current
-                                * shared memory segment.
-                                */
-                               tried_once=TRUE;
-                               _wapi_shm_destroy ();
-                               
-                               goto attach_again;
-                       }
-               }
+       while(_wapi_fd_reserve > _wapi_private_handle_count) {
+               _wapi_private_handle_count += _WAPI_HANDLE_INITIAL_COUNT;
        }
+       
+       _wapi_private_handles = g_new0 (struct _WapiHandleUnshared,
+                                       _wapi_private_handle_count);
 
-       if(shared==FALSE) {
-#ifdef DEBUG
-               g_message (G_GNUC_PRETTY_FUNCTION
-                          ": Using process-private handles");
-#endif
-               _wapi_shared_data[0]=g_new0 (struct _WapiHandleShared_list, 1);
-               _wapi_shared_data[0]->num_segments=1;
-
-               _wapi_shared_scratch=g_new0 (struct _WapiHandleScratch, 1);
-       }
-       _wapi_private_data[0]=g_new0 (struct _WapiHandlePrivate_list, 1);
-       _wapi_shm_mapped_segments=1;
 
-       thr_ret = pthread_mutexattr_init (&mutex_shared_attr);
-       g_assert (thr_ret == 0);
+       _wapi_shared_layout = _wapi_shm_attach ();
+       g_assert (_wapi_shared_layout != NULL);
        
-       thr_ret = pthread_condattr_init (&cond_shared_attr);
-       g_assert (thr_ret == 0);
+       _wapi_fileshare_layout = _wapi_fileshare_shm_attach ();
+       g_assert (_wapi_fileshare_layout != NULL);
        
-#if defined(_POSIX_THREAD_PROCESS_SHARED) && _POSIX_THREAD_PROCESS_SHARED != -1
-       thr_ret = pthread_mutexattr_setpshared (&mutex_shared_attr,
-                                               PTHREAD_PROCESS_SHARED);
-       g_assert (thr_ret == 0);
+       _wapi_collection_init ();
        
-       thr_ret = pthread_condattr_setpshared (&cond_shared_attr,
-                                              PTHREAD_PROCESS_SHARED);
-       g_assert (thr_ret == 0);
-#else
-       thr_ret = pthread_cond_init(&_wapi_private_data[0]->signal_cond, NULL);
+       thr_ret = pthread_cond_init(&_wapi_global_signal_cond, NULL);
        g_assert (thr_ret == 0);
        
-       thr_ret = mono_mutex_init(&_wapi_private_data[0]->signal_mutex, NULL);
+       thr_ret = mono_mutex_init(&_wapi_global_signal_mutex, NULL);
        g_assert (thr_ret == 0);
-#endif
 }
 
-#ifdef HEAVY_DEBUG
-static void
-print_handle_count (gint mask)
+static void _wapi_handle_init_shared_metadata (struct _WapiHandleSharedMetadata *meta)
 {
-       gint *count, num_handles;
-       gint i;
-       static const gchar *names [] = {"WAPI_HANDLE_UNUSED",
-                                 "WAPI_HANDLE_FILE",
-                                 "WAPI_HANDLE_CONSOLE",
-                                 "WAPI_HANDLE_THREAD",
-                                 "WAPI_HANDLE_SEM",
-                                 "WAPI_HANDLE_MUTEX",
-                                 "WAPI_HANDLE_EVENT",
-                                 "WAPI_HANDLE_SOCKET",
-                                 "WAPI_HANDLE_FIND",
-                                 "WAPI_HANDLE_PROCESS",
-                                 "WAPI_HANDLE_PIPE"
-                               };
-
-
-       num_handles=_wapi_handle_get_shared_segment (0)->num_segments * _WAPI_HANDLES_PER_SEGMENT;
-       count=g_new0 (gint, num_handles);
-
-       for (i = 1; i < num_handles; i++) {
-               struct _WapiHandleShared *shared;
-               guint32 segment, idx;
-               
-               _wapi_handle_segment (GUINT_TO_POINTER (i), &segment, &idx);
-               _wapi_handle_ensure_mapped (segment);
-               
-               shared = &_wapi_handle_get_shared_segment (segment)->handles[idx];
-               count [shared->type]++;
+       meta->timestamp = (guint32)(time (NULL) & 0xFFFFFFFF);
+       meta->signalled = FALSE;
+}
+
+static void _wapi_handle_init_shared (struct _WapiHandleShared *handle,
+                                     WapiHandleType type,
+                                     gpointer handle_specific)
+{
+       handle->type = type;
+       handle->stale = FALSE;
+       
+       if (handle_specific != NULL) {
+               memcpy (&handle->u, handle_specific, sizeof (handle->u));
        }
+}
 
-       for (i = 0; i < num_handles; i++)
-               if ((i & mask) == i) /* Always prints the UNUSED count */
-                       g_print ("%s: %d\n", names [i], count [i]);
+static void _wapi_handle_init (struct _WapiHandleUnshared *handle,
+                              WapiHandleType type, gpointer handle_specific)
+{
+       int thr_ret;
+       
+       handle->type = type;
+       handle->signalled = FALSE;
+       handle->ref = 1;
+       
+       if (!_WAPI_SHARED_HANDLE(type)) {
+               thr_ret = pthread_cond_init (&handle->signal_cond, NULL);
+               g_assert (thr_ret == 0);
+                               
+               thr_ret = mono_mutex_init (&handle->signal_mutex, NULL);
+               g_assert (thr_ret == 0);
 
-       g_free (count);
+               if (handle_specific != NULL) {
+                       memcpy (&handle->u, handle_specific,
+                               sizeof (handle->u));
+               }
+       }
 }
-#endif /* HEAVY_DEBUG */
 
-/*
- * _wapi_handle_new_internal:
- * @type: Init handle to this type
- *
- * Search for a free handle and initialize it. Return the handle on
- * success and 0 on failure.
- */
-guint32 _wapi_handle_new_internal (WapiHandleType type)
+static guint32 _wapi_handle_new_shared_offset (guint32 offset)
 {
-       guint32 segment, idx;
-       guint32 i, j;
-       static guint32 last=1;
-       int thr_ret;
+       guint32 i;
+       static guint32 last = 1;
        
-       /* A linear scan should be fast enough.  Start from the last
-        * allocation, assuming that handles are allocated more often
-        * than they're freed. Leave 0 (NULL) as a guard
-        */
-#ifdef HEAVY_DEBUG
-       print_handle_count (0xFFF);
-#endif
 again:
-       _wapi_handle_segment (GUINT_TO_POINTER (last), &segment, &idx);
-       for(i=segment; i<_wapi_handle_get_shared_segment (0)->num_segments;
-           i++) {
-               if(i!=segment) {
-                       idx=0;
-               }
-               
-               for(j=idx; j<_WAPI_HANDLES_PER_SEGMENT; j++) {
-                       struct _WapiHandleShared *shared;
+       /* FIXME: expandable array */
+       /* 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 - _WAPI_HEADROOM; i++) {
+               struct _WapiHandleSharedMetadata *meta = &_wapi_shared_layout->metadata[i];
                
-                       /* Make sure we dont try and assign handle 0 */
-                       if (i==0 && j==0) {
-                               continue;
-                       }
+               if(meta->offset == 0) {
+                       if (InterlockedCompareExchange (&meta->offset, offset,
+                                                       0) == 0) {
+                               last = i + 1;
                        
-                       shared=&_wapi_handle_get_shared_segment (i)->handles[j];
-               
-                       if(shared->type==WAPI_HANDLE_UNUSED) {
-                               last=(_wapi_handle_index (i, j)+1) % (_wapi_handle_get_shared_segment (0)->num_segments * _WAPI_HANDLES_PER_SEGMENT);
-                               shared->type=type;
-                               shared->signalled=FALSE;
-#if defined(_POSIX_THREAD_PROCESS_SHARED) && _POSIX_THREAD_PROCESS_SHARED != -1
-                               thr_ret = mono_mutex_init (&shared->signal_mutex, &mutex_shared_attr);
-                               g_assert (thr_ret == 0);
-                               
-                               thr_ret = pthread_cond_init (&shared->signal_cond, &cond_shared_attr);
-                               g_assert (thr_ret == 0);
-#else
-                               thr_ret = pthread_cond_init(&shared->signal_cond, NULL);
-                               g_assert (thr_ret == 0);
-                               
-                               thr_ret = mono_mutex_init(&shared->signal_mutex, NULL);
-                               g_assert (thr_ret == 0);
-#endif
-                               
-                               return(_wapi_handle_index (i, j));
+                               _wapi_handle_init_shared_metadata (meta);
+                               return(i);
+                       } else {
+                               /* Someone else beat us to it, just
+                                * continue looking
+                                */
                        }
                }
        }
 
-       if(last>1) {
+       if(last > 1) {
                /* Try again from the beginning */
-               last=1;
+               last = 1;
                goto again;
        }
 
-       /* Will need a new segment.  The caller will sort it out */
+       /* Will need to expand the array.  The caller will sort it out */
 
        return(0);
 }
 
-gpointer _wapi_handle_new (WapiHandleType type)
+static guint32 _wapi_handle_new_shared (WapiHandleType type,
+                                       gpointer handle_specific)
 {
-       static mono_once_t shared_init_once = MONO_ONCE_INIT;
-       static pthread_mutex_t scan_mutex=PTHREAD_MUTEX_INITIALIZER;
-       guint32 handle_idx = 0, idx, segment;
-       gpointer handle;
-       WapiHandleRequest new={0};
-       WapiHandleResponse new_resp={0};
-#if HAVE_BOEHM_GC
-       gboolean tried_collect=FALSE;
-#endif
-       int thr_ret;
+       guint32 offset;
+       static guint32 last = 1;
        
-       mono_once (&shared_init_once, shared_init);
+       /* The shared memory holds an offset to the real data, so we
+        * can update the handle RCU-style without taking a lock.
+        * This function just allocates the next available data slot,
+        * use _wapi_handle_new_shared_offset to get the offset entry.
+        */
 
+       /* Leave the first slot empty as a guard */
 again:
-       if(shared==TRUE) {
-               new.type=WapiHandleRequestType_New;
-               new.u.new.type=type;
-       
-               _wapi_daemon_request_response (daemon_sock, &new, &new_resp);
-       
-               if (new_resp.type==WapiHandleResponseType_New) {
-                       handle_idx=new_resp.u.new.handle;
-               } else {
-                       g_warning (G_GNUC_PRETTY_FUNCTION
-                                  ": bogus daemon response, type %d",
-                                  new_resp.type);
-                       g_assert_not_reached ();
-               }
-       } else {
-               pthread_cleanup_push ((void(*)(void *))pthread_mutex_unlock,
-                                     (void *)&scan_mutex);
-               thr_ret = pthread_mutex_lock (&scan_mutex);
-               g_assert (thr_ret == 0);
+       /* FIXME: expandable array */
+       /* 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 - _WAPI_HEADROOM;
+           offset++) {
+               struct _WapiHandleShared *handle = &_wapi_shared_layout->handles[offset];
                
-               handle_idx=_wapi_handle_new_internal (type);
-               if(handle_idx==0) {
-                       /* Try and get a new segment, and have another go */
-                       segment=_wapi_handle_get_shared_segment (0)->num_segments;
-                       _wapi_handle_ensure_mapped (segment);
+               if(handle->type == WAPI_HANDLE_UNUSED) {
+                       if (InterlockedCompareExchange ((gint32 *)&handle->type, type, WAPI_HANDLE_UNUSED) == WAPI_HANDLE_UNUSED) {
+                               last = offset + 1;
                        
-                       if(_wapi_handle_get_shared_segment (segment)!=NULL) {
-                               /* Got a new segment */
-                               _wapi_handle_get_shared_segment (0)->num_segments++;
-                               handle_idx=_wapi_handle_new_internal (type);
+                               _wapi_handle_init_shared (handle, type,
+                                                         handle_specific);
+                               return(offset);
                        } else {
-                               /* Map failed.  Just return 0 meaning
-                                * "out of handles"
+                               /* Someone else beat us to it, just
+                                * continue looking
                                 */
                        }
                }
-               
-               _wapi_handle_segment (GUINT_TO_POINTER (handle_idx), &segment, &idx);
-               _wapi_handle_get_shared_segment (segment)->handles[idx].ref++;
-
-               thr_ret = pthread_mutex_unlock (&scan_mutex);
-               g_assert (thr_ret == 0);
-               pthread_cleanup_pop (0);
        }
-               
-       if(handle_idx==0) {
-               g_warning (G_GNUC_PRETTY_FUNCTION ": Ran out of handles!");
 
-#if HAVE_BOEHM_GC
-               /* See if we can reclaim some handles by forcing a GC
-                * collection
-                */
-               if(tried_collect==FALSE) {
-                       g_warning (G_GNUC_PRETTY_FUNCTION
-                                  ": Seeing if GC collection helps...");
-                       GC_gcollect (); /* FIXME: we should wait for finalizers to be called */
-                       tried_collect=TRUE;
-                       goto again;
-               } else {
-                       g_warning (G_GNUC_PRETTY_FUNCTION
-                                  ": didn't help, returning error");
-               }
-#endif
-       
-               return(GUINT_TO_POINTER (_WAPI_HANDLE_INVALID));
+       if(last > 1) {
+               /* Try again from the beginning */
+               last = 1;
+               goto again;
        }
 
-       _wapi_handle_segment (GUINT_TO_POINTER (handle_idx), &segment, &idx);
-       _wapi_handle_ensure_mapped (segment);
+       /* Will need to expand the array.  The caller will sort it out */
 
-       if(_wapi_private_data!=NULL) {
-               _wapi_handle_get_private_segment (segment)->handles[idx].type=type;
-       }
-       
-#if !defined(_POSIX_THREAD_PROCESS_SHARED) || _POSIX_THREAD_PROCESS_SHARED == -1
-       thr_ret = mono_mutex_init (&_wapi_handle_get_shared_segment (segment)->handles[idx].signal_mutex, &mutex_shared_attr);
-       g_assert (thr_ret == 0);
-       
-       thr_ret = pthread_cond_init (&_wapi_handle_get_shared_segment (segment)->handles[idx].signal_cond, &cond_shared_attr);
-       g_assert (thr_ret == 0);
-#endif
-       handle=GUINT_TO_POINTER (handle_idx);
-
-#ifdef DEBUG
-       g_message (G_GNUC_PRETTY_FUNCTION ": Allocated new handle %p", handle);
-#endif
-       
-       return(handle);
+       return(0);
 }
 
-gboolean _wapi_lookup_handle (gpointer handle, WapiHandleType type,
-                             gpointer *shared, gpointer *private)
+/*
+ * _wapi_handle_new_internal:
+ * @type: Init handle to this type
+ *
+ * Search for a free handle and initialize it. Return the handle on
+ * success and 0 on failure.  This is only called from
+ * _wapi_handle_new, and scan_mutex must be held.
+ */
+static guint32 _wapi_handle_new_internal (WapiHandleType type,
+                                         gpointer handle_specific)
 {
-       struct _WapiHandleShared *shared_handle_data;
-       struct _WapiHandlePrivate *private_handle_data = NULL;
-       guint32 idx;
-       guint32 segment;
-
-       _wapi_handle_segment (handle, &segment, &idx);
-       _wapi_handle_ensure_mapped (segment);
+       guint32 i;
+       static guint32 last = 0;
        
-       shared_handle_data=&_wapi_handle_get_shared_segment (segment)->handles[idx];
-
-       if(shared!=NULL) {
-               *shared=&shared_handle_data->u;
-       }
+       /* 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
+        * descriptors
+        */
        
-       if(private!=NULL) {
-               private_handle_data=&_wapi_handle_get_private_segment (segment)->handles[idx];
-
-               *private=&private_handle_data->u;
-       }
-
-       if(shared_handle_data->type!=type) {
-               /* If shared type is UNUSED, see if the private type
-                * matches what we are looking for - this can happen
-                * when the handle is being destroyed and the
-                * close_private function is looking up the private
-                * data
-                */
-               if(shared_handle_data->type==WAPI_HANDLE_UNUSED &&
-                  (private!=NULL && private_handle_data->type==type)) {
-                       return(TRUE);
-               } else {
-                       return(FALSE);
-               }
+       if (last < _wapi_fd_reserve) {
+               last = _wapi_fd_reserve;
        }
        
-       return(TRUE);
-}
-
-gpointer _wapi_search_handle (WapiHandleType type,
-                             gboolean (*check)(gpointer test, gpointer user),
-                             gpointer user_data,
-                             gpointer *shared, gpointer *private)
-{
-       struct _WapiHandleShared *shared_handle_data;
-       struct _WapiHandlePrivate *private_handle_data;
-       guint32 i, segment, idx;
-
-       for(i=1; i<_wapi_handle_get_shared_segment (0)->num_segments * _WAPI_HANDLES_PER_SEGMENT; i++) {
-               struct _WapiHandleShared *shared;
-               
-               _wapi_handle_segment (GUINT_TO_POINTER (i), &segment, &idx);
-               _wapi_handle_ensure_mapped (segment);
-               
-               shared=&_wapi_handle_get_shared_segment (segment)->handles[idx];
+again:
+       for(i = last; i <_wapi_private_handle_count; i++) {
+               struct _WapiHandleUnshared *handle = &_wapi_private_handles[i];
                
-               if(shared->type==type) {
-                       if(check (GUINT_TO_POINTER (i), user_data)==TRUE) {
-                               break;
-                       }
+               if(handle->type == WAPI_HANDLE_UNUSED) {
+                       last = i + 1;
+                       
+                       _wapi_handle_init (handle, type, handle_specific);
+                       return(i);
                }
        }
 
-       if(i==_wapi_handle_get_shared_segment (0)->num_segments * _WAPI_HANDLES_PER_SEGMENT) {
-               return(GUINT_TO_POINTER (0));
+       if(last > _wapi_fd_reserve) {
+               /* Try again from the beginning */
+               last = _wapi_fd_reserve;
+               goto again;
        }
-       
-       if(shared!=NULL) {
-               shared_handle_data=&_wapi_handle_get_shared_segment (segment)->handles[idx];
 
-               *shared=&shared_handle_data->u;
-       }
-       
-       if(private!=NULL) {
-               private_handle_data=&_wapi_handle_get_private_segment (segment)->handles[idx];
+       /* Will need to expand the array.  The caller will sort it out */
 
-               *private=&private_handle_data->u;
-       }
-       
-       return(GUINT_TO_POINTER (i));
+       return(0);
 }
 
-gpointer _wapi_search_handle_namespace (WapiHandleType type,
-                                       gchar *utf8_name, gpointer *shared,
-                                       gpointer *private)
+gpointer _wapi_handle_new (WapiHandleType type, gpointer handle_specific)
 {
-       struct _WapiHandleShared *shared_handle_data;
-       struct _WapiHandlePrivate *private_handle_data;
-       guint32 i, segment, idx;
-
+       static mono_mutex_t scan_mutex = MONO_MUTEX_INITIALIZER;
+       guint32 handle_idx = 0;
+       gpointer handle;
+       int thr_ret;
+       
+       mono_once (&shared_init_once, shared_init);
+       
 #ifdef DEBUG
-       g_message (G_GNUC_PRETTY_FUNCTION
-                  ": Lookup for handle named [%s] type %d", utf8_name, type);
+       g_message ("%s: Creating new handle of type %s", __func__,
+                  _wapi_handle_typename[type]);
 #endif
 
-       for(i=1; i<_wapi_handle_get_shared_segment (0)->num_segments * _WAPI_HANDLES_PER_SEGMENT; i++) {
-               struct _WapiHandleShared *shared;
+       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);
                
-               _wapi_handle_segment (GUINT_TO_POINTER (i), &segment, &idx);
-               _wapi_handle_ensure_mapped (segment);
+       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)));
                
-               shared=&_wapi_handle_get_shared_segment (segment)->handles[idx];
+               _wapi_private_handle_count += _WAPI_HANDLE_INITIAL_COUNT;
+       }
                
-               /* Check mutex, event, semaphore, timer, job and file-mapping
-                * object names.  So far only mutex is implemented.
-                */
-               if(_WAPI_SHARED_NAMESPACE (shared->type)) {
-                       gchar *lookup_name;
-                       WapiSharedNamespace *sharedns;
-                       
-#ifdef DEBUG
-                       g_message (G_GNUC_PRETTY_FUNCTION ": found a shared namespace handle at 0x%x (type %d)", i, shared->type);
-#endif
-
-                       shared_handle_data=&_wapi_handle_get_shared_segment (segment)->handles[idx];
-                       sharedns=(WapiSharedNamespace *)&shared_handle_data->u;
-                       
-                       
-                       if(sharedns->name) {
-                               lookup_name=_wapi_handle_scratch_lookup (
-                                       sharedns->name);
-                       } else {
-#ifdef DEBUG
-                               g_message (G_GNUC_PRETTY_FUNCTION
-                                          ": handle 0x%x is unnamed", i);
-#endif
-                               continue;
-                       }
-
-                       if(lookup_name==NULL) {
-#ifdef DEBUG
-                               g_message (G_GNUC_PRETTY_FUNCTION
-                                          ": couldn't find handle 0x%x name",
-                                          i);
-#endif
-                               continue;
-                       }
-
-#ifdef DEBUG
-                       g_message (G_GNUC_PRETTY_FUNCTION ": name is [%s]",
-                                  lookup_name);
-#endif
+       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);
+       
+       handle = GUINT_TO_POINTER (handle_idx);
 
-                       if(strcmp (lookup_name, utf8_name)==0) {
-                               if(shared->type!=type) {
-                                       /* Its the wrong type, so fail now */
 #ifdef DEBUG
-                                       g_message (G_GNUC_PRETTY_FUNCTION ": handle 0x%x matches name but is wrong type: %d", i, shared->type);
+       g_message ("%s: Allocated new handle %p", __func__, handle);
 #endif
-                                       return(_WAPI_HANDLE_INVALID);
-                               } else {
-                                       /* fall through so we can fill
-                                        * in the data
-                                        */
+       
+       if (_WAPI_SHARED_HANDLE(type)) {
+               /* Add the shared section too */
+               guint32 offset, ref;
+               
+               offset = _wapi_handle_new_shared (type, handle_specific);
+               if (offset == 0) {
+                       _wapi_handle_collect ();
+                       offset = _wapi_handle_new_shared (type,
+                                                         handle_specific);
+                       /* FIXME: grow the arrays */
+                       g_assert (offset != 0);
+               }
+               
+               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);
+               }
+               
+               _wapi_private_handles[handle_idx].u.shared.offset = ref;
 #ifdef DEBUG
-                                       g_message (G_GNUC_PRETTY_FUNCTION ": handle 0x%x matches name and type", i);
+               g_message ("%s: New shared handle at offset 0x%x", __func__,
+                          ref);
 #endif
-                                       break;
-                               }
-                       }
-               }
-       }
-
-       if(i==_wapi_handle_get_shared_segment (0)->num_segments * _WAPI_HANDLES_PER_SEGMENT) {
-               return(GUINT_TO_POINTER (0));
-       }
-       
-       if(shared!=NULL) {
-               shared_handle_data=&_wapi_handle_get_shared_segment (segment)->handles[idx];
-
-               *shared=&shared_handle_data->u;
-       }
-       
-       if(private!=NULL) {
-               private_handle_data=&_wapi_handle_get_private_segment (segment)->handles[idx];
-
-               *private=&private_handle_data->u;
        }
        
-       return(GUINT_TO_POINTER (i));
+       return(handle);
 }
 
-void _wapi_handle_ref (gpointer handle)
+gpointer _wapi_handle_new_for_existing_ns (WapiHandleType type,
+                                          gpointer handle_specific,
+                                          guint32 offset)
 {
-       if(shared==TRUE) {
-               WapiHandleRequest req={0};
-               WapiHandleResponse resp={0};
-       
-               req.type=WapiHandleRequestType_Open;
-               req.u.open.handle=GPOINTER_TO_UINT (handle);
-       
-               _wapi_daemon_request_response (daemon_sock, &req, &resp);
-               if(resp.type!=WapiHandleResponseType_Open) {
-                       g_warning (G_GNUC_PRETTY_FUNCTION
-                                  ": bogus daemon response, type %d",
-                                  resp.type);
-                       g_assert_not_reached ();
-               }
-       } else {
-               guint32 idx, segment;
+       static mono_mutex_t scan_mutex = MONO_MUTEX_INITIALIZER;
+       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__,
+                  _wapi_handle_typename[type]);
+#endif
 
-               _wapi_handle_segment (handle, &segment, &idx);
+       g_assert(!_WAPI_FD_HANDLE(type));
+       g_assert(_WAPI_SHARED_HANDLE(type));
+       g_assert(offset != 0);
+       
+       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);
                
-               _wapi_handle_get_shared_segment (segment)->handles[idx].ref++;
+       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)));
+               
+               _wapi_private_handle_count += _WAPI_HANDLE_INITIAL_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);
        
+       handle = GUINT_TO_POINTER (handle_idx);
+               
+       _wapi_private_handles[handle_idx].u.shared.offset = offset;
+
 #ifdef DEBUG
-               g_message (G_GNUC_PRETTY_FUNCTION ": handle %p ref now %d",
-                          handle,
-                          _wapi_handle_get_shared_segment (segment)->handles[idx].ref);
+       g_message ("%s: Allocated new handle %p referencing 0x%x", __func__,
+                  handle, offset);
 #endif
-       }
+
+       return(handle);
 }
 
-/* The handle must not be locked on entry to this function */
-void _wapi_handle_unref (gpointer handle)
+gpointer _wapi_handle_new_fd (WapiHandleType type, int fd,
+                             gpointer handle_specific)
 {
-       guint32 idx, segment;
-       gboolean destroy = FALSE;
-       int thr_ret;
+       struct _WapiHandleUnshared *handle;
        
-       _wapi_handle_segment (handle, &segment, &idx);
-       
-       if(shared==TRUE) {
-               WapiHandleRequest req={0};
-               WapiHandleResponse resp={0};
+       mono_once (&shared_init_once, shared_init);
        
-               req.type=WapiHandleRequestType_Close;
-               req.u.close.handle=GPOINTER_TO_UINT (handle);
+#ifdef DEBUG
+       g_message ("%s: Creating new handle of type %s", __func__,
+                  _wapi_handle_typename[type]);
+#endif
        
-               _wapi_daemon_request_response (daemon_sock, &req, &resp);
-               if(resp.type!=WapiHandleResponseType_Close) {
-                       g_warning (G_GNUC_PRETTY_FUNCTION
-                                  ": bogus daemon response, type %d",
-                                  resp.type);
-                       g_assert_not_reached ();
-               } else {
-                       destroy=resp.u.close.destroy;
-               }
-       } else {
-               _wapi_handle_get_shared_segment (segment)->handles[idx].ref--;
+       g_assert(_WAPI_FD_HANDLE(type));
+       g_assert(!_WAPI_SHARED_HANDLE(type));
        
+       if (fd >= _wapi_fd_reserve) {
 #ifdef DEBUG
-               g_message (G_GNUC_PRETTY_FUNCTION ": handle %p ref now %d", handle, _wapi_handle_get_shared_segment (segment)->handles[idx].ref);
+               g_message ("%s: fd %d is too big", __func__, fd);
 #endif
 
-               /* Possible race condition here if another thread refs
-                * the handle between here and setting the type to
-                * UNUSED.  I could lock a mutex, but I'm not sure
-                * that allowing a handle reference to reach 0 isn't
-                * an application bug anyway.
+               return(GUINT_TO_POINTER (_WAPI_HANDLE_INVALID));
+       }
+
+       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
+               /* FIXME: clean up this handle?  We can't do anything
+                * with the fd, cos thats the new one
                 */
-               destroy=(_wapi_handle_get_shared_segment (segment)->handles[idx].ref==0);
        }
 
-       if(destroy==TRUE) {
 #ifdef DEBUG
-               g_message (G_GNUC_PRETTY_FUNCTION ": Destroying handle %p",
-                          handle);
+       g_message ("%s: Assigning new fd handle %d", __func__, fd);
 #endif
-               
-               if(shared==FALSE) {
-                       _wapi_handle_ops_close_shared (handle);
 
-                       memset (&_wapi_handle_get_shared_segment (segment)->handles[idx].u, '\0', sizeof(_wapi_handle_get_shared_segment (segment)->handles[idx].u));
-               }
+       _wapi_handle_init (handle, type, handle_specific);
 
-               _wapi_handle_ops_close_private (handle);
-               _wapi_handle_get_shared_segment (segment)->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_handle_get_shared_segment (segment)->handles[idx].signal_mutex);
-               g_assert (thr_ret == 0);
-                       
-               thr_ret = pthread_cond_destroy (&_wapi_handle_get_shared_segment (segment)->handles[idx].signal_cond);
-               g_assert (thr_ret == 0);
-       }
+       return(GUINT_TO_POINTER(fd));
 }
 
-#define HDRSIZE sizeof(struct _WapiScratchHeader)
+gboolean _wapi_lookup_handle (gpointer handle, WapiHandleType type,
+                             gpointer *handle_specific)
+{
+       struct _WapiHandleUnshared *handle_data;
+       guint32 handle_idx = GPOINTER_TO_UINT(handle);
 
-static pthread_mutex_t _wapi_scratch_mutex=PTHREAD_MUTEX_INITIALIZER;
+       handle_data = &_wapi_private_handles[handle_idx];
+       
+       if (handle_data->type != type) {
+               return(FALSE);
+       }
 
-/* _wapi_scratch_mutex must be held when this function is called in
- * the non-shared case
- */
-static void _wapi_handle_scratch_expand (void)
-{
-       guint32 old_len, new_len;
+       if (handle_specific == NULL) {
+               return(FALSE);
+       }
+       
+       if (_WAPI_SHARED_HANDLE(type)) {
+               struct _WapiHandle_shared_ref *ref;
+               struct _WapiHandleShared *shared_handle_data;
+               struct _WapiHandleSharedMetadata *shared_meta;
+               guint32 offset;
                
-       old_len=sizeof(struct _WapiHandleScratch) +
-               _wapi_shared_scratch->data_len;
-       new_len=old_len+_WAPI_SHM_SCRATCH_SIZE;
+               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];
                
-       if(_wapi_shared_scratch->is_shared==TRUE) {
-               /* expand via mmap() */
-               _wapi_shared_scratch=_wapi_shm_file_expand (_wapi_shared_scratch, WAPI_SHM_SCRATCH, 0, old_len, new_len);
+                       g_assert(shared_handle_data->type == type);
+
+                       *handle_specific = &shared_handle_data->u;
+               } while (offset != shared_meta->offset);
        } else {
-               _wapi_shared_scratch=_wapi_g_renew0 (_wapi_shared_scratch, old_len, new_len);
+               *handle_specific = &handle_data->u;
        }
-       _wapi_shared_scratch->data_len+=_WAPI_SHM_SCRATCH_SIZE;
+       
+       return(TRUE);
 }
 
-/* _wapi_scratch_mutex must be held when this function is called in
- * the non-shared case
- */
-static guint32 _wapi_handle_scratch_locate_space (guint32 bytes)
+gboolean _wapi_copy_handle (gpointer handle, WapiHandleType type,
+                           struct _WapiHandleShared *handle_specific)
 {
-       guint32 idx=0, last_idx=0;
-       struct _WapiScratchHeader *hdr, *last_hdr = NULL;
-       gboolean last_was_free=FALSE;
-       guchar *storage=_wapi_shared_scratch->scratch_data;
-       
-#ifdef DEBUG
-       g_message (G_GNUC_PRETTY_FUNCTION
-                  ": looking for %d bytes of scratch space (%d bytes total)",
-                  bytes, _wapi_shared_scratch->data_len);
-#endif
+       struct _WapiHandleUnshared *handle_data;
+       guint32 handle_idx = GPOINTER_TO_UINT(handle);
+       struct _WapiHandle_shared_ref *ref;
+       struct _WapiHandleShared *shared_handle_data;
+       struct _WapiHandleSharedMetadata *shared_meta;
+       guint32 offset;
        
-       while(idx< _wapi_shared_scratch->data_len) {
-               hdr=(struct _WapiScratchHeader *)&storage[idx];
-               
-               /* Do a simple first-fit allocation, coalescing
-                * adjacent free blocks as we progress through the
-                * scratch space
-                */
-               if(hdr->flags & WAPI_SHM_SCRATCH_FREE &&
-                  hdr->length >= bytes + HDRSIZE) {
-                       /* found space */
-                       guint32 old_length=hdr->length;
-#ifdef DEBUG
-                       g_message (G_GNUC_PRETTY_FUNCTION ": found suitable free size at %d, length %d", idx, hdr->length);
-#endif
-
-                       hdr->flags &= ~WAPI_SHM_SCRATCH_FREE;
-                       hdr->length=bytes;
-                       idx += HDRSIZE;
-
-                       /* Put a new header in at the end of the used
-                        * space
-                        */
-                       hdr=(struct _WapiScratchHeader *)&storage[idx+bytes];
-                       hdr->flags |= WAPI_SHM_SCRATCH_FREE;
-                       hdr->length = old_length-bytes-HDRSIZE;
+       g_assert(_WAPI_SHARED_HANDLE(type));
 
 #ifdef DEBUG
-                       g_message (G_GNUC_PRETTY_FUNCTION ": new header at %d, length %d", idx+bytes, hdr->length);
+       g_message ("%s: copying handle %p type %s", __func__, handle,
+                  _wapi_handle_typename[type]);
 #endif
-                       
-                       /*
-                        * It was memset(0..) when free/made so no need to do it here
-                        */
 
-                       return(idx);
-               } else if(hdr->flags & WAPI_SHM_SCRATCH_FREE &&
-                         last_was_free == FALSE) {
-#ifdef DEBUG
-                       g_message (G_GNUC_PRETTY_FUNCTION ": found too-small free block at %d, length %d (previous used)", idx, hdr->length);
-#endif
-
-                       /* save this point in case we can coalesce it with
-                        * the next block, if that is free.
-                        */
-                       last_was_free=TRUE;
-                       last_idx=idx;
-                       last_hdr=hdr;
-                       idx+=(hdr->length+HDRSIZE);
-               } else if (hdr->flags & WAPI_SHM_SCRATCH_FREE &&
-                          last_was_free == TRUE) {
+       handle_data = &_wapi_private_handles[handle_idx];
+       
+       if(handle_data->type != type) {
 #ifdef DEBUG
-                       g_message (G_GNUC_PRETTY_FUNCTION ": found too-small free block at %d, length %d (previous free)", idx, hdr->length);
+               g_message ("%s: incorrect type, %p has type %s", __func__,
+                          handle, _wapi_handle_typename[handle_data->type]);
 #endif
 
-                       /* This block and the previous are both free,
-                        * so coalesce them
-                        */
-                       last_hdr->length += (hdr->length + HDRSIZE);
+               return(FALSE);
+       }
 
-                       /* If the new block is now big enough, use it
-                        * (next time round the loop)
-                        */
-                       if(last_hdr->length >= bytes + HDRSIZE) {
-                               idx=last_idx;
-                       } else {
-                               /* leave the last free info as it is,
-                                * in case the next block is also free
-                                * and can be coalesced too
-                                */
-                               idx=last_idx+last_hdr->length+HDRSIZE;
-                       }
-               } else {
+       if(handle_specific == NULL) {
 #ifdef DEBUG
-                       g_message (G_GNUC_PRETTY_FUNCTION
-                                  ": found used block at %d, length %d", idx,
-                                  hdr->length);
+               g_message ("%s: Nowhere to store data", __func__);
 #endif
 
-                       /* must be used, try next chunk */
-                       idx+=(hdr->length+HDRSIZE);
-
-                       /* Don't let the coalescing blow away this block */
-                       last_was_free=FALSE;
-
-                       /* But remember where the last block started */
-                       last_idx=idx;
-               }
+               return(FALSE);
        }
-
-       /* Not enough free space.  last_idx points to the last block.
-        * If it's free, just tack on more space and update the
-        * length.  If it's allocated, it must have fit right into the
-        * available space, so add more space and add a new header
-        * after this block.
-        */
-       _wapi_handle_scratch_expand ();
-       storage=_wapi_shared_scratch->scratch_data;
        
-       hdr=(struct _WapiScratchHeader *)&storage[last_idx];
-       if(hdr->flags & WAPI_SHM_SCRATCH_FREE) {
-               hdr->length+=_WAPI_SHM_SCRATCH_SIZE;
-       } else {
-               idx=(hdr->length+HDRSIZE);
-               hdr=(struct _WapiScratchHeader *)&storage[idx];
-               hdr->flags |= WAPI_SHM_SCRATCH_FREE;
-               hdr->length = _WAPI_SHM_SCRATCH_SIZE-HDRSIZE;
-       }
+       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);
+               
+               memcpy(handle_specific, shared_handle_data,
+                      sizeof(struct _WapiHandleShared));
+       } while (offset != shared_meta->offset);
+       
+#ifdef DEBUG
+       g_message ("%s: OK", __func__);
+#endif
 
-       /* The caller will try again */
-       return(0);
+       return(TRUE);
 }
 
-/*
- * _wapi_handle_scratch_store_internal:
- * @bytes: Allocate no. bytes
- *
- * Like malloc(3) except its for the shared memory segment's scratch
- * part. Memory block returned is zeroed out.
- */
-guint32 _wapi_handle_scratch_store_internal (guint32 bytes, gboolean *remap)
+void _wapi_replace_handle (gpointer handle, WapiHandleType type,
+                          struct _WapiHandleShared *handle_specific)
 {
-       guchar *storage;
-       guint32 idx;
-       struct _WapiScratchHeader *hdr;
-
-#ifdef DEBUG
-       g_message (G_GNUC_PRETTY_FUNCTION ": storing %d bytes", bytes);
-#endif
-       
-       *remap=FALSE;
+       struct _WapiHandleShared *shared_handle_data;
+       struct _WapiHandleSharedMetadata *shared_meta;
+       guint32 handle_idx = GPOINTER_TO_UINT(handle);
+       guint32 old_off, new_off, ref;
        
-       if(_wapi_shared_scratch->data_len==0) {
-               /* Need to expand the data array for the first use */
 #ifdef DEBUG
-               g_message (G_GNUC_PRETTY_FUNCTION
-                          ": setting up scratch space");
+       g_message ("%s: Replacing handle %p of type %s", __func__, handle,
+                  _wapi_handle_typename[type]);
 #endif
 
-               _wapi_handle_scratch_expand ();
-               *remap=TRUE;
-       }
+       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];
+       
+       do {
+               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];
 
-       storage=_wapi_shared_scratch->scratch_data;
-       hdr=(struct _WapiScratchHeader *)&storage[0];
-       if(hdr->flags==0 && hdr->length==0) {
-               /* Need to initialise scratch data */
-               hdr->flags |= WAPI_SHM_SCRATCH_FREE;
-               hdr->length = _wapi_shared_scratch->data_len - HDRSIZE;
-       }
+               memcpy (shared_handle_data, handle_specific,
+                       sizeof(struct _WapiHandleShared));
+
+               /* 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;
+       } while(InterlockedCompareExchange (&shared_meta->offset, new_off,
+                                           old_off) != old_off);
 
-       idx=_wapi_handle_scratch_locate_space (bytes);
-       if(idx==0) {
-               /* Some more space will have been allocated, so try again */
 #ifdef DEBUG
-               g_message (G_GNUC_PRETTY_FUNCTION ": trying again");
+       g_message ("%s: handle at 0x%x is now found at 0x%x", __func__, ref,
+                  new_off);
 #endif
-
-               idx=_wapi_handle_scratch_locate_space (bytes);
-               *remap=TRUE;
-       }
-       
-       return(idx);
 }
 
-guint32 _wapi_handle_scratch_store (gconstpointer data, guint32 bytes)
+gboolean _wapi_try_replace_handle (gpointer handle, WapiHandleType type,
+                                  struct _WapiHandleShared *handle_specific)
 {
-       guint32 idx = 0, store_bytes;
-       gboolean remap;
-       int thr_ret;
-       guint32 ret = 0;
+       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 (G_GNUC_PRETTY_FUNCTION ": storing %d bytes", bytes);
+       g_message ("%s: Trying to replace handle %p of type %s", __func__,
+                  handle, _wapi_handle_typename[type]);
 #endif
 
-       /* No point storing no data */
-       if(bytes==0) {
-               return(0);
-       }
-
-       /* Align bytes to 32 bits (needed for sparc at least) */
-       store_bytes = (((bytes) + 3) & (~3));
-
-       pthread_cleanup_push ((void(*)(void *))pthread_mutex_unlock,
-                             (void *)&_wapi_scratch_mutex);
-       thr_ret = pthread_mutex_lock (&_wapi_scratch_mutex);
-       g_assert (thr_ret == 0);
-       
-       if(shared==TRUE) {
-               WapiHandleRequest scratch={0};
-               WapiHandleResponse scratch_resp={0};
-               guint32 old_len=sizeof(struct _WapiHandleScratch) +
-                       _wapi_shared_scratch->data_len;
-               
-               scratch.type=WapiHandleRequestType_Scratch;
-               scratch.u.scratch.length=store_bytes;
+       g_assert(_WAPI_SHARED_HANDLE(type));
+       g_assert(_wapi_private_handles[handle_idx].type == type);
        
-               _wapi_daemon_request_response (daemon_sock, &scratch,
-                                              &scratch_resp);
+       ref = _wapi_private_handles[handle_idx].u.shared.offset;
+       shared_meta = &_wapi_shared_layout->metadata[ref];
        
-               if(scratch_resp.type==WapiHandleResponseType_Scratch) {
-                       idx=scratch_resp.u.scratch.idx;
-                       remap=scratch_resp.u.scratch.remap;
-               } else {
-                       g_warning (G_GNUC_PRETTY_FUNCTION
-                                  ": bogus daemon response, type %d",
-                                  scratch_resp.type);
-                       g_assert_not_reached ();
-               }
+       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);
        
-               if(remap==TRUE) {
-                       munmap (_wapi_shared_scratch, old_len);
-                       _wapi_shared_scratch=_wapi_shm_file_map (WAPI_SHM_SCRATCH, 0, NULL, NULL);
-               }
-       } else {
-               idx=_wapi_handle_scratch_store_internal (store_bytes, &remap);
-               if(idx==0) {
-                       /* Failed to allocate space */
-                       goto cleanup;
-               }
+               /* FIXME: grow the arrays */
+               g_assert (new_off != 0);
        }
-       ret = idx;
        
+       shared_handle_data = &_wapi_shared_layout->handles[new_off];
+
 #ifdef DEBUG
-       g_message (G_GNUC_PRETTY_FUNCTION
-                  ": stored [%s] at %d (len %d, aligned len %d)",
-                  (char *)data, idx, bytes, store_bytes);
+       g_message ("%s: Old offset: 0x%x, trying to move to 0x%x", __func__,
+                  old_off, new_off);
 #endif
-       
-       memcpy (&_wapi_shared_scratch->scratch_data[idx], data, bytes);
 
-cleanup:
-       thr_ret = pthread_mutex_unlock (&_wapi_scratch_mutex);
-       g_assert (thr_ret == 0);
-       pthread_cleanup_pop (0);
+       memcpy (shared_handle_data, handle_specific,
+               sizeof(struct _WapiHandleShared));
        
+       ret = (InterlockedCompareExchange (&shared_meta->offset, new_off,
+                                          old_off) == old_off);
+
+       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;
+       }
+
+#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);
+       }
+#endif
+
        return(ret);
 }
 
-guint32 _wapi_handle_scratch_store_string_array (gchar **data)
+/* 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
+ */
+gpointer _wapi_search_handle (WapiHandleType type,
+                             gboolean (*check)(gpointer test, gpointer user),
+                             gpointer user_data,
+                             gpointer *handle_specific)
 {
-       guint32 *stored_strings, count=0, i, idx;
-       gchar **strings;
-       
-       /* No point storing no data */
-       if(data==NULL) {
-               return(0);
+       struct _WapiHandleUnshared *handle_data = NULL;
+       gpointer ret = NULL;
+       guint32 i;
+
+       /* Unsafe, because we don't want the handle to vanish while
+        * we're checking it
+        */
+       _WAPI_HANDLE_COLLECTION_UNSAFE;
+
+       for(i = 0; i < _wapi_private_handle_count; i++) {
+               handle_data = &_wapi_private_handles[i];
+               
+               if(handle_data->type == type) {
+                       ret = GUINT_TO_POINTER (i);
+                       if(check (ret, user_data) == TRUE) {
+                               break;
+                       }
+               }
        }
 
-       strings=data;
-       while(*strings!=NULL) {
-               count++;
-               strings++;
+       if(i == _wapi_private_handle_count) {
+               goto done;
        }
        
-#ifdef DEBUG
-       g_message (G_GNUC_PRETTY_FUNCTION ": %d strings to store", count);
-#endif
-       
-       if(count==0) {
-               return(0);
-       }
+       if(handle_specific != NULL) {
+               if (_WAPI_SHARED_HANDLE(type)) {
+                       struct _WapiHandle_shared_ref *ref ;
+                       struct _WapiHandleShared *shared_handle_data;
+                       struct _WapiHandleSharedMetadata *shared_meta;
+                       guint32 offset, now;
+                       
+                       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);
+                       
+                               *handle_specific = &shared_handle_data->u;
+                       } while (offset != shared_meta->offset);
 
-       /* stored_strings[0] is the count */
-       stored_strings=g_new0 (guint32, count+1);
-       stored_strings[0]=count;
-       
-       strings=data;
-       for(i=0; i<count; i++) {
-               stored_strings[i+1]=_wapi_handle_scratch_store (strings[i], strlen (strings[i]));
+                       /* Make sure this handle doesn't vanish in the
+                        * next collection
+                        */
+                       now = (guint32)(time (NULL) & 0xFFFFFFFF);
+                       InterlockedExchange (&shared_meta->timestamp, now);
+               } else {
+                       *handle_specific = &handle_data->u;
+               }
        }
 
-       idx=_wapi_handle_scratch_store (stored_strings,
-                                       sizeof(guint32)*(count+1));
+done:
+       _WAPI_HANDLE_COLLECTION_SAFE;
        
-       return(idx);
+       return(ret);
 }
 
-gpointer _wapi_handle_scratch_lookup (guint32 idx)
+/* This signature makes it easier to use in pthread cleanup handlers */
+int _wapi_namespace_timestamp_release (gpointer nowptr)
 {
-       struct _WapiScratchHeader *hdr;
-       gpointer ret;
-       guchar *storage;
-       int thr_ret;
+       guint32 now = GPOINTER_TO_UINT(nowptr);
        
-       if(idx < HDRSIZE || idx > _wapi_shared_scratch->data_len) {
-               return(NULL);
-       }
+       return (_wapi_timestamp_release (&_wapi_shared_layout->namespace_check,
+                                        now));
+}
 
-       pthread_cleanup_push ((void(*)(void *))pthread_mutex_unlock,
-                             (void *)&_wapi_scratch_mutex);
-       thr_ret = pthread_mutex_lock (&_wapi_scratch_mutex);
-       g_assert (thr_ret == 0);
+int _wapi_namespace_timestamp (guint32 now)
+{
+       int ret;
        
-       storage=_wapi_shared_scratch->scratch_data;
+       do {
+               ret = _wapi_timestamp_exclusion (&_wapi_shared_layout->namespace_check, now);
+               /* sleep for a bit */
+               if (ret == EBUSY) {
+                       _wapi_handle_spin (100);
+               }
+       } while (ret == EBUSY);
        
-       hdr=(struct _WapiScratchHeader *)&storage[idx - HDRSIZE];
-       ret=g_malloc0 (hdr->length+1);
-       memcpy (ret, &storage[idx], hdr->length);
-
-       thr_ret = pthread_mutex_unlock (&_wapi_scratch_mutex);
-       g_assert (thr_ret == 0);
-       pthread_cleanup_pop (0);
-
        return(ret);
 }
 
-gchar **_wapi_handle_scratch_lookup_string_array (guint32 idx)
+/* Returns the offset of the metadata array, or -1 on error, or 0 for
+ * not found (0 is not a valid offset)
+ */
+gint32 _wapi_search_handle_namespace (WapiHandleType type,
+                                     gchar *utf8_name)
 {
-       gchar **strings;
-       guint32 *stored_strings;
-       guint32 count, i;
+       struct _WapiHandleShared *shared_handle_data;
+       struct _WapiHandleSharedMetadata *shared_meta;
+       guint32 i;
+       gint32 ret = 0;
        
-       if(idx < HDRSIZE || idx > _wapi_shared_scratch->data_len) {
-               return(NULL);
-       }
-
-       stored_strings=_wapi_handle_scratch_lookup (idx);
-       if(stored_strings==NULL) {
-               return(NULL);
-       }
-       
-       /* stored_strings[0] is the number of strings, the index of
-        * each string follows
-        */
-       count=stored_strings[0];
+       g_assert(_WAPI_SHARED_HANDLE(type));
+       g_assert(_wapi_shared_layout->namespace_check != 0);
        
 #ifdef DEBUG
-       g_message (G_GNUC_PRETTY_FUNCTION
-                  ": looking up an array of %d strings", count);
+       g_message ("%s: Lookup for handle named [%s] type %s", __func__,
+                  utf8_name, _wapi_handle_typename[type]);
 #endif
+
+       _WAPI_HANDLE_COLLECTION_UNSAFE;
        
-       /* NULL-terminate the array */
-       strings=g_new0 (gchar *, count+1);
-       
-       for(i=0; i<count; i++) {
-               strings[i]=_wapi_handle_scratch_lookup (stored_strings[i+1]);
+       for(i = 1; i < _WAPI_HANDLE_INITIAL_COUNT; i++) {
+               WapiSharedNamespace *sharedns;
+               
+               shared_meta = &_wapi_shared_layout->metadata[i];
+               shared_handle_data = &_wapi_shared_layout->handles[shared_meta->offset];
+
+               /* Check mutex, event, semaphore, timer, job and file-mapping
+                * object names.  So far only mutex is implemented.
+                */
+               if (!_WAPI_SHARED_NAMESPACE (shared_handle_data->type)) {
+                       continue;
+               }
 
 #ifdef DEBUG
-               g_message (G_GNUC_PRETTY_FUNCTION ": string %d is [%s]", i,
-                          strings[i]);
+               g_message ("%s: found a shared namespace handle at 0x%x (type %s)", __func__, i, _wapi_handle_typename[shared_handle_data->type]);
 #endif
-       }
 
-       g_free (stored_strings);
-       
-       return(strings);
-}
+               sharedns=(WapiSharedNamespace *)&shared_handle_data->u;
+                       
+#ifdef DEBUG
+               g_message ("%s: name is [%s]", __func__, sharedns->name);
+#endif
 
-/*
- * _wapi_handle_scratch_delete_internal:
- * @idx: Index to free block
- *
- * Like free(3) except its for the shared memory segment's scratch
- * part.
- */
-void _wapi_handle_scratch_delete_internal (guint32 idx)
-{
-       struct _WapiScratchHeader *hdr;
-       guchar *storage;
-       int thr_ret;
-       
-       if(idx < HDRSIZE || idx > _wapi_shared_scratch->data_len) {
-               return;
+               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
+                               ret = -1;
+                               goto done;
+                       } else {
+#ifdef DEBUG
+                               g_message ("%s: handle 0x%x matches name and type", __func__, i);
+#endif
+                               ret = i;
+                               goto done;
+                       }
+               }
        }
 
-       pthread_cleanup_push ((void(*)(void *))pthread_mutex_unlock,
-                             (void *)&_wapi_scratch_mutex);
-       thr_ret = pthread_mutex_lock (&_wapi_scratch_mutex);
-       g_assert (thr_ret == 0);
+done:
+       _WAPI_HANDLE_COLLECTION_SAFE;
        
-       storage=_wapi_shared_scratch->scratch_data;
-       
-       hdr=(struct _WapiScratchHeader *)&storage[idx - HDRSIZE];
-       memset (&storage[idx], '\0', hdr->length);
-       hdr->flags |= WAPI_SHM_SCRATCH_FREE;
-       
-       /* We could coalesce forwards here if the next block is also
-        * free, but the _store() function will do that anyway.
-        */
-
-       thr_ret = pthread_mutex_unlock (&_wapi_scratch_mutex);
-       g_assert (thr_ret == 0);
-       pthread_cleanup_pop (0);
+       return(ret);
 }
 
-void _wapi_handle_scratch_delete (guint32 idx)
+void _wapi_handle_ref (gpointer handle)
 {
-       if(shared==TRUE) {
-               WapiHandleRequest scratch_free={0};
-               WapiHandleResponse scratch_free_resp={0};
-       
-               scratch_free.type=WapiHandleRequestType_ScratchFree;
-               scratch_free.u.scratch_free.idx=idx;
+       guint32 idx = GPOINTER_TO_UINT(handle);
        
-               _wapi_daemon_request_response (daemon_sock, &scratch_free,
-                                              &scratch_free_resp);
+       InterlockedIncrement (&_wapi_private_handles[idx].ref);
        
-               if(scratch_free_resp.type!=WapiHandleResponseType_ScratchFree) {
-                       g_warning (G_GNUC_PRETTY_FUNCTION
-                                  ": bogus daemon response, type %d",
-                                  scratch_free_resp.type);
-                       g_assert_not_reached ();
-               }
-       } else {
-               _wapi_handle_scratch_delete_internal (idx);
-       }
+#ifdef DEBUG_REFS
+       g_message ("%s: handle %p ref now %d", __func__, handle,
+                  _wapi_private_handles[idx].ref);
+#endif
 }
 
-void _wapi_handle_scratch_delete_string_array (guint32 idx)
+/* The handle must not be locked on entry to this function */
+void _wapi_handle_unref (gpointer handle)
 {
-       guint32 *stored_strings;
-       guint32 count, i;
-       
-       stored_strings=_wapi_handle_scratch_lookup (idx);
-       if(stored_strings==NULL) {
-               return;
-       }
-       
-       /* stored_strings[0] is the number of strings, the index of
-        * each string follows
+       guint32 idx = GPOINTER_TO_UINT(handle);
+       gboolean destroy = FALSE;
+       int thr_ret;
+
+       /* Possible race condition here if another thread refs the
+        * handle between here and setting the type to UNUSED.  I
+        * could lock a mutex, but I'm not sure that allowing a handle
+        * reference to reach 0 isn't an application bug anyway.
         */
-       count=stored_strings[0];
+       destroy = (InterlockedDecrement (&_wapi_private_handles[idx].ref) ==0);
        
-#ifdef DEBUG
-       g_message (G_GNUC_PRETTY_FUNCTION ": deleting an array of %d strings",
-                  count);
+#ifdef DEBUG_REFS
+       g_message ("%s: handle %p ref now %d (destroy %s)", __func__, handle,
+                  _wapi_private_handles[idx].ref, destroy?"TRUE":"FALSE");
 #endif
        
-       for(i=1; i<count; i++) {
-               _wapi_handle_scratch_delete (stored_strings[i]);
-       }
-       
-       _wapi_handle_scratch_delete (idx);
+       if(destroy==TRUE) {
+#ifdef DEBUG
+               g_message ("%s: Destroying handle %p", __func__, handle);
+#endif
+               
+               _wapi_handle_ops_close (handle);
+
+               memset (&_wapi_private_handles[idx].u, '\0',
+                       sizeof(_wapi_private_handles[idx].u));
+
+               _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);
 
-       g_free (stored_strings);
+               /* The garbage collector will take care of shared data
+                * if this is a shared handle
+                */
+       }
 }
 
 void _wapi_handle_register_capabilities (WapiHandleType type,
                                         WapiHandleCapability caps)
 {
-       handle_caps[type]=caps;
+       handle_caps[type] = caps;
 }
 
 gboolean _wapi_handle_test_capabilities (gpointer handle,
                                         WapiHandleCapability caps)
 {
-       guint32 idx, segment;
+       guint32 idx = GPOINTER_TO_UINT(handle);
        WapiHandleType type;
 
-       _wapi_handle_segment (handle, &segment, &idx);
-       
-       type=_wapi_handle_get_shared_segment (segment)->handles[idx].type;
+       type = _wapi_private_handles[idx].type;
 
 #ifdef DEBUG
-       g_message (G_GNUC_PRETTY_FUNCTION ": testing 0x%x against 0x%x (%d)",
+       g_message ("%s: testing 0x%x against 0x%x (%d)", __func__,
                   handle_caps[type], caps, handle_caps[type] & caps);
 #endif
        
-       return((handle_caps[type] & caps)!=0);
-}
-
-void _wapi_handle_ops_close_shared (gpointer handle)
-{
-       guint32 idx, segment;
-       WapiHandleType type;
-
-       _wapi_handle_segment (handle, &segment, &idx);
-       
-       type=_wapi_handle_get_shared_segment (segment)->handles[idx].type;
-
-       if(handle_ops[type]!=NULL && handle_ops[type]->close_shared!=NULL) {
-               handle_ops[type]->close_shared (handle);
-       }
+       return((handle_caps[type] & caps) != 0);
 }
 
-void _wapi_handle_ops_close_private (gpointer handle)
+void _wapi_handle_ops_close (gpointer handle)
 {
-       guint32 idx, segment;
+       guint32 idx = GPOINTER_TO_UINT(handle);
        WapiHandleType type;
 
-       _wapi_handle_segment (handle, &segment, &idx);
-
-       type=_wapi_handle_get_shared_segment (segment)->handles[idx].type;
-
-       /* When a handle in the process of being destroyed the shared
-        * type has already been set to UNUSED
-        */
-       if(type==WAPI_HANDLE_UNUSED && _wapi_private_data!=NULL) {
-               type=_wapi_handle_get_private_segment (segment)->handles[idx].type;
-       }
+       type = _wapi_private_handles[idx].type;
 
-       if(handle_ops[type]!=NULL && handle_ops[type]->close_private!=NULL) {
-               handle_ops[type]->close_private (handle);
+       if (handle_ops[type] != NULL &&
+           handle_ops[type]->close != NULL) {
+               handle_ops[type]->close (handle);
        }
 }
 
 void _wapi_handle_ops_signal (gpointer handle)
 {
-       guint32 idx, segment;
+       guint32 idx = GPOINTER_TO_UINT(handle);
        WapiHandleType type;
 
-       _wapi_handle_segment (handle, &segment, &idx);
+       type = _wapi_private_handles[idx].type;
 
-       type=_wapi_handle_get_shared_segment (segment)->handles[idx].type;
-
-       if(handle_ops[type]!=NULL && handle_ops[type]->signal!=NULL) {
+       if (handle_ops[type] != NULL && handle_ops[type]->signal != NULL) {
                handle_ops[type]->signal (handle);
        }
 }
 
-void _wapi_handle_ops_own (gpointer handle)
+gboolean _wapi_handle_ops_own (gpointer handle)
 {
-       guint32 idx, segment;
+       guint32 idx = GPOINTER_TO_UINT(handle);
        WapiHandleType type;
-
-       _wapi_handle_segment (handle, &segment, &idx);
        
-       type=_wapi_handle_get_shared_segment (segment)->handles[idx].type;
+       type = _wapi_private_handles[idx].type;
 
-       if(handle_ops[type]!=NULL && handle_ops[type]->own_handle!=NULL) {
-               handle_ops[type]->own_handle (handle);
+       if (handle_ops[type] != NULL && handle_ops[type]->own_handle != NULL) {
+               return(handle_ops[type]->own_handle (handle));
+       } else {
+               return(FALSE);
        }
 }
 
 gboolean _wapi_handle_ops_isowned (gpointer handle)
 {
-       guint32 idx, segment;
+       guint32 idx = GPOINTER_TO_UINT(handle);
        WapiHandleType type;
 
-       _wapi_handle_segment (handle, &segment, &idx);
-       
-       type=_wapi_handle_get_shared_segment (segment)->handles[idx].type;
+       type = _wapi_private_handles[idx].type;
 
-       if(handle_ops[type]!=NULL && handle_ops[type]->is_owned!=NULL) {
+       if (handle_ops[type] != NULL && handle_ops[type]->is_owned != NULL) {
                return(handle_ops[type]->is_owned (handle));
        } else {
                return(FALSE);
@@ -1298,31 +1013,63 @@ gboolean _wapi_handle_count_signalled_handles (guint32 numhandles,
        guint32 count, i, iter=0;
        gboolean ret;
        int thr_ret;
+       WapiHandleType type;
        
        /* Lock all the handles, with backoff */
 again:
        for(i=0; i<numhandles; i++) {
-               guint32 idx, segment;
-               
-               _wapi_handle_segment (handles[i], &segment, &idx);
-               
+               gpointer handle = handles[i];
+               guint32 idx = GPOINTER_TO_UINT(handle);
+               guint32 now = (guint32)(time(NULL) & 0xFFFFFFFF);
+
 #ifdef DEBUG
-               g_message (G_GNUC_PRETTY_FUNCTION ": attempting to lock %p",
-                          handles[i]);
+               g_message ("%s: attempting to lock %p", __func__, handle);
 #endif
 
-               ret=mono_mutex_trylock (&_wapi_handle_get_shared_segment (segment)->handles[idx].signal_mutex);
-               if(ret!=0) {
+               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);
+               }
+               
+               if (thr_ret != 0) {
                        /* Bummer */
-                       struct timespec sleepytime;
                        
 #ifdef DEBUG
-                       g_message (G_GNUC_PRETTY_FUNCTION ": attempt failed for %p", handles[i]);
+                       g_message ("%s: attempt failed for %p: %s", __func__,
+                                  handle, strerror (thr_ret));
 #endif
 
-                       while(i--) {
-                               _wapi_handle_segment (handles[i], &segment, &idx);
-                               thr_ret = mono_mutex_unlock (&_wapi_handle_get_shared_segment (segment)->handles[idx].signal_mutex);
+                       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);
+                               }
                                g_assert (thr_ret == 0);
                        }
 
@@ -1332,51 +1079,51 @@ again:
                         */
                        iter++;
                        if(iter==100) {
-                               g_warning (G_GNUC_PRETTY_FUNCTION
-                                          ": iteration overflow!");
+                               g_warning ("%s: iteration overflow!",
+                                          __func__);
                                iter=1;
                        }
                        
-                       sleepytime.tv_sec=0;
-                       sleepytime.tv_nsec=10000000 * iter;     /* 10ms*iter */
-                       
 #ifdef DEBUG
-                       g_message (G_GNUC_PRETTY_FUNCTION
-                                  ": Backing off for %d ms", iter*10);
+                       g_message ("%s: Backing off for %d ms", __func__,
+                                  iter*10);
 #endif
-                       nanosleep (&sleepytime, NULL);
+                       _wapi_handle_spin (10 * iter);
                        
                        goto again;
                }
        }
        
 #ifdef DEBUG
-       g_message (G_GNUC_PRETTY_FUNCTION ": Locked all handles");
+       g_message ("%s: Locked all handles", __func__);
 #endif
 
        count=0;
        *lowest=numhandles;
        
        for(i=0; i<numhandles; i++) {
-               guint32 idx, segment;
-
-               _wapi_handle_ref (handles[i]);
+               gpointer handle = handles[i];
+               guint32 idx = GPOINTER_TO_UINT(handle);
                
-               _wapi_handle_segment (handles[i], &segment, &idx);
+               type = _wapi_private_handles[idx].type;
+
+               _wapi_handle_ref (handle);
                
 #ifdef DEBUG
-               g_message (G_GNUC_PRETTY_FUNCTION ": Checking handle %p",
-                          handles[i]);
+               g_message ("%s: Checking handle %p", __func__, handle);
 #endif
 
-               if(((_wapi_handle_test_capabilities (handles[i], WAPI_HANDLE_CAP_OWN)==TRUE) &&
-                   (_wapi_handle_ops_isowned (handles[i])==TRUE)) ||
-                  (_wapi_handle_get_shared_segment (segment)->handles[idx].signalled==TRUE)) {
+               if(((_wapi_handle_test_capabilities (handle, WAPI_HANDLE_CAP_OWN)==TRUE) &&
+                   (_wapi_handle_ops_isowned (handle) == TRUE)) ||
+                  (_WAPI_SHARED_HANDLE(type) &&
+                   WAPI_SHARED_HANDLE_METADATA(handle).signalled == TRUE) ||
+                  (!_WAPI_SHARED_HANDLE(type) &&
+                   _wapi_private_handles[idx].signalled == TRUE)) {
                        count++;
                        
 #ifdef DEBUG
-                       g_message (G_GNUC_PRETTY_FUNCTION
-                                  ": Handle %p signalled", handles[i]);
+                       g_message ("%s: Handle %p signalled", __func__,
+                                  handle);
 #endif
                        if(*lowest>i) {
                                *lowest=i;
@@ -1385,19 +1132,18 @@ again:
        }
        
 #ifdef DEBUG
-       g_message (G_GNUC_PRETTY_FUNCTION ": %d event handles signalled",
-                  count);
+       g_message ("%s: %d event handles signalled", __func__, count);
 #endif
 
-       if((waitall==TRUE && count==numhandles) ||
-          (waitall==FALSE && count>0)) {
+       if ((waitall == TRUE && count == numhandles) ||
+           (waitall == FALSE && count > 0)) {
                ret=TRUE;
        } else {
                ret=FALSE;
        }
        
 #ifdef DEBUG
-       g_message (G_GNUC_PRETTY_FUNCTION ": Returning %d", ret);
+       g_message ("%s: Returning %d", __func__, ret);
 #endif
 
        *retcount=count;
@@ -1411,150 +1157,225 @@ void _wapi_handle_unlock_handles (guint32 numhandles, gpointer *handles)
        int thr_ret;
        
        for(i=0; i<numhandles; i++) {
-               guint32 idx, segment;
-
-               _wapi_handle_segment (handles[i], &segment, &idx);
-
+               gpointer handle = handles[i];
+               guint32 idx = GPOINTER_TO_UINT(handle);
+               WapiHandleType type = _wapi_private_handles[idx].type;
+               
 #ifdef DEBUG
-               g_message (G_GNUC_PRETTY_FUNCTION ": unlocking handle %p",
-                          handles[i]);
+               g_message ("%s: unlocking handle %p", __func__, handle);
 #endif
 
-               thr_ret = mono_mutex_unlock (&_wapi_handle_get_shared_segment (segment)->handles[idx].signal_mutex);
-               g_assert (thr_ret == 0);
+               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);
+               }
 
-               _wapi_handle_unref (handles[i]);
+               _wapi_handle_unref (handle);
        }
 }
 
-/* Process-shared handles (currently only process and thread handles
- * are allowed, and they only work because once signalled they can't
- * become unsignalled) are waited for by one process and signalled by
- * another.  Without process-shared conditions, the waiting process
- * will block forever.  To get around this, the four handle waiting
- * functions use a short timeout when _POSIX_THREAD_PROCESS_SHARED is
- * not available.  They also return "success" if the fake timeout
- * expired, and let the caller check signal status.
- */
 int _wapi_handle_wait_signal (void)
 {
-#if defined(_POSIX_THREAD_PROCESS_SHARED) && _POSIX_THREAD_PROCESS_SHARED != -1
-       return(mono_cond_wait (&_wapi_handle_get_shared_segment (0)->signal_cond,
-                              &_wapi_handle_get_shared_segment (0)->signal_mutex));
-#else
+       return(mono_cond_wait (&_wapi_global_signal_cond,
+                              &_wapi_global_signal_mutex));
+}
+
+int _wapi_handle_timedwait_signal (struct timespec *timeout)
+{
+       return(mono_cond_timedwait (&_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;
        
-       _wapi_calc_timeout (&fake_timeout, 100);
+#ifdef DEBUG
+       g_message ("%s: poll private and shared handles", __func__);
+#endif
 
-       ret=mono_cond_timedwait (&_wapi_handle_get_private_segment (0)->signal_cond,
-                                &_wapi_handle_get_private_segment (0)->signal_mutex,
-                                &fake_timeout);
-       if(ret==ETIMEDOUT) {
-               ret=0;
-       }
+       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(ret);
-#endif /* _POSIX_THREAD_PROCESS_SHARED */
+                               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
+                */
+       }
 }
 
-int _wapi_handle_timedwait_signal (struct timespec *timeout)
+int _wapi_handle_timedwait_signal_poll_share (struct timespec *timeout)
 {
-#if defined(_POSIX_THREAD_PROCESS_SHARED) && _POSIX_THREAD_PROCESS_SHARED != -1
-       return(mono_cond_timedwait (&_wapi_handle_get_shared_segment (0)->signal_cond,
-                                   &_wapi_handle_get_shared_segment (0)->signal_mutex,
-                                   timeout));
-#else
        struct timespec fake_timeout;
+       guint32 signal_count = _wapi_shared_layout->signal_count;
        int ret;
        
-       _wapi_calc_timeout (&fake_timeout, 100);
+#ifdef DEBUG
+       g_message ("%s: poll private and shared handles", __func__);
+#endif
        
-       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 */
-               ret=mono_cond_timedwait (&_wapi_handle_get_private_segment (0)->signal_cond,
-                                        &_wapi_handle_get_private_segment (0)->signal_mutex,
-                                        timeout);
-       } else {
-               ret=mono_cond_timedwait (&_wapi_handle_get_private_segment (0)->signal_cond,
-                                        &_wapi_handle_get_private_segment (0)->signal_mutex,
-                                        &fake_timeout);
-               if(ret==ETIMEDOUT) {
-                       ret=0;
-               }
-       }
+       do {
+               _wapi_calc_timeout (&fake_timeout, 100);
        
-       return(ret);
-#endif /* _POSIX_THREAD_PROCESS_SHARED */
+               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);
+                       /* If this times out, it will compare the
+                        * shared signal counter and then if that
+                        * hasn't increased will fall out of the
+                        * do-while loop.
+                        */
+                       if (ret != ETIMEDOUT) {
+                               /* Either a private handle was
+                                * signalled, or an error.
+                                */
+#ifdef DEBUG
+                               g_message ("%s: returning: %d", __func__, ret);
+#endif
+                               return (ret);
+                       }
+               } 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;
+                       } else {
+                               /* Either a private handle was
+                                * signalled, or an error
+                                */
+#ifdef DEBUG
+                               g_message ("%s: returning: %d", __func__, ret);
+#endif
+                               return (ret);
+                       }
+               }
+
+               /* No private handle was signalled, so 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);
 }
 
 int _wapi_handle_wait_signal_handle (gpointer handle)
 {
-#if defined(_POSIX_THREAD_PROCESS_SHARED) && _POSIX_THREAD_PROCESS_SHARED != -1
-       guint32 idx, segment;
-
-       _wapi_handle_segment (handle, &segment, &idx);
-       
-       return(mono_cond_wait (&_wapi_handle_get_shared_segment (segment)->handles[idx].signal_cond,
-                              &_wapi_handle_get_shared_segment (segment)->handles[idx].signal_mutex));
-#else
-       guint32 idx, segment;
-       struct timespec fake_timeout;
-       int ret;
+       guint32 idx = GPOINTER_TO_UINT(handle);
        
-       _wapi_handle_segment (handle, &segment, &idx);
-       _wapi_calc_timeout (&fake_timeout, 100);
+#ifdef DEBUG
+       g_message ("%s: waiting for %p", __func__, handle);
+#endif
        
-       ret=mono_cond_timedwait (&_wapi_handle_get_shared_segment (segment)->handles[idx].signal_cond,
-                                &_wapi_handle_get_shared_segment (segment)->handles[idx].signal_mutex,
-                                &fake_timeout);
-       if(ret==ETIMEDOUT) {
-               ret=0;
+       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(ret);
-#endif /* _POSIX_THREAD_PROCESS_SHARED */
 }
 
 int _wapi_handle_timedwait_signal_handle (gpointer handle,
                                          struct timespec *timeout)
 {
-#if defined(_POSIX_THREAD_PROCESS_SHARED) && _POSIX_THREAD_PROCESS_SHARED != -1
-       guint32 idx, segment;
-
-       _wapi_handle_segment (handle, &segment, &idx);
+       guint32 idx = GPOINTER_TO_UINT(handle);
        
-       return(mono_cond_timedwait (&_wapi_handle_get_shared_segment (segment)->handles[idx].signal_cond,
-                                   &_wapi_handle_get_shared_segment (segment)->handles[idx].signal_mutex,
-                                   timeout));
-#else
-       guint32 idx, segment;
-       struct timespec fake_timeout;
-       int ret;
-       
-       _wapi_handle_segment (handle, &segment, &idx);
-       _wapi_calc_timeout (&fake_timeout, 100);
+#ifdef DEBUG
+       g_message ("%s: waiting for %p (type %s)", __func__, handle,
+                  _wapi_handle_typename[_wapi_handle_type (handle)]);
+#endif
        
-       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 */
-               ret=mono_cond_timedwait (&_wapi_handle_get_shared_segment (segment)->handles[idx].signal_cond,
-                                        &_wapi_handle_get_shared_segment (segment)->handles[idx].signal_mutex,
-                                        timeout);
-       } else {
-               ret=mono_cond_timedwait (&_wapi_handle_get_shared_segment (segment)->handles[idx].signal_cond,
-                                        &_wapi_handle_get_shared_segment (segment)->handles[idx].signal_mutex,
-                                        &fake_timeout);
-               if(ret==ETIMEDOUT) {
-                       ret=0;
+       if (_WAPI_SHARED_HANDLE (_wapi_handle_type (handle))) {
+               struct timespec fake_timeout;
+
+               while (1) {
+                       if (WAPI_SHARED_HANDLE_METADATA(handle).signalled == TRUE) {
+                               return (0);
+                       }
+               
+                       _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)) {
+                               /* 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));
        }
-       
-       return(ret);
-#endif /* _POSIX_THREAD_PROCESS_SHARED */
 }
 
 gboolean _wapi_handle_process_fork (guint32 cmd, guint32 env, guint32 dir,
@@ -1566,6 +1387,7 @@ gboolean _wapi_handle_process_fork (guint32 cmd, guint32 env, guint32 dir,
                                    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;
@@ -1584,9 +1406,9 @@ gboolean _wapi_handle_process_fork (guint32 cmd, guint32 env, guint32 dir,
        fork_proc.u.process_fork.inherit=inherit;
        fork_proc.u.process_fork.flags=flags;
        
-       in_fd=_wapi_file_handle_to_fd (stdin_handle);
-       out_fd=_wapi_file_handle_to_fd (stdout_handle);
-       err_fd=_wapi_file_handle_to_fd (stderr_handle);
+       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 */
@@ -1609,24 +1431,44 @@ gboolean _wapi_handle_process_fork (guint32 cmd, guint32 env, guint32 dir,
                 * exec_errno will be set, and the handle will be
                 * signalled immediately.
                 */
-               if(process_handle==0 || thread_handle==0) {
+               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);
                }
        } else {
-               g_warning (G_GNUC_PRETTY_FUNCTION
-                          ": bogus daemon response, type %d",
+               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;
@@ -1643,8 +1485,7 @@ _wapi_handle_process_kill (pid_t process, guint32 signo, gint *errnum)
        _wapi_daemon_request_response (daemon_sock, &killproc, &killprocresp);
 
        if (killprocresp.type != WapiHandleResponseType_ProcessKill) {
-               g_warning (G_GNUC_PRETTY_FUNCTION
-                          ": bogus daemon response, type %d",
+               g_warning ("%s: bogus daemon response, type %d", __func__,
                           killprocresp.type);
                g_assert_not_reached ();
        }
@@ -1654,68 +1495,296 @@ _wapi_handle_process_kill (pid_t process, guint32 signo, gint *errnum)
                *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,
                                        guint32 new_sharemode,
                                        guint32 new_access,
                                        guint32 *old_sharemode,
-                                       guint32 *old_access)
+                                       guint32 *old_access,
+                                       struct _WapiFileShare **share_info)
 {
-       WapiHandleRequest req = {0};
-       WapiHandleResponse resp = {0};
-       
-       if(shared != TRUE) {
-               /* No daemon means we don't know if a file is sharable.
-                * We're running in our own little world if this is
-                * the case, so there's no point in pretending that
-                * the file isn't sharable.
+       struct _WapiFileShare *file_share;
+       guint32 now = (guint32)(time(NULL) & 0xFFFFFFFF);
+       int thr_ret, i, first_unused = -1;
+       gboolean exists = FALSE;
+       
+       /* Marking this as COLLECTION_UNSAFE prevents entries from
+        * expiring under us as we search
+        */
+       _WAPI_HANDLE_COLLECTION_UNSAFE;
+       
+       /* Prevent new entries racing with us */
+       do {
+               now = (guint32)(time(NULL) & 0xFFFFFFFF);
+
+               thr_ret = _wapi_timestamp_exclusion (&_wapi_fileshare_layout->share_check, now);
+               if (thr_ret == EBUSY) {
+                       _wapi_handle_spin (100);
+               }
+       } while (thr_ret == EBUSY);
+       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
                 */
-               return(FALSE);
+               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 (&file_share->handle_refs);
+                       
+                       exists = TRUE;
+                       break;
+               }
        }
        
-       req.type = WapiHandleRequestType_GetOrSetShare;
-       req.u.get_or_set_share.device = device;
-       req.u.get_or_set_share.inode = inode;
-       req.u.get_or_set_share.new_sharemode = new_sharemode;
-       req.u.get_or_set_share.new_access = new_access;
-       
-       _wapi_daemon_request_response (daemon_sock, &req, &resp);
-       if (resp.type != WapiHandleResponseType_GetOrSetShare) {
-               g_warning (G_GNUC_PRETTY_FUNCTION
-                          ": bogus daemon response, type %d", resp.type);
-               g_assert_not_reached ();
+       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->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);
        }
        
-       *old_sharemode = resp.u.get_or_set_share.sharemode;
-       *old_access = resp.u.get_or_set_share.access;
+       thr_ret = _wapi_timestamp_release (&_wapi_fileshare_layout->share_check, now);
+
+       _WAPI_HANDLE_COLLECTION_SAFE;
 
-       return(resp.u.get_or_set_share.exists);
+       return(exists);
 }
 
-void _wapi_handle_set_share (dev_t device, ino_t inode, guint32 sharemode,
-                            guint32 access)
+/* Scan /proc/<pids>/fd/ for open file descriptors to the file in
+ * question.  If there are none, reset the share info.
+ *
+ * This implementation is Linux-specific; legacy systems will have to
+ * 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)
 {
-       WapiHandleRequest req = {0};
-       WapiHandleResponse resp = {0};
+       DIR *proc_dir;
+       struct dirent *proc_entry;
+       gboolean found = FALSE;
+       pid_t self = getpid();
+       int pid;
+       guint32 now = (guint32)(time(NULL) & 0xFFFFFFFF);
+       int thr_ret;
        
-       if(shared != TRUE) {
-               /* No daemon, so there's no one else to tell about
-                * file sharing.
-                */
+       proc_dir = opendir ("/proc");
+       if (proc_dir == NULL) {
                return;
        }
+       
+       /* Marking this as COLLECTION_UNSAFE prevents entries from
+        * expiring under us if we remove this one
+        */
+       _WAPI_HANDLE_COLLECTION_UNSAFE;
+       
+       /* Prevent new entries racing with us */
+       do {
+               now = (guint32)(time(NULL) & 0xFFFFFFFF);
+
+               thr_ret = _wapi_timestamp_exclusion (&_wapi_fileshare_layout->share_check, now);
+               if (thr_ret == EBUSY) {
+                       _wapi_handle_spin (100);
+               }
+       } while (thr_ret == EBUSY);
+       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
+                        */
+                       DIR *fd_dir;
+                       struct dirent *fd_entry;
+                       char subdir[_POSIX_PATH_MAX];
+                       
+                       g_snprintf (subdir, _POSIX_PATH_MAX, "/proc/%d/fd",
+                                   pid);
+                       
+                       fd_dir = opendir (subdir);
+                       if (fd_dir == NULL) {
+                               continue;
+                       }
+                       
+                       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, "..")) {
+                                       continue;
+                               }
+
+                               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
+
+                                       found = TRUE;
+                               }
+                       }
+                       
+                       closedir (fd_dir);
+               }
+       }
+       
+       closedir (proc_dir);
+
+       if (found == FALSE) {
+               /* Blank out this entry, as it is stale */
+#ifdef DEBUG
+               g_message ("%s: Didn't find it, destroying entry", __func__);
+#endif
+
+               memset (share_info, '\0', sizeof(struct _WapiFileShare));
+       }
+
+       thr_ret = _wapi_timestamp_release (&_wapi_fileshare_layout->share_check, now);
+
+       _WAPI_HANDLE_COLLECTION_SAFE;
+}
+
+void _wapi_handle_dump (void)
+{
+       struct _WapiHandleUnshared *handle_data;
+       guint32 i;
+
+       for (i = 0; i < _wapi_private_handle_count; i++) {
+               handle_data = &_wapi_private_handles[i];
+
+               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");
+       }
+}
 
-       req.type = WapiHandleRequestType_SetShare;
-       req.u.set_share.device = device;
-       req.u.set_share.inode = inode;
-       req.u.set_share.sharemode = sharemode;
-       req.u.set_share.access = access;
+static void _wapi_shared_details (gpointer handle_info)
+{
+       struct _WapiHandle_shared_ref *shared = (struct _WapiHandle_shared_ref *)handle_info;
        
-       _wapi_daemon_request_response (daemon_sock, &req, &resp);
-       if (resp.type != WapiHandleResponseType_SetShare) {
-               g_warning (G_GNUC_PRETTY_FUNCTION
-                          ": bogus daemon response, type %d", resp.type);
-               g_assert_not_reached ();
+       g_print ("offset: 0x%x", shared->offset);
+}
+
+void _wapi_handle_update_refs (void)
+{
+       guint32 i, lock_now;
+       int thr_ret;
+       
+       _WAPI_HANDLE_COLLECTION_UNSAFE;
+
+       /* Prevent file share entries racing with us */
+       do {
+               lock_now = (guint32)(time(NULL) & 0xFFFFFFFF);
+
+               thr_ret = _wapi_timestamp_exclusion (&_wapi_fileshare_layout->share_check, lock_now);
+
+               if (thr_ret == EBUSY) {
+                       _wapi_handle_spin (100);
+               }
+       } while (thr_ret == EBUSY);
+       g_assert(thr_ret == 0);
+
+       for (i = 0; i < _wapi_private_handle_count; i++) {
+               struct _WapiHandleUnshared *handle = &_wapi_private_handles[i];
+               guint32 now = (guint32)(time (NULL) & 0xFFFFFFFF);
+
+               if (_WAPI_SHARED_HANDLE(handle->type)) {
+                       struct _WapiHandleSharedMetadata *shared_meta;
+                       
+#ifdef DEBUG
+                       g_message ("%s: (%d) handle 0x%x is SHARED", __func__,
+                                  getpid (), i);
+#endif
+
+                       shared_meta = &_wapi_shared_layout->metadata[handle->u.shared.offset];
+
+#ifdef DEBUG
+                       g_message ("%s: (%d) Updating timstamp of handle 0x%x",
+                                  __func__, getpid(),
+                                  handle->u.shared.offset);
+#endif
+
+                       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);
+#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_timestamp_release (&_wapi_fileshare_layout->share_check, lock_now);
+       _WAPI_HANDLE_COLLECTION_SAFE;
 }