* Makefile (MCS) [PROFILE=default]: Force testing of 'mcs'.
[mono.git] / mono / io-layer / handles.c
index 20074e5baac5be18564d8ce78b71e7e031b46f56..a1c3dde13efd889a11789b6069411d2e8b706dbb 100644 (file)
@@ -12,6 +12,7 @@
 #include <pthread.h>
 #include <errno.h>
 #include <unistd.h>
+#include <string.h>
 #include <sys/types.h>
 #include <sys/socket.h>
 #include <sys/un.h>
@@ -76,15 +77,19 @@ pthread_mutex_t _wapi_shared_mutex=PTHREAD_MUTEX_INITIALIZER;
  */
 guint32 _wapi_shm_mapped_segments;
 
+guint32 _wapi_fd_offset_table_size;
+gpointer *_wapi_fd_offset_table=NULL;
+
 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:
 
 #ifndef DISABLE_SHARED_HANDLES
@@ -102,8 +107,10 @@ attach_again:
                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");
+                       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 */
        }
@@ -142,6 +149,9 @@ attach_again:
                                
                                goto attach_again;
                        }
+               } else {
+                       _wapi_fd_offset_table_size = _wapi_shared_data[0]->fd_offset_table_size;
+                       _wapi_fd_offset_table=g_new0 (gpointer, _wapi_fd_offset_table_size);
                }
        }
 
@@ -154,18 +164,34 @@ attach_again:
                _wapi_shared_data[0]->num_segments=1;
 
                _wapi_shared_scratch=g_new0 (struct _WapiHandleScratch, 1);
+
+               _wapi_fd_offset_table_size=getdtablesize ();
+               _wapi_fd_offset_table=g_new0 (gpointer,
+                                             _wapi_fd_offset_table_size);
        }
        _wapi_private_data[0]=g_new0 (struct _WapiHandlePrivate_list, 1);
        _wapi_shm_mapped_segments=1;
 
-       pthread_mutexattr_init (&mutex_shared_attr);
-       pthread_condattr_init (&cond_shared_attr);
-
+       thr_ret = pthread_mutexattr_init (&mutex_shared_attr);
+       g_assert (thr_ret == 0);
+       
+       thr_ret = pthread_condattr_init (&cond_shared_attr);
+       g_assert (thr_ret == 0);
+       
 #if defined(_POSIX_THREAD_PROCESS_SHARED) && _POSIX_THREAD_PROCESS_SHARED != -1
-       pthread_mutexattr_setpshared (&mutex_shared_attr,
-                                     PTHREAD_PROCESS_SHARED);
-       pthread_condattr_setpshared (&cond_shared_attr,
-                                    PTHREAD_PROCESS_SHARED);
+       thr_ret = pthread_mutexattr_setpshared (&mutex_shared_attr,
+                                               PTHREAD_PROCESS_SHARED);
+       g_assert (thr_ret == 0);
+       
+       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);
+       g_assert (thr_ret == 0);
+       
+       thr_ret = mono_mutex_init(&_wapi_private_data[0]->signal_mutex, NULL);
+       g_assert (thr_ret == 0);
 #endif
 }
 
@@ -223,6 +249,8 @@ guint32 _wapi_handle_new_internal (WapiHandleType type)
        guint32 segment, idx;
        guint32 i, j;
        static guint32 last=1;
