#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 */
+#undef DEBUG_REFS
-/* 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;
+static void (*_wapi_handle_ops_get_close_func (WapiHandleType type))(gpointer, gpointer);
static WapiHandleCapability handle_caps[WAPI_HANDLE_COUNT]={0};
static struct _WapiHandleOps *handle_ops[WAPI_HANDLE_COUNT]={
&_wapi_find_ops,
&_wapi_process_ops,
&_wapi_pipe_ops,
+ &_wapi_namedmutex_ops,
};
-static int daemon_sock;
+static void _wapi_shared_details (gpointer handle_info);
-static pthread_mutexattr_t mutex_shared_attr;
-static pthread_condattr_t cond_shared_attr;
+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 */
+};
-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;
+const char *_wapi_handle_typename[] = {
+ "Unused",
+ "File",
+ "Console",
+ "Thread",
+ "Sem",
+ "Mutex",
+ "Event",
+ "Socket",
+ "Find",
+ "Process",
+ "Pipe",
+ "N.Mutex",
+ "Error!!"
+};
-/* 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
+/*
+ * We can hold _WAPI_PRIVATE_MAX_SLOTS * _WAPI_HANDLE_INITIAL_COUNT handles.
+ * If 4M handles are not enough... Oh, well... we will crash.
*/
-guint32 _wapi_shm_mapped_segments;
+#define SLOT_INDEX(x) (x / _WAPI_HANDLE_INITIAL_COUNT)
+#define SLOT_OFFSET(x) (x % _WAPI_HANDLE_INITIAL_COUNT)
+
+struct _WapiHandleUnshared *_wapi_private_handles [_WAPI_PRIVATE_MAX_SLOTS];
+static guint32 _wapi_private_handle_count = 0;
+
+struct _WapiHandleSharedLayout *_wapi_shared_layout = NULL;
+struct _WapiFileShareLayout *_wapi_fileshare_layout = NULL;
+
+guint32 _wapi_fd_reserve;
+mono_mutex_t _wapi_global_signal_mutex;
+pthread_cond_t _wapi_global_signal_cond;
+
+int _wapi_sem_id;
+
+static mono_mutex_t scan_mutex = MONO_MUTEX_INITIALIZER;
+
+static mono_once_t shared_init_once = MONO_ONCE_INIT;
static void shared_init (void)
{
- struct sockaddr_un shared_socket_address;
- gboolean tried_once=FALSE;
- int ret;
-
- _wapi_shared_data=g_new0 (struct _WapiHandleShared_list *, 1);
- _wapi_private_data=g_new0 (struct _WapiHandlePrivate_list *, 1);
+ int thr_ret;
+ int idx = 0;
-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");
- }
-#endif /* DISABLE_SHARED_HANDLES */
- }
-
+ do {
+ _wapi_private_handles [idx++] = g_new0 (struct _WapiHandleUnshared,
+ _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;
- }
- }
- }
+ _wapi_private_handle_count += _WAPI_HANDLE_INITIAL_COUNT;
+ } while(_wapi_fd_reserve > _wapi_private_handle_count);
+
+ _wapi_shared_layout = _wapi_shm_attach (WAPI_SHM_DATA);
+ g_assert (_wapi_shared_layout != NULL);
- 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_shm_semaphores_init ();
+
+ _wapi_fileshare_layout = _wapi_shm_attach (WAPI_SHM_FILESHARE);
+ g_assert (_wapi_fileshare_layout != NULL);
+
+ _wapi_collection_init ();
+
+ thr_ret = pthread_cond_init(&_wapi_global_signal_cond, NULL);
+ g_assert (thr_ret == 0);
+
+ thr_ret = mono_mutex_init(&_wapi_global_signal_mutex, NULL);
+ g_assert (thr_ret == 0);
+}
- _wapi_shared_scratch=g_new0 (struct _WapiHandleScratch, 1);
- }
- _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);
-
-#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);
-#else
- pthread_cond_init(&_wapi_private_data[0]->signal_cond, NULL);
- mono_mutex_init(&_wapi_private_data[0]->signal_mutex, NULL);
-#endif
+static void _wapi_handle_init_shared_metadata (struct _WapiHandleSharedMetadata *meta)
+{
+ meta->timestamp = (guint32)(time (NULL) & 0xFFFFFFFF);
+ meta->signalled = FALSE;
}
-#ifdef HEAVY_DEBUG
-static void
-print_handle_count (gint mask)
+static void _wapi_handle_init_shared (struct _WapiHandleShared *handle,
+ WapiHandleType type,
+ gpointer handle_specific)
{
- 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]++;
+ 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;
+ 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
- mono_mutex_init (&shared.signal_mutex, &mutex_shared_attr);
- pthread_cond_init (&shared.signal_cond, &cond_shared_attr);
-#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, idx, segment;
- gpointer handle;
- WapiHandleRequest new={0};
- WapiHandleResponse new_resp={0};
-#if HAVE_BOEHM_GC
- gboolean tried_collect=FALSE;
-#endif
+ 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_mutex_lock (&scan_mutex);
- 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);
+ /* 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];
+
+ 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++;
- pthread_mutex_unlock (&scan_mutex);
}
-
- 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);
-
- 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
- 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);
-#endif
- handle=GUINT_TO_POINTER (handle_idx);
+ /* Will need to expand the array. The caller will sort it out */
-#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;
- guint32 idx;
- guint32 segment;
-
- _wapi_handle_segment (handle, &segment, &idx);
- _wapi_handle_ensure_mapped (segment);
+ guint32 i, k, count;
+ static guint32 last = 0;
+ gboolean retry = FALSE;
- 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 (last < _wapi_fd_reserve) {
+ last = _wapi_fd_reserve;
+ } else {
+ retry = TRUE;
}
- 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);
- }
- }
-
- 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;
+again:
+ count = last;
+ for(i = SLOT_INDEX (count); _wapi_private_handles [i] != NULL; i++) {
+ for (k = SLOT_OFFSET (count); k < _WAPI_HANDLE_INITIAL_COUNT; k++) {
+ struct _WapiHandleUnshared *handle = &_wapi_private_handles [i][k];
- for(i=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];
-
- if(shared->type==type) {
- if(check (GUINT_TO_POINTER (i), user_data)==TRUE) {
- break;
+ if(handle->type == WAPI_HANDLE_UNUSED) {
+ last = count + 1;
+
+ _wapi_handle_init (handle, type, handle_specific);
+ return (count);
}
+ count++;
}
}
- if(i==_wapi_handle_get_shared_segment (0)->num_segments * _WAPI_HANDLES_PER_SEGMENT) {
- return(GUINT_TO_POINTER (0));
+ if(retry && 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;
-
+ 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 */
+ int idx = SLOT_INDEX (_wapi_private_handle_count);
+ _wapi_private_handles [idx] = g_new0 (struct _WapiHandleUnshared,
+ _WAPI_HANDLE_INITIAL_COUNT);
+
+ _wapi_private_handle_count += _WAPI_HANDLE_INITIAL_COUNT;
+ }
- shared=&_wapi_handle_get_shared_segment (segment)->handles[idx];
+ thr_ret = mono_mutex_unlock (&scan_mutex);
+ g_assert (thr_ret == 0);
+ pthread_cleanup_pop (0);
- /* 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
+ /* Make sure we left the space for fd mappings */
+ g_assert (handle_idx >= _wapi_fd_reserve);
+
+ handle = GUINT_TO_POINTER (handle_idx);
- 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);
+ g_message ("%s: Allocated new handle %p", __func__, handle);
#endif
- continue;
+
+ 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);
+ if (offset == 0) {
+ /* FIXME: grow the arrays */
+ return (_WAPI_HANDLE_INVALID);
}
-
- if(lookup_name==NULL) {
-#ifdef DEBUG
- g_message (G_GNUC_PRETTY_FUNCTION
- ": couldn't find handle 0x%x name",
- i);
-#endif
- continue;
+ }
+
+ ref = _wapi_handle_new_shared_offset (offset);
+ if (ref == 0) {
+ _wapi_handle_collect ();
+ ref = _wapi_handle_new_shared_offset (offset);
+
+ if (ref == 0) {
+ /* FIXME: grow the arrays */
+ return (_WAPI_HANDLE_INVALID);
}
-
+ }
+
+ _WAPI_PRIVATE_HANDLES(handle_idx).u.shared.offset = ref;
#ifdef DEBUG
- g_message (G_GNUC_PRETTY_FUNCTION ": name is [%s]",
- lookup_name);
+ g_message ("%s: New shared handle at offset 0x%x", __func__,
+ ref);
#endif
+ }
+
+ return(handle);
+}
- if(strcmp (lookup_name, utf8_name)==0) {
- if(shared->type!=type) {
- /* Its the wrong type, so fail now */
+gpointer _wapi_handle_new_from_offset (WapiHandleType type, guint32 offset)
+{
+ guint32 handle_idx = 0;
+ gpointer handle;
+ int thr_ret, i, k;
+
+ mono_once (&shared_init_once, shared_init);
+
#ifdef DEBUG
- g_message (G_GNUC_PRETTY_FUNCTION ": handle 0x%x matches name but is wrong type: %d", i, shared->type);
+ g_message ("%s: Creating new handle of type %s to offset %d", __func__,
+ _wapi_handle_typename[type], offset);
#endif
- return(_WAPI_HANDLE_INVALID);
- } else {
- /* fall through so we can fill
- * in the data
- */
+
+ g_assert(!_WAPI_FD_HANDLE(type));
+ g_assert(_WAPI_SHARED_HANDLE(type));
+ g_assert(offset != 0);
+
+ for (i = SLOT_INDEX (0); _wapi_private_handles [i] != NULL; i++) {
+ for (k = SLOT_OFFSET (0); k < _WAPI_HANDLE_INITIAL_COUNT; k++) {
+ struct _WapiHandleUnshared *handle_data = &_wapi_private_handles [i][k];
+
+ if (handle_data->type == type &&
+ handle_data->u.shared.offset == offset) {
+ handle = GUINT_TO_POINTER (i * _WAPI_HANDLE_INITIAL_COUNT + k);
+ _wapi_handle_ref (handle);
+
#ifdef DEBUG
- g_message (G_GNUC_PRETTY_FUNCTION ": handle 0x%x matches name and type", i);
+ g_message ("%s: Returning old handle %p referencing 0x%x", __func__, handle, offset);
#endif
- break;
- }
+ return (handle);
}
}
}
- 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;
- }
+ 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);
- if(private!=NULL) {
- private_handle_data=&_wapi_handle_get_private_segment (segment)->handles[idx];
+ while ((handle_idx = _wapi_handle_new_internal (type, NULL)) == 0) {
+ /* Try and expand the array, and have another go */
+ int idx = SLOT_INDEX (_wapi_private_handle_count);
+ _wapi_private_handles [idx] = g_new0 (struct _WapiHandleUnshared,
+ _WAPI_HANDLE_INITIAL_COUNT);
- *private=&private_handle_data->u;
+ _wapi_private_handle_count += _WAPI_HANDLE_INITIAL_COUNT;
}
-
- return(GUINT_TO_POINTER (i));
-}
-
-void _wapi_handle_ref (gpointer handle)
-{
- 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;
-
- _wapi_handle_segment (handle, &segment, &idx);
- _wapi_handle_get_shared_segment (segment)->handles[idx].ref++;
+ 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);
}
-void _wapi_handle_unref (gpointer handle)
+gpointer _wapi_handle_new_fd (WapiHandleType type, int fd,
+ gpointer handle_specific)
{
- guint32 idx, segment;
- gboolean destroy;
-
- _wapi_handle_segment (handle, &segment, &idx);
+ struct _WapiHandleUnshared *handle;
- 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.
- */
- destroy=(_wapi_handle_get_shared_segment (segment)->handles[idx].ref==0);
+ return(GUINT_TO_POINTER (_WAPI_HANDLE_INVALID));
}
- if(destroy==TRUE) {
+ handle = &_WAPI_PRIVATE_HANDLES(fd);
+
+ if (handle->type != WAPI_HANDLE_UNUSED) {
#ifdef DEBUG
- g_message (G_GNUC_PRETTY_FUNCTION ": Destroying handle %p",
- handle);
+ g_message ("%s: fd %d is already in use!", __func__, fd);
#endif
-
- if(shared==FALSE) {
- _wapi_handle_ops_close_shared (handle);
+ /* FIXME: clean up this handle? We can't do anything
+ * with the fd, cos thats the new one
+ */
+ }
- 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);
- }
+#ifdef DEBUG
+ g_message ("%s: Assigning new fd handle %d", __func__, fd);
#endif
- _wapi_handle_ops_close_private (handle);
- _wapi_handle_get_shared_segment (segment)->handles[idx].type=WAPI_HANDLE_UNUSED;
- }
+ _wapi_handle_init (handle, type, handle_specific);
+
+ 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;
+
+ /* Unsafe, because we don't want the handle to vanish
+ * while we're checking it
+ */
+ _WAPI_HANDLE_COLLECTION_UNSAFE;
- 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);
+
+ _WAPI_HANDLE_COLLECTION_SAFE;
} 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;
- 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;
-
-#ifdef DEBUG
- g_message (G_GNUC_PRETTY_FUNCTION ": new header at %d, length %d", idx+bytes, hdr->length);
-#endif
-
- /*
- * It was memset(0..) when free/made so no need to do it here
- */
+ g_assert(_WAPI_SHARED_HANDLE(type));
- 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);
+ g_message ("%s: copying handle %p type %s", __func__, handle,
+ _wapi_handle_typename[type]);
#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)
+gboolean _wapi_replace_handle (gpointer handle, WapiHandleType type,
+ struct _WapiHandleShared *handle_specific)
{
- guchar *storage;
- guint32 idx;
- struct _WapiScratchHeader *hdr;
-
+ struct _WapiHandleShared *shared_handle_data;
+ struct _WapiHandleSharedMetadata *shared_meta;
+ guint32 handle_idx = GPOINTER_TO_UINT(handle);
+ guint32 old_off, new_off, ref;
+
#ifdef DEBUG
- g_message (G_GNUC_PRETTY_FUNCTION ": storing %d bytes", bytes);
+ g_message ("%s: Replacing handle %p of type %s", __func__, handle,
+ _wapi_handle_typename[type]);
#endif
+
+ g_assert(_WAPI_SHARED_HANDLE(type));
+ g_assert(_WAPI_PRIVATE_HANDLES(handle_idx).type == type);
- *remap=FALSE;
+ ref = _WAPI_PRIVATE_HANDLES(handle_idx).u.shared.offset;
+ shared_meta = &_wapi_shared_layout->metadata[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");
-#endif
+ 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);
- _wapi_handle_scratch_expand ();
- *remap=TRUE;
- }
+ if (new_off == 0) {
+ /* FIXME: grow the arrays */
+ return (FALSE);
+ }
+ }
+
+ 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);
+ return (TRUE);
}
-guint32 _wapi_handle_scratch_store (gconstpointer data, guint32 bytes)
+void
+_wapi_handle_foreach (WapiHandleType type,
+ gboolean (*on_each)(gpointer test, gpointer user),
+ gpointer user_data)
{
- guint32 idx, store_bytes;
- gboolean remap;
-
-#ifdef DEBUG
- g_message (G_GNUC_PRETTY_FUNCTION ": storing %d bytes", bytes);
-#endif
-
- /* No point storing no data */
- if(bytes==0) {
- return(0);
+ struct _WapiHandleUnshared *handle_data = NULL;
+ gpointer ret = NULL;
+ guint32 i, k;
+ int thr_ret;
+
+ pthread_cleanup_push ((void(*)(void *))mono_mutex_unlock_in_cleanup,
+ (void *)&scan_mutex);
+ thr_ret = mono_mutex_lock (&scan_mutex);
+ g_assert (thr_ret == 0);
+
+ for (i = SLOT_INDEX (0); _wapi_private_handles [i] != NULL; i++) {
+ for (k = SLOT_OFFSET (0); k < _WAPI_HANDLE_INITIAL_COUNT; k++) {
+ handle_data = &_wapi_private_handles [i][k];
+
+ if (handle_data->type == type) {
+ ret = GUINT_TO_POINTER (i * _WAPI_HANDLE_INITIAL_COUNT + k);
+ if (on_each (ret, user_data) == TRUE)
+ break;
+ }
+ }
}
- /* Align bytes to 32 bits (needed for sparc at least) */
- store_bytes = (((bytes) + 3) & (~3));
+ thr_ret = mono_mutex_unlock (&scan_mutex);
+ g_assert (thr_ret == 0);
+ pthread_cleanup_pop (0);
+}
+
+/* This might list some shared handles twice if they are already
+ * opened by this process, and the check function returns FALSE the
+ * first time. Shared handles that are created during the search are
+ * unreffed if the check function returns FALSE, so callers must not
+ * rely on the handle persisting (unless the check function returns
+ * TRUE)
+ */
+gpointer _wapi_search_handle (WapiHandleType type,
+ gboolean (*check)(gpointer test, gpointer user),
+ gpointer user_data,
+ gpointer *handle_specific)
+{
+ struct _WapiHandleUnshared *handle_data = NULL;
+ gpointer ret = NULL;
+ guint32 i, k;
+ gboolean found = FALSE;
- pthread_mutex_lock (&_wapi_scratch_mutex);
- if(shared==TRUE) {
- WapiHandleRequest scratch={0};
- WapiHandleResponse scratch_resp={0};
- guint32 old_len=sizeof(struct _WapiHandleScratch) +
- _wapi_shared_scratch->data_len;
+ for (i = SLOT_INDEX (0); !found && _wapi_private_handles [i] != NULL; i++) {
+ for (k = SLOT_OFFSET (0); k < _WAPI_HANDLE_INITIAL_COUNT; k++) {
+ handle_data = &_wapi_private_handles [i][k];
- scratch.type=WapiHandleRequestType_Scratch;
- scratch.u.scratch.length=store_bytes;
-
- _wapi_daemon_request_response (daemon_sock, &scratch,
- &scratch_resp);
-
- 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 ();
- }
-
- 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 */
- pthread_mutex_unlock (&_wapi_scratch_mutex);
- return(0);
+ if (handle_data->type == type) {
+ ret = GUINT_TO_POINTER (i * _WAPI_HANDLE_INITIAL_COUNT + k);
+ if (check (ret, user_data) == TRUE) {
+ found = TRUE;
+ break;
+ }
+ }
}
}
+ if (!found) {
+ /* Not found yet, so search the shared memory too */
#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: Looking at other shared handles...", __func__);
#endif
-
- memcpy (&_wapi_shared_scratch->scratch_data[idx], data, bytes);
- pthread_mutex_unlock (&_wapi_scratch_mutex);
-
- return(idx);
-}
+ for (i = 0; i < _WAPI_HANDLE_INITIAL_COUNT; i++) {
+ struct _WapiHandleShared *shared;
+ struct _WapiHandleSharedMetadata *meta;
+ WapiHandleType shared_type;
-guint32 _wapi_handle_scratch_store_string_array (gchar **data)
-{
- guint32 *stored_strings, count=0, i, idx;
- gchar **strings;
-
- /* No point storing no data */
- if(data==NULL) {
- return(0);
- }
+ _WAPI_HANDLE_COLLECTION_UNSAFE;
+
+ meta = &_wapi_shared_layout->metadata[i];
+ shared = &_wapi_shared_layout->handles[meta->offset];
+ shared_type = shared->type;
+
+ _WAPI_HANDLE_COLLECTION_SAFE;
+
+ if (shared_type == type) {
+ ret = _wapi_handle_new_from_offset (type, i);
- strings=data;
- while(*strings!=NULL) {
- count++;
- strings++;
- }
-
#ifdef DEBUG
- g_message (G_GNUC_PRETTY_FUNCTION ": %d strings to store", count);
+ g_message ("%s: Opened tmp handle %p (type %s) from offset %d", __func__, ret, _wapi_handle_typename[type], meta->offset);
#endif
-
- if(count==0) {
- return(0);
- }
- /* stored_strings[0] is the count */
- stored_strings=g_new0 (guint32, count+1);
- stored_strings[0]=count;
+ if (check (ret, user_data) == TRUE) {
+ found = TRUE;
+ handle_data = &_WAPI_PRIVATE_HANDLES(GPOINTER_TO_UINT(ret));
+
+ break;
+ }
+
+ /* This isn't the handle we're looking
+ * for, so drop the reference we took
+ * in _wapi_handle_new_from_offset ()
+ */
+ _wapi_handle_unref (ret);
+ }
+ }
+ }
- strings=data;
- for(i=0; i<count; i++) {
- stored_strings[i+1]=_wapi_handle_scratch_store (strings[i], strlen (strings[i]));
+ if (!found) {
+ goto done;
}
-
- idx=_wapi_handle_scratch_store (stored_strings,
- sizeof(guint32)*(count+1));
- return(idx);
-}
+ 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;
+
+ /* Unsafe, because we don't want the handle to
+ * vanish while we're checking it
+ */
+ _WAPI_HANDLE_COLLECTION_UNSAFE;
-gpointer _wapi_handle_scratch_lookup (guint32 idx)
-{
- struct _WapiScratchHeader *hdr;
- gpointer ret;
- guchar *storage;
-
- if(idx < HDRSIZE || idx > _wapi_shared_scratch->data_len) {
- return(NULL);
- }
+ 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);
- pthread_mutex_lock (&_wapi_scratch_mutex);
-
- storage=_wapi_shared_scratch->scratch_data;
-
- hdr=(struct _WapiScratchHeader *)&storage[idx - HDRSIZE];
- ret=g_malloc0 (hdr->length+1);
- memcpy (ret, &storage[idx], hdr->length);
+ /* Make sure this handle doesn't vanish in the
+ * next collection
+ */
+ now = (guint32)(time (NULL) & 0xFFFFFFFF);
+ InterlockedExchange (&shared_meta->timestamp, now);
- pthread_mutex_unlock (&_wapi_scratch_mutex);
+ _WAPI_HANDLE_COLLECTION_SAFE;
+ } else {
+ *handle_specific = &handle_data->u;
+ }
+ }
+done:
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;
-
- if(idx < HDRSIZE || idx > _wapi_shared_scratch->data_len) {
- return(NULL);
- }
-
- stored_strings=_wapi_handle_scratch_lookup (idx);
- if(stored_strings==NULL) {
- return(NULL);
- }
+ struct _WapiHandleShared *shared_handle_data;
+ struct _WapiHandleSharedMetadata *shared_meta;
+ guint32 i;
+ gint32 ret = 0;
- /* stored_strings[0] is the number of strings, the index of
- * each string follows
- */
- count=stored_strings[0];
+ g_assert(_WAPI_SHARED_HANDLE(type));
#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;
-
- 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_mutex_lock (&_wapi_scratch_mutex);
-
- storage=_wapi_shared_scratch->scratch_data;
+done:
+ _WAPI_HANDLE_COLLECTION_SAFE;
- 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.
- */
-
- pthread_mutex_unlock (&_wapi_scratch_mutex);
+ 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);
+ guint32 now = (guint32)(time (NULL) & 0xFFFFFFFF);
+ struct _WapiHandleUnshared *handle_data = &_WAPI_PRIVATE_HANDLES(idx);
- _wapi_daemon_request_response (daemon_sock, &scratch_free,
- &scratch_free_resp);
-
- 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);
+ InterlockedIncrement (&handle_data->ref);
+
+ /* It's possible for processes to exit before getting around
+ * to updating timestamps in the collection thread, so if a
+ * shared handle is reffed do the timestamp here as well just
+ * to make sure.
+ */
+ if (_WAPI_SHARED_HANDLE(handle_data->type)) {
+ struct _WapiHandleSharedMetadata *shared_meta = &_wapi_shared_layout->metadata[handle_data->u.shared.offset];
+
+ InterlockedExchange (&shared_meta->timestamp, now);
}
+
+#ifdef DEBUG_REFS
+ g_message ("%s: handle %p ref now %d", __func__, handle,
+ _WAPI_PRIVATE_HANDLES(idx).ref);
+#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) {
+ /* Need to copy the handle info, reset the slot in the
+ * array, and _only then_ call the close function to
+ * avoid race conditions (eg file descriptors being
+ * closed, and another file being opened getting the
+ * same fd racing the memset())
+ */
+ struct _WapiHandleUnshared handle_data;
+ WapiHandleType type = _WAPI_PRIVATE_HANDLES(idx).type;
+ void (*close_func)(gpointer, gpointer) = _wapi_handle_ops_get_close_func (type);
+
+#ifdef DEBUG
+ g_message ("%s: Destroying handle %p", __func__, handle);
+#endif
+
+ memcpy (&handle_data, &_WAPI_PRIVATE_HANDLES(idx),
+ sizeof (struct _WapiHandleUnshared));
+
+ memset (&_WAPI_PRIVATE_HANDLES(idx).u, '\0',
+ sizeof(_WAPI_PRIVATE_HANDLES(idx).u));
+
+ _WAPI_PRIVATE_HANDLES(idx).type = WAPI_HANDLE_UNUSED;
+
+ if (!_WAPI_SHARED_HANDLE(type)) {
+ /* Destroy the mutex and cond var. We hope nobody
+ * tried to grab them between the handle unlock and
+ * now, but pthreads doesn't have a
+ * "unlock_and_destroy" atomic function.
+ */
+ thr_ret = mono_mutex_destroy (&_WAPI_PRIVATE_HANDLES(idx).signal_mutex);
+ g_assert (thr_ret == 0);
+
+ thr_ret = pthread_cond_destroy (&_WAPI_PRIVATE_HANDLES(idx).signal_cond);
+ g_assert (thr_ret == 0);
+ }
- g_free (stored_strings);
+ /* The garbage collector will take care of shared data
+ * if this is a shared handle
+ */
+
+ if (close_func != NULL) {
+ close_func (handle, &handle_data.u);
+ }
+ }
}
void _wapi_handle_register_capabilities (WapiHandleType type,
WapiHandleCapability caps)
{
- handle_caps[type]=caps;
+ handle_caps[type] = caps;
}
gboolean _wapi_handle_test_capabilities (gpointer handle,
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);
+ return((handle_caps[type] & caps) != 0);
}
-void _wapi_handle_ops_close_shared (gpointer handle)
+static void (*_wapi_handle_ops_get_close_func (WapiHandleType type))(gpointer, gpointer)
{
- 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);
+ if (handle_ops[type] != NULL &&
+ handle_ops[type]->close != NULL) {
+ return (handle_ops[type]->close);
}
+
+ return (NULL);
}
-void _wapi_handle_ops_close_private (gpointer handle)
+void _wapi_handle_ops_close (gpointer handle, gpointer data)
{
- 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, data);
}
}
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);
}
}
+guint32 _wapi_handle_ops_special_wait (gpointer handle, guint32 timeout)
+{
+ guint32 idx = GPOINTER_TO_UINT(handle);
+ WapiHandleType type;
+
+ type = _WAPI_PRIVATE_HANDLES(idx).type;
+
+ if (handle_ops[type] != NULL &&
+ handle_ops[type]->special_wait != NULL) {
+ return(handle_ops[type]->special_wait (handle, timeout));
+ } else {
+ return(WAIT_FAILED);
+ }
+}
+
+
/**
* CloseHandle:
* @handle: The handle to release
{
guint32 count, i, iter=0;
gboolean ret;
+ int thr_ret;
+ WapiHandleType type;
/* Lock all the handles, with backoff */
again:
+ thr_ret = _wapi_handle_lock_shared_handles ();
+ g_assert (thr_ret == 0);
+
for(i=0; i<numhandles; i++) {
- guint32 idx, segment;
-
- _wapi_handle_segment (handles[i], &segment, &idx);
-
+ gpointer handle = handles[i];
+ guint32 idx = GPOINTER_TO_UINT(handle);
+
#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;
+
+ 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);
- mono_mutex_unlock (&_wapi_handle_get_shared_segment (segment)->handles[idx].signal_mutex);
+ thr_ret = _wapi_handle_unlock_shared_handles ();
+ g_assert (thr_ret == 0);
+
+ while (i--) {
+ handle = handles[i];
+ idx = GPOINTER_TO_UINT(handle);
+
+ thr_ret = _wapi_handle_unlock_handle (handle);
+ g_assert (thr_ret == 0);
}
/* If iter ever reaches 100 the nanosleep will
*/
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;
+ gpointer handle = handles[i];
+ guint32 idx = GPOINTER_TO_UINT(handle);
+
+ type = _WAPI_PRIVATE_HANDLES(idx).type;
- _wapi_handle_segment (handles[i], &segment, &idx);
+ _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;
}
#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;
void _wapi_handle_unlock_handles (guint32 numhandles, gpointer *handles)
{
guint32 i;
+ int thr_ret;
+
+ thr_ret = _wapi_handle_unlock_shared_handles ();
+ g_assert (thr_ret == 0);
for(i=0; i<numhandles; i++) {
- guint32 idx, segment;
-
- _wapi_handle_segment (handles[i], &segment, &idx);
-
+ gpointer handle = handles[i];
+
#ifdef DEBUG
- g_message (G_GNUC_PRETTY_FUNCTION ": unlocking handle %p",
- handles[i]);
+ g_message ("%s: unlocking handle %p", __func__, handle);
#endif
- mono_mutex_unlock (&_wapi_handle_get_shared_segment (segment)->handles[idx].signal_mutex);
- }
-}
-
-/* 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
- struct timespec fake_timeout;
- int ret;
-
- _wapi_calc_timeout (&fake_timeout, 100);
-
- 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;
+ thr_ret = _wapi_handle_unlock_handle (handle);
+ g_assert (thr_ret == 0);
}
-
- return(ret);
-#endif /* _POSIX_THREAD_PROCESS_SHARED */
}
-int _wapi_handle_timedwait_signal (struct timespec *timeout)
+static int timedwait_signal_poll_cond (pthread_cond_t *cond, mono_mutex_t *mutex, 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;
int ret;
_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)) {
+ if (timeout != NULL && ((fake_timeout.tv_sec > timeout->tv_sec) ||
+ (fake_timeout.tv_sec == timeout->tv_sec &&
+ fake_timeout.tv_nsec > timeout->tv_nsec))) {
/* Real timeout is less than 100ms time */
- ret=mono_cond_timedwait (&_wapi_handle_get_private_segment (0)->signal_cond,
- &_wapi_handle_get_private_segment (0)->signal_mutex,
- timeout);
+ ret=mono_cond_timedwait (cond, 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=mono_cond_timedwait (cond, mutex, &fake_timeout);
+
+ /* Mask the fake timeout, this will cause
+ * another poll if the cond was not really signaled
+ */
+ if (ret==ETIMEDOUT) {
ret=0;
}
}
return(ret);
-#endif /* _POSIX_THREAD_PROCESS_SHARED */
}
-int _wapi_handle_wait_signal_handle (gpointer handle)
+int _wapi_handle_wait_signal (void)
{
-#if defined(_POSIX_THREAD_PROCESS_SHARED) && _POSIX_THREAD_PROCESS_SHARED != -1
- guint32 idx, segment;
+ return timedwait_signal_poll_cond (&_wapi_global_signal_cond, &_wapi_global_signal_mutex, NULL);
+}
- _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;
+int _wapi_handle_timedwait_signal (struct timespec *timeout)
+{
+ return timedwait_signal_poll_cond (&_wapi_global_signal_cond, &_wapi_global_signal_mutex, timeout);
+}
+
+int _wapi_handle_wait_signal_poll_share (void)
+{
+#ifdef DEBUG
+ g_message ("%s: poll private and shared handles", __func__);
+#endif
- _wapi_handle_segment (handle, &segment, &idx);
- _wapi_calc_timeout (&fake_timeout, 100);
+ return timedwait_signal_poll_cond (&_wapi_global_signal_cond, &_wapi_global_signal_mutex, NULL);
+}
+
+int _wapi_handle_timedwait_signal_poll_share (struct timespec *timeout)
+{
+#ifdef DEBUG
+ g_message ("%s: poll private and shared handles", __func__);
+#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;
- }
+ return timedwait_signal_poll_cond (&_wapi_global_signal_cond, &_wapi_global_signal_mutex, timeout);
+}
- return(ret);
-#endif /* _POSIX_THREAD_PROCESS_SHARED */
+int _wapi_handle_wait_signal_handle (gpointer handle)
+{
+#ifdef DEBUG
+ g_message ("%s: waiting for %p", __func__, handle);
+#endif
+
+ return _wapi_handle_timedwait_signal_handle (handle, NULL);
}
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;
+#ifdef DEBUG
+ g_message ("%s: waiting for %p (type %s)", __func__, handle,
+ _wapi_handle_typename[_wapi_handle_type (handle)]);
+#endif
+
+ if (_WAPI_SHARED_HANDLE (_wapi_handle_type (handle))) {
+ if (WAPI_SHARED_HANDLE_METADATA(handle).signalled == TRUE) {
+ return (0);
+ }
+ if (timeout != NULL) {
+ struct timespec fake_timeout;
+ _wapi_calc_timeout (&fake_timeout, 100);
+
+ if ((fake_timeout.tv_sec > timeout->tv_sec) ||
+ (fake_timeout.tv_sec == timeout->tv_sec &&
+ fake_timeout.tv_nsec > timeout->tv_nsec)) {
+ /* FIXME: Real timeout is less than
+ * 100ms time, but is it really worth
+ * calculating to the exact ms?
+ */
+ _wapi_handle_spin (100);
- _wapi_handle_segment (handle, &segment, &idx);
+ if (WAPI_SHARED_HANDLE_METADATA(handle).signalled == TRUE) {
+ return (0);
+ } else {
+ return (ETIMEDOUT);
+ }
+ }
+ }
+ _wapi_handle_spin (100);
+ return (0);
+
+ } else {
+ guint32 idx = GPOINTER_TO_UINT(handle);
+ return timedwait_signal_poll_cond (&_WAPI_PRIVATE_HANDLES(idx).signal_cond, &_WAPI_PRIVATE_HANDLES(idx).signal_mutex, timeout);
+ }
+}
+
+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,
+ struct _WapiFileShare **share_info)
+{
+ struct _WapiFileShare *file_share;
+ guint32 now = (guint32)(time(NULL) & 0xFFFFFFFF);
+ int thr_ret, i, first_unused = -1;
+ gboolean exists = FALSE;
- 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;
+ /* Marking this as COLLECTION_UNSAFE prevents entries from
+ * expiring under us as we search
+ */
+ _WAPI_HANDLE_COLLECTION_UNSAFE;
- _wapi_handle_segment (handle, &segment, &idx);
- _wapi_calc_timeout (&fake_timeout, 100);
+ /* Prevent new entries racing with us */
+ thr_ret = _wapi_shm_sem_lock (_WAPI_SHARED_SEM_SHARE);
+ g_assert (thr_ret == 0);
- 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 a linear scan gets too slow we'll have to fit a hash
+ * table onto the shared mem backing store
+ */
+ *share_info = NULL;
+ for (i = 0; i <= _wapi_fileshare_layout->hwm; i++) {
+ file_share = &_wapi_fileshare_layout->share_info[i];
+
+ /* Make a note of an unused slot, in case we need to
+ * store share info
+ */
+ if (first_unused == -1 && file_share->handle_refs == 0) {
+ first_unused = i;
+ continue;
+ }
+
+ if (file_share->handle_refs == 0) {
+ continue;
+ }
+
+ if (file_share->device == device &&
+ file_share->inode == inode) {
+ *old_sharemode = file_share->sharemode;
+ *old_access = file_share->access;
+ *share_info = file_share;
+
+ /* Increment the reference count while we
+ * still have sole access to the shared area.
+ * This makes the increment atomic wrt
+ * collections
+ */
+ InterlockedIncrement (&file_share->handle_refs);
+
+ exists = TRUE;
+ break;
}
}
- return(ret);
-#endif /* _POSIX_THREAD_PROCESS_SHARED */
+ if (!exists) {
+ if (i == _WAPI_FILESHARE_SIZE && first_unused == -1) {
+ /* No more space */
+ } else {
+ if (first_unused == -1) {
+ file_share = &_wapi_fileshare_layout->share_info[++i];
+ _wapi_fileshare_layout->hwm = i;
+ } else {
+ file_share = &_wapi_fileshare_layout->share_info[first_unused];
+ }
+
+ file_share->device = device;
+ file_share->inode = inode;
+ file_share->opened_by_pid = getpid ();
+ file_share->sharemode = new_sharemode;
+ file_share->access = new_access;
+ file_share->handle_refs = 1;
+ *share_info = file_share;
+ }
+ }
+
+ if (*share_info != NULL) {
+ InterlockedExchange (&(*share_info)->timestamp, now);
+ }
+
+ thr_ret = _wapi_shm_sem_unlock (_WAPI_SHARED_SEM_SHARE);
+
+ _WAPI_HANDLE_COLLECTION_SAFE;
+
+ return(exists);
+}
+
+/* If we don't have the info in /proc, check if the process that
+ * opened this share info is still there (it's not a perfect method,
+ * due to pid reuse)
+ */
+static void _wapi_handle_check_share_by_pid (struct _WapiFileShare *share_info)
+{
+ if (kill (share_info->opened_by_pid, 0) == -1 &&
+ (errno == ESRCH ||
+ errno == EPERM)) {
+ /* It's gone completely (or there's a new process
+ * owned by someone else) so mark this share info as
+ * dead
+ */
+#ifdef DEBUG
+ g_message ("%s: Didn't find it, destroying entry", __func__);
+#endif
+
+ memset (share_info, '\0', sizeof(struct _WapiFileShare));
+ }
}
-gboolean _wapi_handle_process_fork (guint32 cmd, guint32 env, guint32 dir,
- gboolean inherit, guint32 flags,
- gpointer stdin_handle,
- gpointer stdout_handle,
- gpointer stderr_handle,
- gpointer *process_handle,
- gpointer *thread_handle, guint32 *pid,
- guint32 *tid)
+/* 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, int fd)
{
- WapiHandleRequest fork_proc={0};
- WapiHandleResponse fork_proc_resp={0};
- int in_fd, out_fd, err_fd;
+ gboolean found = FALSE, proc_fds = FALSE;
+ pid_t self = getpid();
+ int pid;
+ int thr_ret, i;
+
+ /* If there is no /proc, there's nothing more we can do here */
+ if (access ("/proc", F_OK) == -1) {
+ _wapi_handle_check_share_by_pid (share_info);
+ return;
+ }
- if(shared!=TRUE) {
- return(FALSE);
+ /* 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 */
+ thr_ret = _wapi_shm_sem_lock (_WAPI_SHARED_SEM_SHARE);
+ g_assert (thr_ret == 0);
+
+ for (i = 0; i < _WAPI_HANDLE_INITIAL_COUNT; i++) {
+ struct _WapiHandleShared *shared;
+ struct _WapiHandleSharedMetadata *meta;
+ struct _WapiHandle_process *process_handle;
+
+ meta = &_wapi_shared_layout->metadata[i];
+ shared = &_wapi_shared_layout->handles[meta->offset];
+
+ if (shared->type == WAPI_HANDLE_PROCESS) {
+ DIR *fd_dir;
+ struct dirent *fd_entry;
+ char subdir[_POSIX_PATH_MAX];
+
+ process_handle = &shared->u.process;
+ pid = process_handle->id;
+
+ /* Look in /proc/<pid>/fd/ but ignore
+ * /proc/<our pid>/fd/<fd>, as we have the
+ * file open too
+ */
+ g_snprintf (subdir, _POSIX_PATH_MAX, "/proc/%d/fd",
+ pid);
+
+ fd_dir = opendir (subdir);
+ if (fd_dir == NULL) {
+ continue;
+ }
+
+#ifdef DEBUG
+ g_message ("%s: Looking in %s", __func__, subdir);
+#endif
+
+ proc_fds = TRUE;
+
+ while ((fd_entry = readdir (fd_dir)) != NULL) {
+ char path[_POSIX_PATH_MAX];
+ struct stat link_stat;
+
+ if (!strcmp (fd_entry->d_name, ".") ||
+ !strcmp (fd_entry->d_name, "..") ||
+ (pid == self &&
+ fd == atoi (fd_entry->d_name))) {
+ continue;
+ }
+
+ 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);
+ }
}
- fork_proc.type=WapiHandleRequestType_ProcessFork;
- fork_proc.u.process_fork.cmd=cmd;
- fork_proc.u.process_fork.env=env;
- fork_proc.u.process_fork.dir=dir;
- fork_proc.u.process_fork.stdin_handle=GPOINTER_TO_UINT (stdin_handle);
- fork_proc.u.process_fork.stdout_handle=GPOINTER_TO_UINT (stdout_handle);
- fork_proc.u.process_fork.stderr_handle=GPOINTER_TO_UINT (stderr_handle);
- fork_proc.u.process_fork.inherit=inherit;
- fork_proc.u.process_fork.flags=flags;
-
- in_fd=_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);
-
- if(in_fd==-1 || out_fd==-1 || err_fd==-1) {
- /* We were given duff handles */
- /* FIXME: error code */
- return(FALSE);
+ if (proc_fds == FALSE) {
+ _wapi_handle_check_share_by_pid (share_info);
+ } else if (found == FALSE) {
+ /* Blank out this entry, as it is stale */
+#ifdef DEBUG
+ g_message ("%s: Didn't find it, destroying entry", __func__);
+#endif
+
+ memset (share_info, '\0', sizeof(struct _WapiFileShare));
+ }
+
+ thr_ret = _wapi_shm_sem_unlock (_WAPI_SHARED_SEM_SHARE);
+
+ _WAPI_HANDLE_COLLECTION_SAFE;
+}
+
+void _wapi_handle_dump (void)
+{
+ struct _WapiHandleUnshared *handle_data;
+ guint32 i, k;
+
+ for(i = SLOT_INDEX (0); _wapi_private_handles [i] != NULL; i++) {
+ for (k = SLOT_OFFSET (0); k < _WAPI_HANDLE_INITIAL_COUNT; k++) {
+ handle_data = &_wapi_private_handles [i][k];
+
+ if (handle_data->type == WAPI_HANDLE_UNUSED) {
+ continue;
+ }
+
+ g_print ("%3x [%7s] %s %d ",
+ i * _WAPI_HANDLE_INITIAL_COUNT + k,
+ _wapi_handle_typename[handle_data->type],
+ handle_data->signalled?"Sg":"Un",
+ handle_data->ref);
+ handle_details[handle_data->type](&handle_data->u);
+ g_print ("\n");
+ }
}
+}
+
+static void _wapi_shared_details (gpointer handle_info)
+{
+ struct _WapiHandle_shared_ref *shared = (struct _WapiHandle_shared_ref *)handle_info;
- _wapi_daemon_request_response_with_fds (daemon_sock, &fork_proc,
- &fork_proc_resp, in_fd,
- out_fd, err_fd);
- if(fork_proc_resp.type==WapiHandleResponseType_ProcessFork) {
- *process_handle=GUINT_TO_POINTER (fork_proc_resp.u.process_fork.process_handle);
- *thread_handle=GUINT_TO_POINTER (fork_proc_resp.u.process_fork.thread_handle);
- *pid=fork_proc_resp.u.process_fork.pid;
- *tid=fork_proc_resp.u.process_fork.tid;
-
- /* If there was an internal error, the handles will be
- * 0. If there was an error forking or execing, the
- * handles will have values, and process_handle's
- * exec_errno will be set, and the handle will be
- * signalled immediately.
- */
- if(process_handle==0 || thread_handle==0) {
- return(FALSE);
- } else {
- return(TRUE);
+ g_print ("offset: 0x%x", shared->offset);
+}
+
+void _wapi_handle_update_refs (void)
+{
+ guint32 i, k;
+ int thr_ret;
+
+ _WAPI_HANDLE_COLLECTION_UNSAFE;
+
+ /* Prevent file share entries racing with us */
+ thr_ret = _wapi_shm_sem_lock (_WAPI_SHARED_SEM_SHARE);
+ g_assert(thr_ret == 0);
+
+ for(i = SLOT_INDEX (0); _wapi_private_handles [i] != NULL; i++) {
+ for (k = SLOT_OFFSET (0); k < _WAPI_HANDLE_INITIAL_COUNT; k++) {
+ struct _WapiHandleUnshared *handle = &_wapi_private_handles [i][k];
+ guint32 now = (guint32)(time (NULL) & 0xFFFFFFFF);
+
+ if (_WAPI_SHARED_HANDLE(handle->type)) {
+ struct _WapiHandleSharedMetadata *shared_meta;
+
+#ifdef DEBUG
+ g_message ("%s: (%d) handle 0x%x is SHARED (%s)", __func__,
+ getpid (), i * _WAPI_HANDLE_INITIAL_COUNT + k, _wapi_handle_typename[handle->type]);
+#endif
+
+ shared_meta = &_wapi_shared_layout->metadata[handle->u.shared.offset];
+
+#ifdef DEBUG
+ g_message ("%s: (%d) Updating timestamp 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 * _WAPI_HANDLE_INITIAL_COUNT + k);
+#endif
+
+ g_assert (file_handle->share_info != NULL);
+
+#ifdef DEBUG
+ g_message ("%s: (%d) Inc refs on fileshare 0x%x",
+ __func__, getpid(),
+ (file_handle->share_info - &_wapi_fileshare_layout->share_info[0]) / sizeof(struct _WapiFileShare));
+#endif
+
+ InterlockedExchange (&file_handle->share_info->timestamp, now);
+ }
}
- } else {
- g_warning (G_GNUC_PRETTY_FUNCTION
- ": bogus daemon response, type %d",
- fork_proc_resp.type);
- g_assert_not_reached ();
}
- return(FALSE);
+ thr_ret = _wapi_shm_sem_unlock (_WAPI_SHARED_SEM_SHARE);
+
+ _WAPI_HANDLE_COLLECTION_SAFE;
}