+       int thr_ret;
+       guint32 num_segments = _wapi_handle_get_shared_segment (0)->num_segments;
        
        /* A linear scan should be fast enough.  Start from the last
         * allocation, assuming that handles are allocated more often
@@ -233,8 +261,7 @@ guint32 _wapi_handle_new_internal (WapiHandleType type)
 #endif
 again:
        _wapi_handle_segment (GUINT_TO_POINTER (last), &segment, &idx);
-       for(i=segment; i<_wapi_handle_get_shared_segment (0)->num_segments;
-           i++) {
+       for(i=segment; i < num_segments; i++) {
                if(i!=segment) {
                        idx=0;
                }
@@ -242,8 +269,20 @@ again:
                for(j=idx; j<_WAPI_HANDLES_PER_SEGMENT; j++) {
                        struct _WapiHandleShared *shared;
                
-                       /* Make sure we dont try and assign handle 0 */
-                       if (i==0 && j==0) {
+                       /* Make sure we dont try and assign the
+                        * handles that would clash with fds
+                        */
+                       if ((i * _WAPI_HANDLES_PER_SEGMENT + j) < _wapi_fd_offset_table_size) {
+                               i = _wapi_fd_offset_table_size / _WAPI_HANDLES_PER_SEGMENT;
+                               j = _wapi_fd_offset_table_size - (i * _WAPI_HANDLES_PER_SEGMENT);
+                               
+                               if (i >= num_segments) {
+                                       /* Need to get the caller to
+                                        * add more shared segments
+                                        */
+                                       return(0);
+                               }
+                               
                                continue;
                        }
                        
@@ -254,8 +293,17 @@ again:
                                shared->type=type;
                                shared->signalled=FALSE;
 #if defined(_POSIX_THREAD_PROCESS_SHARED) && _POSIX_THREAD_PROCESS_SHARED != -1
-                               mono_mutex_init (&shared.signal_mutex, &mutex_shared_attr);
-                               pthread_cond_init (&shared.signal_cond, &cond_shared_attr);
+                               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));
@@ -278,16 +326,17 @@ gpointer _wapi_handle_new (WapiHandleType type)
 {
        static mono_once_t shared_init_once = MONO_ONCE_INIT;
        static pthread_mutex_t scan_mutex=PTHREAD_MUTEX_INITIALIZER;
-       guint32 handle_idx, idx, segment;
+       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;
        
        mono_once (&shared_init_once, shared_init);
-
+       
 again:
        if(shared==TRUE) {
                new.type=WapiHandleRequestType_New;
@@ -304,9 +353,12 @@ again:
                        g_assert_not_reached ();
                }
        } else {
-               pthread_mutex_lock (&scan_mutex);
-               handle_idx=_wapi_handle_new_internal (type);
-               if(handle_idx==0) {
+               pthread_cleanup_push ((void(*)(void *))pthread_mutex_unlock,
+                                     (void *)&scan_mutex);
+               thr_ret = pthread_mutex_lock (&scan_mutex);
+               g_assert (thr_ret == 0);
+               
+               while ((handle_idx = _wapi_handle_new_internal (type)) == 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);
@@ -314,7 +366,6 @@ again:
                        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);
                        } else {
                                /* Map failed.  Just return 0 meaning
                                 * "out of handles"
@@ -324,9 +375,15 @@ again:
                
                _wapi_handle_segment (GUINT_TO_POINTER (handle_idx), &segment, &idx);
                _wapi_handle_get_shared_segment (segment)->handles[idx].ref++;
-               pthread_mutex_unlock (&scan_mutex);
+
+               thr_ret = pthread_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_offset_table_size);
+       
        if(handle_idx==0) {
                g_warning (G_GNUC_PRETTY_FUNCTION ": Ran out of handles!");
 
@@ -357,8 +414,11 @@ again:
        }
        
 #if !defined(_POSIX_THREAD_PROCESS_SHARED) || _POSIX_THREAD_PROCESS_SHARED == -1
-       mono_mutex_init (&_wapi_handle_get_shared_segment (segment)->handles[idx].signal_mutex, &mutex_shared_attr);
-       pthread_cond_init (&_wapi_handle_get_shared_segment (segment)->handles[idx].signal_cond, &cond_shared_attr);
+       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);
 
@@ -373,10 +433,12 @@ gboolean _wapi_lookup_handle (gpointer handle, WapiHandleType type,
                              gpointer *shared, gpointer *private)
 {
        struct _WapiHandleShared *shared_handle_data;
-       struct _WapiHandlePrivate *private_handle_data;
+       struct _WapiHandlePrivate *private_handle_data = NULL;
        guint32 idx;
        guint32 segment;
 
+       g_assert (GPOINTER_TO_UINT (handle) >= _wapi_fd_offset_table_size);
+       
        _wapi_handle_segment (handle, &segment, &idx);
        _wapi_handle_ensure_mapped (segment);
        
@@ -453,8 +515,110 @@ gpointer _wapi_search_handle (WapiHandleType type,
        return(GUINT_TO_POINTER (i));
 }
 
+gpointer _wapi_search_handle_namespace (WapiHandleType type,
+                                       gchar *utf8_name, gpointer *shared,
+                                       gpointer *private)
+{
+       struct _WapiHandleShared *shared_handle_data;
+       struct _WapiHandlePrivate *private_handle_data;
+       guint32 i, segment, idx;
+
+#ifdef DEBUG
+       g_message (G_GNUC_PRETTY_FUNCTION
+                  ": Lookup for handle named [%s] type %d", utf8_name, type);
+#endif
+
+       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];
+               
+               /* 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
+
+                       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);
+#endif
+                                       return(_WAPI_HANDLE_INVALID);
+                               } else {
+                                       /* fall through so we can fill
+                                        * in the data
+                                        */
+#ifdef DEBUG
+                                       g_message (G_GNUC_PRETTY_FUNCTION ": handle 0x%x matches name and type", i);
+#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));
+}
+
 void _wapi_handle_ref (gpointer handle)
 {
+       g_assert (GPOINTER_TO_UINT (handle) >= _wapi_fd_offset_table_size);
+       
        if(shared==TRUE) {
                WapiHandleRequest req={0};
                WapiHandleResponse resp={0};
@@ -484,11 +648,15 @@ void _wapi_handle_ref (gpointer handle)
        }
 }
 
+/* The handle must not be locked on entry to this function */
 void _wapi_handle_unref (gpointer handle)
 {
        guint32 idx, segment;
-       gboolean destroy;
-
+       gboolean destroy = FALSE;
+       int thr_ret;
+       
+       g_assert (GPOINTER_TO_UINT (handle) >= _wapi_fd_offset_table_size);
+       
        _wapi_handle_segment (handle, &segment, &idx);
        
        if(shared==TRUE) {
@@ -532,20 +700,23 @@ void _wapi_handle_unref (gpointer handle)
                if(shared==FALSE) {
                        _wapi_handle_ops_close_shared (handle);
 
-                       mono_mutex_destroy (&_wapi_handle_get_shared_segment (segment)->handles[idx].signal_mutex);
-                       pthread_cond_destroy (&_wapi_handle_get_shared_segment (segment)->handles[idx].signal_cond);
                        memset (&_wapi_handle_get_shared_segment (segment)->handles[idx].u, '\0', sizeof(_wapi_handle_get_shared_segment (segment)->handles[idx].u));
-               
-               }
-#if !defined(_POSIX_THREAD_PROCESS_SHARED) || _POSIX_THREAD_PROCESS_SHARED == -1
-               else {
-                       mono_mutex_destroy (&_wapi_handle_get_shared_segment (segment)->handles[idx].signal_mutex);
-                       pthread_cond_destroy (&_wapi_handle_get_shared_segment (segment)->handles[idx].signal_cond);
                }
-#endif
 
                _wapi_handle_ops_close_private (handle);
                _wapi_handle_get_shared_segment (segment)->handles[idx].type=WAPI_HANDLE_UNUSED;
+               _wapi_handle_get_private_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);
        }
 }
 
@@ -579,7 +750,7 @@ static void _wapi_handle_scratch_expand (void)
 static guint32 _wapi_handle_scratch_locate_space (guint32 bytes)
 {
        guint32 idx=0, last_idx=0;
-       struct _WapiScratchHeader *hdr, *last_hdr;
+       struct _WapiScratchHeader *hdr, *last_hdr = NULL;
        gboolean last_was_free=FALSE;
        guchar *storage=_wapi_shared_scratch->scratch_data;
        
@@ -755,9 +926,11 @@ guint32 _wapi_handle_scratch_store_internal (guint32 bytes, gboolean *remap)
 
 guint32 _wapi_handle_scratch_store (gconstpointer data, guint32 bytes)
 {
-       guint32 idx, store_bytes;
+       guint32 idx = 0, store_bytes;
        gboolean remap;
-
+       int thr_ret;
+       guint32 ret = 0;
+       
 #ifdef DEBUG
        g_message (G_GNUC_PRETTY_FUNCTION ": storing %d bytes", bytes);
 #endif
@@ -770,8 +943,11 @@ guint32 _wapi_handle_scratch_store (gconstpointer data, guint32 bytes)
        /* Align bytes to 32 bits (needed for sparc at least) */
        store_bytes = (((bytes) + 3) & (~3));
 
-       pthread_mutex_lock (&_wapi_scratch_mutex);
-
+       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};
@@ -796,17 +972,17 @@ guint32 _wapi_handle_scratch_store (gconstpointer data, guint32 bytes)
        
                if(remap==TRUE) {
                        munmap (_wapi_shared_scratch, old_len);
-                       _wapi_shared_scratch=_wapi_shm_file_map (WAPI_SHM_SCRATCH, 0, NULL);
+                       _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 */
-                       pthread_mutex_unlock (&_wapi_scratch_mutex);
-                       return(0);
+                       goto cleanup;
                }
        }
-
+       ret = idx;
+       
 #ifdef DEBUG
        g_message (G_GNUC_PRETTY_FUNCTION
                   ": stored [%s] at %d (len %d, aligned len %d)",
@@ -815,9 +991,12 @@ guint32 _wapi_handle_scratch_store (gconstpointer data, guint32 bytes)
        
        memcpy (&_wapi_shared_scratch->scratch_data[idx], data, bytes);
 
-       pthread_mutex_unlock (&_wapi_scratch_mutex);
+cleanup:
+       thr_ret = pthread_mutex_unlock (&_wapi_scratch_mutex);
+       g_assert (thr_ret == 0);
+       pthread_cleanup_pop (0);
        
-       return(idx);
+       return(ret);
 }
 
 guint32 _wapi_handle_scratch_store_string_array (gchar **data)
@@ -864,12 +1043,16 @@ gpointer _wapi_handle_scratch_lookup (guint32 idx)
        struct _WapiScratchHeader *hdr;
        gpointer ret;
        guchar *storage;
+       int thr_ret;
        
        if(idx < HDRSIZE || idx > _wapi_shared_scratch->data_len) {
                return(NULL);
        }
 
-       pthread_mutex_lock (&_wapi_scratch_mutex);
+       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);
        
        storage=_wapi_shared_scratch->scratch_data;
        
@@ -877,7 +1060,9 @@ gpointer _wapi_handle_scratch_lookup (guint32 idx)
        ret=g_malloc0 (hdr->length+1);
        memcpy (ret, &storage[idx], hdr->length);
 
-       pthread_mutex_unlock (&_wapi_scratch_mutex);
+       thr_ret = pthread_mutex_unlock (&_wapi_scratch_mutex);
+       g_assert (thr_ret == 0);
+       pthread_cleanup_pop (0);
 
        return(ret);
 }
@@ -935,12 +1120,16 @@ 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;
        }
 
-       pthread_mutex_lock (&_wapi_scratch_mutex);
+       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);
        
        storage=_wapi_shared_scratch->scratch_data;
        
@@ -952,7 +1141,9 @@ void _wapi_handle_scratch_delete_internal (guint32 idx)
         * free, but the _store() function will do that anyway.
         */
 
-       pthread_mutex_unlock (&_wapi_scratch_mutex);
+       thr_ret = pthread_mutex_unlock (&_wapi_scratch_mutex);
+       g_assert (thr_ret == 0);
+       pthread_cleanup_pop (0);
 }
 
 void _wapi_handle_scratch_delete (guint32 idx)
@@ -1019,6 +1210,10 @@ gboolean _wapi_handle_test_capabilities (gpointer handle,
        guint32 idx, segment;
        WapiHandleType type;
 
+       if (GPOINTER_TO_UINT (handle) < _wapi_fd_offset_table_size) {
+               handle = _wapi_handle_fd_offset_to_handle (handle);
+       }
+       
        _wapi_handle_segment (handle, &segment, &idx);
        
        type=_wapi_handle_get_shared_segment (segment)->handles[idx].type;
@@ -1036,6 +1231,10 @@ void _wapi_handle_ops_close_shared (gpointer handle)
        guint32 idx, segment;
        WapiHandleType type;
 
+       if (GPOINTER_TO_UINT (handle) < _wapi_fd_offset_table_size) {
+               handle = _wapi_handle_fd_offset_to_handle (handle);
+       }
+
        _wapi_handle_segment (handle, &segment, &idx);
        
        type=_wapi_handle_get_shared_segment (segment)->handles[idx].type;
@@ -1050,6 +1249,10 @@ void _wapi_handle_ops_close_private (gpointer handle)
        guint32 idx, segment;
        WapiHandleType type;
 
+       if (GPOINTER_TO_UINT (handle) < _wapi_fd_offset_table_size) {
+               handle = _wapi_handle_fd_offset_to_handle (handle);
+       }
+
        _wapi_handle_segment (handle, &segment, &idx);
 
        type=_wapi_handle_get_shared_segment (segment)->handles[idx].type;
@@ -1071,6 +1274,10 @@ void _wapi_handle_ops_signal (gpointer handle)
        guint32 idx, segment;
        WapiHandleType type;
 
+       if (GPOINTER_TO_UINT (handle) < _wapi_fd_offset_table_size) {
+               handle = _wapi_handle_fd_offset_to_handle (handle);
+       }
+
        _wapi_handle_segment (handle, &segment, &idx);
 
        type=_wapi_handle_get_shared_segment (segment)->handles[idx].type;
@@ -1085,6 +1292,10 @@ void _wapi_handle_ops_own (gpointer handle)
        guint32 idx, segment;
        WapiHandleType type;
 
+       if (GPOINTER_TO_UINT (handle) < _wapi_fd_offset_table_size) {
+               handle = _wapi_handle_fd_offset_to_handle (handle);
+       }
+
        _wapi_handle_segment (handle, &segment, &idx);
        
        type=_wapi_handle_get_shared_segment (segment)->handles[idx].type;
@@ -1099,6 +1310,10 @@ gboolean _wapi_handle_ops_isowned (gpointer handle)
        guint32 idx, segment;
        WapiHandleType type;
 
+       if (GPOINTER_TO_UINT (handle) < _wapi_fd_offset_table_size) {
+               handle = _wapi_handle_fd_offset_to_handle (handle);
+       }
+
        _wapi_handle_segment (handle, &segment, &idx);
        
        type=_wapi_handle_get_shared_segment (segment)->handles[idx].type;
@@ -1123,6 +1338,14 @@ gboolean _wapi_handle_ops_isowned (gpointer handle)
  */
 gboolean CloseHandle(gpointer handle)
 {
+       if (GPOINTER_TO_UINT (handle) < _wapi_fd_offset_table_size) {
+               handle = _wapi_handle_fd_offset_to_handle (handle);
+       }
+
+       if (handle == NULL) {
+               return(FALSE);
+       }
+
        _wapi_handle_unref (handle);
        
        return(TRUE);
@@ -1136,17 +1359,23 @@ gboolean _wapi_handle_count_signalled_handles (guint32 numhandles,
 {
        guint32 count, i, iter=0;
        gboolean ret;
+       int thr_ret;
        
        /* Lock all the handles, with backoff */
 again:
        for(i=0; i<numhandles; i++) {
                guint32 idx, segment;
+               gpointer handle = handles[i];
                
-               _wapi_handle_segment (handles[i], &segment, &idx);
+               if (GPOINTER_TO_UINT (handle) < _wapi_fd_offset_table_size) {
+                       handle = _wapi_handle_fd_offset_to_handle (handle);
+               }
+               
+               _wapi_handle_segment (handle, &segment, &idx);
                
 #ifdef DEBUG
                g_message (G_GNUC_PRETTY_FUNCTION ": attempting to lock %p",
-                          handles[i]);
+                          handle);
 #endif
 
                ret=mono_mutex_trylock (&_wapi_handle_get_shared_segment (segment)->handles[idx].signal_mutex);
@@ -1155,12 +1384,19 @@ again:
                        struct timespec sleepytime;
                        
 #ifdef DEBUG
-                       g_message (G_GNUC_PRETTY_FUNCTION ": attempt failed for %p", handles[i]);
+                       g_message (G_GNUC_PRETTY_FUNCTION ": attempt failed for %p: %s", handle, strerror (ret));
 #endif
 
                        while(i--) {
-                               _wapi_handle_segment (handles[i], &segment, &idx);
-                               mono_mutex_unlock (&_wapi_handle_get_shared_segment (segment)->handles[idx].signal_mutex);
+                               handle = handles[i];
+               
+                               if (GPOINTER_TO_UINT (handle) < _wapi_fd_offset_table_size) {
+                                       handle = _wapi_handle_fd_offset_to_handle (handle);
+                               }
+
+                               _wapi_handle_segment (handle, &segment, &idx);
+                               thr_ret = mono_mutex_unlock (&_wapi_handle_get_shared_segment (segment)->handles[idx].signal_mutex);
+                               g_assert (thr_ret == 0);
                        }
 
                        /* If iter ever reaches 100 the nanosleep will
@@ -1196,22 +1432,29 @@ again:
        
        for(i=0; i<numhandles; i++) {
                guint32 idx, segment;
-
-               _wapi_handle_segment (handles[i], &segment, &idx);
+               gpointer handle = handles[i];
+               
+               if (GPOINTER_TO_UINT (handle) < _wapi_fd_offset_table_size) {
+                       handle = _wapi_handle_fd_offset_to_handle (handle);
+               }
+               
+               _wapi_handle_ref (handle);
+               
+               _wapi_handle_segment (handle, &segment, &idx);
                
 #ifdef DEBUG
                g_message (G_GNUC_PRETTY_FUNCTION ": Checking handle %p",
-                          handles[i]);
+                          handle);
 #endif
 
-               if(((_wapi_handle_test_capabilities (handles[i], WAPI_HANDLE_CAP_OWN)==TRUE) &&
-                   (_wapi_handle_ops_isowned (handles[i])==TRUE)) ||
+               if(((_wapi_handle_test_capabilities (handle, WAPI_HANDLE_CAP_OWN)==TRUE) &&
+                   (_wapi_handle_ops_isowned (handle)==TRUE)) ||
                   (_wapi_handle_get_shared_segment (segment)->handles[idx].signalled==TRUE)) {
                        count++;
                        
 #ifdef DEBUG
                        g_message (G_GNUC_PRETTY_FUNCTION
-                                  ": Handle %p signalled", handles[i]);
+                                  ": Handle %p signalled", handle);
 #endif
                        if(*lowest>i) {
                                *lowest=i;
@@ -1243,18 +1486,27 @@ again:
 void _wapi_handle_unlock_handles (guint32 numhandles, gpointer *handles)
 {
        guint32 i;
+       int thr_ret;
        
        for(i=0; i<numhandles; i++) {
                guint32 idx, segment;
-
-               _wapi_handle_segment (handles[i], &segment, &idx);
+               gpointer handle = handles[i];
+               
+               if (GPOINTER_TO_UINT (handle) < _wapi_fd_offset_table_size) {
+                       handle = _wapi_handle_fd_offset_to_handle (handle);
+               }
+               
+               _wapi_handle_segment (handle, &segment, &idx);
 
 #ifdef DEBUG
                g_message (G_GNUC_PRETTY_FUNCTION ": unlocking handle %p",
-                          handles[i]);
+                          handle);
 #endif
 
-               mono_mutex_unlock (&_wapi_handle_get_shared_segment (segment)->handles[idx].signal_mutex);
+               thr_ret = mono_mutex_unlock (&_wapi_handle_get_shared_segment (segment)->handles[idx].signal_mutex);
+               g_assert (thr_ret == 0);
+
+               _wapi_handle_unref (handle);
        }
 }
 
@@ -1326,6 +1578,10 @@ int _wapi_handle_wait_signal_handle (gpointer handle)
 #if defined(_POSIX_THREAD_PROCESS_SHARED) && _POSIX_THREAD_PROCESS_SHARED != -1
        guint32 idx, segment;
 
+       if (GPOINTER_TO_UINT (handle) < _wapi_fd_offset_table_size) {
+               handle = _wapi_handle_fd_offset_to_handle (handle);
+       }
+
        _wapi_handle_segment (handle, &segment, &idx);
        
        return(mono_cond_wait (&_wapi_handle_get_shared_segment (segment)->handles[idx].signal_cond,
@@ -1335,6 +1591,10 @@ int _wapi_handle_wait_signal_handle (gpointer handle)
        struct timespec fake_timeout;
        int ret;
        
+       if (GPOINTER_TO_UINT (handle) < _wapi_fd_offset_table_size) {
+               handle = _wapi_handle_fd_offset_to_handle (handle);
+       }
+
        _wapi_handle_segment (handle, &segment, &idx);
        _wapi_calc_timeout (&fake_timeout, 100);
        
@@ -1355,6 +1615,10 @@ int _wapi_handle_timedwait_signal_handle (gpointer handle,
 #if defined(_POSIX_THREAD_PROCESS_SHARED) && _POSIX_THREAD_PROCESS_SHARED != -1
        guint32 idx, segment;
 
+       if (GPOINTER_TO_UINT (handle) < _wapi_fd_offset_table_size) {
+               handle = _wapi_handle_fd_offset_to_handle (handle);
+       }
+
        _wapi_handle_segment (handle, &segment, &idx);
        
        return(mono_cond_timedwait (&_wapi_handle_get_shared_segment (segment)->handles[idx].signal_cond,
@@ -1365,6 +1629,10 @@ int _wapi_handle_timedwait_signal_handle (gpointer handle,
        struct timespec fake_timeout;
        int ret;
        
+       if (GPOINTER_TO_UINT (handle) < _wapi_fd_offset_table_size) {
+               handle = _wapi_handle_fd_offset_to_handle (handle);
+       }
+
        _wapi_handle_segment (handle, &segment, &idx);
        _wapi_calc_timeout (&fake_timeout, 100);
        
@@ -1440,9 +1708,26 @@ 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 {
@@ -1454,3 +1739,99 @@ gboolean _wapi_handle_process_fork (guint32 cmd, guint32 env, guint32 dir,
        
        return(FALSE);
 }
+
+gboolean
+_wapi_handle_process_kill (pid_t process, guint32 signo, gint *errnum)
+{
+       WapiHandleRequest killproc = {0};
+       WapiHandleResponse killprocresp = {0};
+       gint result;
+       
+       if (shared != TRUE) {
+               if (errnum) *errnum = EINVAL;
+               return FALSE;
+       }
+
+       killproc.type = WapiHandleRequestType_ProcessKill;
+       killproc.u.process_kill.pid = process;
+       killproc.u.process_kill.signo = signo;
+       
+       _wapi_daemon_request_response (daemon_sock, &killproc, &killprocresp);
+
+       if (killprocresp.type != WapiHandleResponseType_ProcessKill) {
+               g_warning (G_GNUC_PRETTY_FUNCTION
+                          ": bogus daemon response, type %d",
+                          killprocresp.type);
+               g_assert_not_reached ();
+       }
+
+       result = killprocresp.u.process_kill.err;
+       if (result != 0 && errnum != NULL)
+               *errnum = (result == FALSE) ? result : 0;
+       
+       return (result == 0);
+}
+
+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)
+{
+       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.
+                */
+               return(FALSE);
+       }
+       
+       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 ();
+       }
+       
+       *old_sharemode = resp.u.get_or_set_share.sharemode;
+       *old_access = resp.u.get_or_set_share.access;
+
+       return(resp.u.get_or_set_share.exists);
+}
+
+void _wapi_handle_set_share (dev_t device, ino_t inode, guint32 sharemode,
+                            guint32 access)
+{
+       WapiHandleRequest req = {0};
+       WapiHandleResponse resp = {0};
+       
+       if(shared != TRUE) {
+               /* No daemon, so there's no one else to tell about
+                * file sharing.
+                */
+               return;
+       }
+
+       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;
+       
+       _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 ();
+       }
+}