#undef DEBUG
#undef DEBUG_REFS
+static void (*_wapi_handle_ops_get_close_func (WapiHandleType type))(gpointer, gpointer);
+
static WapiHandleCapability handle_caps[WAPI_HANDLE_COUNT]={0};
static struct _WapiHandleOps *handle_ops[WAPI_HANDLE_COUNT]={
NULL,
"Error!!"
};
-struct _WapiHandleUnshared *_wapi_private_handles = NULL;
+/*
+ * We can hold _WAPI_PRIVATE_MAX_SLOTS * _WAPI_HANDLE_INITIAL_COUNT handles.
+ * If 4M handles are not enough... Oh, well... we will crash.
+ */
+#define SLOT_INDEX(x) (x / _WAPI_HANDLE_INITIAL_COUNT)
+#define SLOT_OFFSET(x) (x % _WAPI_HANDLE_INITIAL_COUNT)
+
+struct _WapiHandleUnshared *_wapi_private_handles [_WAPI_PRIVATE_MAX_SLOTS];
static guint32 _wapi_private_handle_count = 0;
struct _WapiHandleSharedLayout *_wapi_shared_layout = NULL;
mono_mutex_t _wapi_global_signal_mutex;
pthread_cond_t _wapi_global_signal_cond;
+int _wapi_sem_id;
+
+static mono_mutex_t scan_mutex = MONO_MUTEX_INITIALIZER;
+
static mono_once_t shared_init_once = MONO_ONCE_INIT;
static void shared_init (void)
{
int thr_ret;
+ int idx = 0;
_wapi_fd_reserve = getdtablesize();
- _wapi_private_handle_count = _WAPI_HANDLE_INITIAL_COUNT;
-
- while(_wapi_fd_reserve > _wapi_private_handle_count) {
+ do {
+ _wapi_private_handles [idx++] = g_new0 (struct _WapiHandleUnshared,
+ _WAPI_HANDLE_INITIAL_COUNT);
+
_wapi_private_handle_count += _WAPI_HANDLE_INITIAL_COUNT;
- }
+ } while(_wapi_fd_reserve > _wapi_private_handle_count);
- _wapi_private_handles = g_new0 (struct _WapiHandleUnshared,
- _wapi_private_handle_count);
-
-
- _wapi_shared_layout = _wapi_shm_attach ();
+ _wapi_shared_layout = _wapi_shm_attach (WAPI_SHM_DATA);
g_assert (_wapi_shared_layout != NULL);
+
+ _wapi_shm_semaphores_init ();
- _wapi_fileshare_layout = _wapi_fileshare_shm_attach ();
+ _wapi_fileshare_layout = _wapi_shm_attach (WAPI_SHM_FILESHARE);
g_assert (_wapi_fileshare_layout != NULL);
_wapi_collection_init ();
again:
/* FIXME: expandable array */
- /* FIXME: leave a few slots at the end so that there's always
- * space to move a handle. (Leave the space in the offset
- * table too, so we don't have to keep track of inter-segment
+ /* leave a few slots at the end so that there's always space
+ * to move a handle. (We leave the space in the offset table
+ * too, so we don't have to keep track of inter-segment
* offsets.)
*/
- for(i = last; i <_WAPI_HANDLE_INITIAL_COUNT; i++) {
+ for(i = last; i <_WAPI_HANDLE_INITIAL_COUNT - _WAPI_HEADROOM; i++) {
struct _WapiHandleSharedMetadata *meta = &_wapi_shared_layout->metadata[i];
if(meta->offset == 0) {
/* Leave the first slot empty as a guard */
again:
/* FIXME: expandable array */
- /* FIXME: leave a few slots at the end so that there's always
- * space to move a handle
+ /* Leave a few slots at the end so that there's always space
+ * to move a handle
*/
- for(offset = last; offset <_WAPI_HANDLE_INITIAL_COUNT; offset++) {
+ for(offset = last; offset <_WAPI_HANDLE_INITIAL_COUNT - _WAPI_HEADROOM;
+ offset++) {
struct _WapiHandleShared *handle = &_wapi_shared_layout->handles[offset];
if(handle->type == WAPI_HANDLE_UNUSED) {
static guint32 _wapi_handle_new_internal (WapiHandleType type,
gpointer handle_specific)
{
- guint32 i;
+ guint32 i, k, count;
static guint32 last = 0;
+ gboolean retry = FALSE;
/* A linear scan should be fast enough. Start from the last
* allocation, assuming that handles are allocated more often
if (last < _wapi_fd_reserve) {
last = _wapi_fd_reserve;
+ } else {
+ retry = TRUE;
}
-
+
again:
- for(i = last; i <_wapi_private_handle_count; i++) {
- struct _WapiHandleUnshared *handle = &_wapi_private_handles[i];
-
- if(handle->type == WAPI_HANDLE_UNUSED) {
- last = i + 1;
+ count = last;
+ for(i = SLOT_INDEX (count); _wapi_private_handles [i] != NULL; i++) {
+ for (k = SLOT_OFFSET (count); k < _WAPI_HANDLE_INITIAL_COUNT; k++) {
+ struct _WapiHandleUnshared *handle = &_wapi_private_handles [i][k];
+
+ if(handle->type == WAPI_HANDLE_UNUSED) {
+ last = count + 1;
- _wapi_handle_init (handle, type, handle_specific);
- return(i);
+ _wapi_handle_init (handle, type, handle_specific);
+ return (count);
+ }
+ count++;
}
}
- if(last > _wapi_fd_reserve) {
+ if(retry && last > _wapi_fd_reserve) {
/* Try again from the beginning */
last = _wapi_fd_reserve;
goto again;
gpointer _wapi_handle_new (WapiHandleType type, gpointer handle_specific)
{
- static mono_mutex_t scan_mutex = MONO_MUTEX_INITIALIZER;
guint32 handle_idx = 0;
gpointer handle;
int thr_ret;
while ((handle_idx = _wapi_handle_new_internal (type, handle_specific)) == 0) {
/* Try and expand the array, and have another go */
- _wapi_private_handles = g_renew (struct _WapiHandleUnshared,
- _wapi_private_handles,
- _wapi_private_handle_count +
- _WAPI_HANDLE_INITIAL_COUNT);
- memset (_wapi_private_handles +
- (_wapi_private_handle_count *
- sizeof(struct _WapiHandleUnshared)), '\0',
- (_WAPI_HANDLE_INITIAL_COUNT *
- sizeof(struct _WapiHandleUnshared)));
-
+ int idx = SLOT_INDEX (_wapi_private_handle_count);
+ _wapi_private_handles [idx] = g_new0 (struct _WapiHandleUnshared,
+ _WAPI_HANDLE_INITIAL_COUNT);
+
_wapi_private_handle_count += _WAPI_HANDLE_INITIAL_COUNT;
}
_wapi_handle_collect ();
offset = _wapi_handle_new_shared (type,
handle_specific);
- /* FIXME: grow the arrays */
- g_assert (offset != 0);
+ if (offset == 0) {
+ /* FIXME: grow the arrays */
+ return (_WAPI_HANDLE_INVALID);
+ }
}
ref = _wapi_handle_new_shared_offset (offset);
if (ref == 0) {
_wapi_handle_collect ();
ref = _wapi_handle_new_shared_offset (offset);
- /* FIXME: grow the arrays */
- g_assert (ref != 0);
+
+ if (ref == 0) {
+ /* FIXME: grow the arrays */
+ return (_WAPI_HANDLE_INVALID);
+ }
}
- _wapi_private_handles[handle_idx].u.shared.offset = ref;
+ _WAPI_PRIVATE_HANDLES(handle_idx).u.shared.offset = ref;
#ifdef DEBUG
g_message ("%s: New shared handle at offset 0x%x", __func__,
ref);
return(handle);
}
-gpointer _wapi_handle_new_for_existing_ns (WapiHandleType type,
- gpointer handle_specific,
- guint32 offset)
+gpointer _wapi_handle_new_from_offset (WapiHandleType type, guint32 offset)
{
- static mono_mutex_t scan_mutex = MONO_MUTEX_INITIALIZER;
guint32 handle_idx = 0;
gpointer handle;
- int thr_ret;
+ int thr_ret, i, k;
mono_once (&shared_init_once, shared_init);
#ifdef DEBUG
- g_message ("%s: Creating new handle of type %s", __func__,
- _wapi_handle_typename[type]);
+ g_message ("%s: Creating new handle of type %s to offset %d", __func__,
+ _wapi_handle_typename[type], offset);
#endif
g_assert(!_WAPI_FD_HANDLE(type));
g_assert(_WAPI_SHARED_HANDLE(type));
g_assert(offset != 0);
-
+
+ for (i = SLOT_INDEX (0); _wapi_private_handles [i] != NULL; i++) {
+ for (k = SLOT_OFFSET (0); k < _WAPI_HANDLE_INITIAL_COUNT; k++) {
+ struct _WapiHandleUnshared *handle_data = &_wapi_private_handles [i][k];
+
+ if (handle_data->type == type &&
+ handle_data->u.shared.offset == offset) {
+ handle = GUINT_TO_POINTER (i * _WAPI_HANDLE_INITIAL_COUNT + k);
+ _wapi_handle_ref (handle);
+
+#ifdef DEBUG
+ g_message ("%s: Returning old handle %p referencing 0x%x", __func__, handle, offset);
+#endif
+ return (handle);
+ }
+ }
+ }
+
pthread_cleanup_push ((void(*)(void *))mono_mutex_unlock_in_cleanup,
(void *)&scan_mutex);
thr_ret = mono_mutex_lock (&scan_mutex);
g_assert (thr_ret == 0);
-
- while ((handle_idx = _wapi_handle_new_internal (type, handle_specific)) == 0) {
+
+ while ((handle_idx = _wapi_handle_new_internal (type, NULL)) == 0) {
/* Try and expand the array, and have another go */
- _wapi_private_handles = g_renew (struct _WapiHandleUnshared,
- _wapi_private_handles,
- _wapi_private_handle_count +
- _WAPI_HANDLE_INITIAL_COUNT);
- memset (_wapi_private_handles +
- (_wapi_private_handle_count *
- sizeof(struct _WapiHandleUnshared)), '\0',
- (_WAPI_HANDLE_INITIAL_COUNT *
- sizeof(struct _WapiHandleUnshared)));
-
+ int idx = SLOT_INDEX (_wapi_private_handle_count);
+ _wapi_private_handles [idx] = g_new0 (struct _WapiHandleUnshared,
+ _WAPI_HANDLE_INITIAL_COUNT);
+
_wapi_private_handle_count += _WAPI_HANDLE_INITIAL_COUNT;
}
handle = GUINT_TO_POINTER (handle_idx);
- _wapi_private_handles[handle_idx].u.shared.offset = offset;
+ _WAPI_PRIVATE_HANDLES(handle_idx).u.shared.offset = offset;
#ifdef DEBUG
g_message ("%s: Allocated new handle %p referencing 0x%x", __func__,
return(GUINT_TO_POINTER (_WAPI_HANDLE_INVALID));
}
- handle = &_wapi_private_handles[fd];
+ handle = &_WAPI_PRIVATE_HANDLES(fd);
if (handle->type != WAPI_HANDLE_UNUSED) {
#ifdef DEBUG
struct _WapiHandleUnshared *handle_data;
guint32 handle_idx = GPOINTER_TO_UINT(handle);
- handle_data = &_wapi_private_handles[handle_idx];
+ handle_data = &_WAPI_PRIVATE_HANDLES(handle_idx);
- if(handle_data->type != type) {
+ if (handle_data->type != type) {
return(FALSE);
}
- if(handle_specific == NULL) {
+ if (handle_specific == NULL) {
return(FALSE);
}
if (_WAPI_SHARED_HANDLE(type)) {
- struct _WapiHandle_shared_ref *ref = &handle_data->u.shared;
+ struct _WapiHandle_shared_ref *ref;
struct _WapiHandleShared *shared_handle_data;
struct _WapiHandleSharedMetadata *shared_meta;
-
- shared_meta = &_wapi_shared_layout->metadata[ref->offset];
- shared_handle_data = &_wapi_shared_layout->handles[shared_meta->offset];
+ guint32 offset;
+
+ /* Unsafe, because we don't want the handle to vanish
+ * while we're checking it
+ */
+ _WAPI_HANDLE_COLLECTION_UNSAFE;
- g_assert(shared_handle_data->type == type);
+ do {
+ ref = &handle_data->u.shared;
+ shared_meta = &_wapi_shared_layout->metadata[ref->offset];
+ offset = shared_meta->offset;
+ shared_handle_data = &_wapi_shared_layout->handles[offset];
- *handle_specific = &shared_handle_data->u;
+ g_assert(shared_handle_data->type == type);
+
+ *handle_specific = &shared_handle_data->u;
+ } while (offset != shared_meta->offset);
+
+ _WAPI_HANDLE_COLLECTION_SAFE;
} else {
*handle_specific = &handle_data->u;
}
_wapi_handle_typename[type]);
#endif
- handle_data = &_wapi_private_handles[handle_idx];
+ handle_data = &_WAPI_PRIVATE_HANDLES(handle_idx);
if(handle_data->type != type) {
#ifdef DEBUG
return(FALSE);
}
- _WAPI_HANDLE_COLLECTION_UNSAFE;
-
do {
ref = &handle_data->u.shared;
shared_meta = &_wapi_shared_layout->metadata[ref->offset];
sizeof(struct _WapiHandleShared));
} while (offset != shared_meta->offset);
- _WAPI_HANDLE_COLLECTION_SAFE;
-
#ifdef DEBUG
g_message ("%s: OK", __func__);
#endif
return(TRUE);
}
-void _wapi_replace_handle (gpointer handle, WapiHandleType type,
- struct _WapiHandleShared *handle_specific)
+gboolean _wapi_replace_handle (gpointer handle, WapiHandleType type,
+ struct _WapiHandleShared *handle_specific)
{
struct _WapiHandleShared *shared_handle_data;
struct _WapiHandleSharedMetadata *shared_meta;
#endif
g_assert(_WAPI_SHARED_HANDLE(type));
- g_assert(_wapi_private_handles[handle_idx].type == type);
+ g_assert(_WAPI_PRIVATE_HANDLES(handle_idx).type == type);
- ref = _wapi_private_handles[handle_idx].u.shared.offset;
+ ref = _WAPI_PRIVATE_HANDLES(handle_idx).u.shared.offset;
shared_meta = &_wapi_shared_layout->metadata[ref];
do {
_wapi_handle_collect ();
new_off = _wapi_handle_new_shared (type,
handle_specific);
- /* FIXME: grow the arrays */
- g_assert (new_off != 0);
+
+ if (new_off == 0) {
+ /* FIXME: grow the arrays */
+ return (FALSE);
+ }
}
shared_handle_data = &_wapi_shared_layout->handles[new_off];
g_message ("%s: handle at 0x%x is now found at 0x%x", __func__, ref,
new_off);
#endif
+
+ return (TRUE);
}
-gboolean _wapi_try_replace_handle (gpointer handle, WapiHandleType type,
- struct _WapiHandleShared *handle_specific)
+void
+_wapi_handle_foreach (WapiHandleType type,
+ gboolean (*on_each)(gpointer test, gpointer user),
+ gpointer user_data)
{
- struct _WapiHandleShared *shared_handle_data;
- struct _WapiHandleSharedMetadata *shared_meta;
- guint32 handle_idx = GPOINTER_TO_UINT(handle);
- guint32 old_off, new_off, ref;
- gboolean ret;
-
-#ifdef DEBUG
- g_message ("%s: Trying to replace handle %p of type %s", __func__,
- handle, _wapi_handle_typename[type]);
-#endif
-
- g_assert(_WAPI_SHARED_HANDLE(type));
- g_assert(_wapi_private_handles[handle_idx].type == type);
-
- ref = _wapi_private_handles[handle_idx].u.shared.offset;
- shared_meta = &_wapi_shared_layout->metadata[ref];
-
- old_off = shared_meta->offset;
- new_off = _wapi_handle_new_shared (type, handle_specific);
-
- if (new_off == 0) {
- _wapi_handle_collect ();
- new_off = _wapi_handle_new_shared (type, handle_specific);
-
- /* FIXME: grow the arrays */
- g_assert (new_off != 0);
- }
-
- shared_handle_data = &_wapi_shared_layout->handles[new_off];
-
-#ifdef DEBUG
- g_message ("%s: Old offset: 0x%x, trying to move to 0x%x", __func__,
- old_off, new_off);
-#endif
-
- memcpy (shared_handle_data, handle_specific,
- sizeof(struct _WapiHandleShared));
-
- ret = (InterlockedCompareExchange (&shared_meta->offset, new_off,
- old_off) == old_off);
+ struct _WapiHandleUnshared *handle_data = NULL;
+ gpointer ret = NULL;
+ guint32 i, k;
+ int thr_ret;
- if (ret) {
- /* An entry can't become fresh again (its going to be
- * collected eventually), so no need for atomic ops
- * here.
- */
- _wapi_shared_layout->handles[old_off].stale = TRUE;
- }
+ pthread_cleanup_push ((void(*)(void *))mono_mutex_unlock_in_cleanup,
+ (void *)&scan_mutex);
+ thr_ret = mono_mutex_lock (&scan_mutex);
+ g_assert (thr_ret == 0);
-#ifdef DEBUG
- if (ret) {
- g_message ("%s: handle at 0x%x is now found at 0x%x", __func__,
- ref, new_off);
- } else {
- g_message ("%s: handle at 0x%x already updated", __func__,
- ref);
+ for (i = SLOT_INDEX (0); _wapi_private_handles [i] != NULL; i++) {
+ for (k = SLOT_OFFSET (0); k < _WAPI_HANDLE_INITIAL_COUNT; k++) {
+ handle_data = &_wapi_private_handles [i][k];
+
+ if (handle_data->type == type) {
+ ret = GUINT_TO_POINTER (i * _WAPI_HANDLE_INITIAL_COUNT + k);
+ if (on_each (ret, user_data) == TRUE)
+ break;
+ }
+ }
}
-#endif
- return(ret);
+ thr_ret = mono_mutex_unlock (&scan_mutex);
+ g_assert (thr_ret == 0);
+ pthread_cleanup_pop (0);
}
-/* This will only find shared handles that have already been opened by
- * this process. To look up shared handles by name, use
- * _wapi_search_handle_namespace
+/* This might list some shared handles twice if they are already
+ * opened by this process, and the check function returns FALSE the
+ * first time. Shared handles that are created during the search are
+ * unreffed if the check function returns FALSE, so callers must not
+ * rely on the handle persisting (unless the check function returns
+ * TRUE)
*/
gpointer _wapi_search_handle (WapiHandleType type,
gboolean (*check)(gpointer test, gpointer user),
gpointer *handle_specific)
{
struct _WapiHandleUnshared *handle_data = NULL;
- guint32 i;
+ gpointer ret = NULL;
+ guint32 i, k;
+ gboolean found = FALSE;
+
- for(i = 0; i < _wapi_private_handle_count; i++) {
- handle_data = &_wapi_private_handles[i];
+ for (i = SLOT_INDEX (0); !found && _wapi_private_handles [i] != NULL; i++) {
+ for (k = SLOT_OFFSET (0); k < _WAPI_HANDLE_INITIAL_COUNT; k++) {
+ handle_data = &_wapi_private_handles [i][k];
- if(handle_data->type == type) {
- if(check (GUINT_TO_POINTER (i), user_data) == TRUE) {
- break;
+ if (handle_data->type == type) {
+ ret = GUINT_TO_POINTER (i * _WAPI_HANDLE_INITIAL_COUNT + k);
+ if (check (ret, user_data) == TRUE) {
+ found = TRUE;
+ break;
+ }
}
}
}
- if(i == _wapi_private_handle_count) {
- return(GUINT_TO_POINTER (0));
+ if (!found) {
+ /* Not found yet, so search the shared memory too */
+#ifdef DEBUG
+ g_message ("%s: Looking at other shared handles...", __func__);
+#endif
+
+ for (i = 0; i < _WAPI_HANDLE_INITIAL_COUNT; i++) {
+ struct _WapiHandleShared *shared;
+ struct _WapiHandleSharedMetadata *meta;
+ WapiHandleType shared_type;
+
+ _WAPI_HANDLE_COLLECTION_UNSAFE;
+
+ meta = &_wapi_shared_layout->metadata[i];
+ shared = &_wapi_shared_layout->handles[meta->offset];
+ shared_type = shared->type;
+
+ _WAPI_HANDLE_COLLECTION_SAFE;
+
+ if (shared_type == type) {
+ ret = _wapi_handle_new_from_offset (type, i);
+
+#ifdef DEBUG
+ g_message ("%s: Opened tmp handle %p (type %s) from offset %d", __func__, ret, _wapi_handle_typename[type], meta->offset);
+#endif
+
+ if (check (ret, user_data) == TRUE) {
+ found = TRUE;
+ handle_data = &_WAPI_PRIVATE_HANDLES(GPOINTER_TO_UINT(ret));
+
+ break;
+ }
+
+ /* This isn't the handle we're looking
+ * for, so drop the reference we took
+ * in _wapi_handle_new_from_offset ()
+ */
+ _wapi_handle_unref (ret);
+ }
+ }
+ }
+
+ if (!found) {
+ goto done;
}
if(handle_specific != NULL) {
if (_WAPI_SHARED_HANDLE(type)) {
- struct _WapiHandle_shared_ref *ref = &handle_data->u.shared;
+ struct _WapiHandle_shared_ref *ref ;
struct _WapiHandleShared *shared_handle_data;
struct _WapiHandleSharedMetadata *shared_meta;
+ guint32 offset, now;
- shared_meta = &_wapi_shared_layout->metadata[ref->offset];
- shared_handle_data = &_wapi_shared_layout->handles[shared_meta->offset];
+ /* Unsafe, because we don't want the handle to
+ * vanish while we're checking it
+ */
+ _WAPI_HANDLE_COLLECTION_UNSAFE;
+
+ do {
+ ref = &handle_data->u.shared;
+ shared_meta = &_wapi_shared_layout->metadata[ref->offset];
+ offset = shared_meta->offset;
+ shared_handle_data = &_wapi_shared_layout->handles[offset];
- g_assert(shared_handle_data->type == type);
+ g_assert(shared_handle_data->type == type);
- *handle_specific = &shared_handle_data->u;
+ *handle_specific = &shared_handle_data->u;
+ } while (offset != shared_meta->offset);
+
+ /* Make sure this handle doesn't vanish in the
+ * next collection
+ */
+ now = (guint32)(time (NULL) & 0xFFFFFFFF);
+ InterlockedExchange (&shared_meta->timestamp, now);
+
+ _WAPI_HANDLE_COLLECTION_SAFE;
} else {
*handle_specific = &handle_data->u;
}
}
-
- return(GUINT_TO_POINTER (i));
-}
-
-/* This signature makes it easier to use in pthread cleanup handlers */
-int _wapi_namespace_timestamp_release (gpointer nowptr)
-{
- guint32 now = GPOINTER_TO_UINT(nowptr);
-
- return (_wapi_timestamp_release (&_wapi_shared_layout->namespace_check,
- now));
-}
-int _wapi_namespace_timestamp (guint32 now)
-{
- int ret;
-
- do {
- ret = _wapi_timestamp_exclusion (&_wapi_shared_layout->namespace_check, now);
- /* sleep for a bit */
- _wapi_handle_spin (100);
- } while (ret == EBUSY);
-
+done:
return(ret);
}
gint32 ret = 0;
g_assert(_WAPI_SHARED_HANDLE(type));
- g_assert(_wapi_shared_layout->namespace_check != 0);
#ifdef DEBUG
g_message ("%s: Lookup for handle named [%s] type %s", __func__,
void _wapi_handle_ref (gpointer handle)
{
guint32 idx = GPOINTER_TO_UINT(handle);
+ guint32 now = (guint32)(time (NULL) & 0xFFFFFFFF);
+ struct _WapiHandleUnshared *handle_data = &_WAPI_PRIVATE_HANDLES(idx);
- InterlockedIncrement (&_wapi_private_handles[idx].ref);
- /* Do shared part */
+ InterlockedIncrement (&handle_data->ref);
+
+ /* It's possible for processes to exit before getting around
+ * to updating timestamps in the collection thread, so if a
+ * shared handle is reffed do the timestamp here as well just
+ * to make sure.
+ */
+ if (_WAPI_SHARED_HANDLE(handle_data->type)) {
+ struct _WapiHandleSharedMetadata *shared_meta = &_wapi_shared_layout->metadata[handle_data->u.shared.offset];
+
+ InterlockedExchange (&shared_meta->timestamp, now);
+ }
#ifdef DEBUG_REFS
g_message ("%s: handle %p ref now %d", __func__, handle,
- _wapi_private_handles[idx].ref);
+ _WAPI_PRIVATE_HANDLES(idx).ref);
#endif
}
* could lock a mutex, but I'm not sure that allowing a handle
* reference to reach 0 isn't an application bug anyway.
*/
- destroy = (InterlockedDecrement (&_wapi_private_handles[idx].ref) ==0);
+ destroy = (InterlockedDecrement (&_WAPI_PRIVATE_HANDLES(idx).ref) ==0);
#ifdef DEBUG_REFS
g_message ("%s: handle %p ref now %d (destroy %s)", __func__, handle,
- _wapi_private_handles[idx].ref, destroy?"TRUE":"FALSE");
+ _WAPI_PRIVATE_HANDLES(idx).ref, destroy?"TRUE":"FALSE");
#endif
if(destroy==TRUE) {
+ /* Need to copy the handle info, reset the slot in the
+ * array, and _only then_ call the close function to
+ * avoid race conditions (eg file descriptors being
+ * closed, and another file being opened getting the
+ * same fd racing the memset())
+ */
+ struct _WapiHandleUnshared handle_data;
+ WapiHandleType type = _WAPI_PRIVATE_HANDLES(idx).type;
+ void (*close_func)(gpointer, gpointer) = _wapi_handle_ops_get_close_func (type);
+
#ifdef DEBUG
g_message ("%s: Destroying handle %p", __func__, handle);
#endif
- _wapi_handle_ops_close (handle);
+ memcpy (&handle_data, &_WAPI_PRIVATE_HANDLES(idx),
+ sizeof (struct _WapiHandleUnshared));
- memset (&_wapi_private_handles[idx].u, '\0',
- sizeof(_wapi_private_handles[idx].u));
+ memset (&_WAPI_PRIVATE_HANDLES(idx).u, '\0',
+ sizeof(_WAPI_PRIVATE_HANDLES(idx).u));
- _wapi_private_handles[idx].type = WAPI_HANDLE_UNUSED;
+ _WAPI_PRIVATE_HANDLES(idx).type = WAPI_HANDLE_UNUSED;
- /* Destroy the mutex and cond var. We hope nobody
- * tried to grab them between the handle unlock and
- * now, but pthreads doesn't have a
- * "unlock_and_destroy" atomic function.
- */
- thr_ret = mono_mutex_destroy (&_wapi_private_handles[idx].signal_mutex);
- g_assert (thr_ret == 0);
-
- thr_ret = pthread_cond_destroy (&_wapi_private_handles[idx].signal_cond);
- g_assert (thr_ret == 0);
+ if (!_WAPI_SHARED_HANDLE(type)) {
+ /* Destroy the mutex and cond var. We hope nobody
+ * tried to grab them between the handle unlock and
+ * now, but pthreads doesn't have a
+ * "unlock_and_destroy" atomic function.
+ */
+ thr_ret = mono_mutex_destroy (&_WAPI_PRIVATE_HANDLES(idx).signal_mutex);
+ g_assert (thr_ret == 0);
+
+ thr_ret = pthread_cond_destroy (&_WAPI_PRIVATE_HANDLES(idx).signal_cond);
+ g_assert (thr_ret == 0);
+ }
/* The garbage collector will take care of shared data
* if this is a shared handle
*/
+
+ if (close_func != NULL) {
+ close_func (handle, &handle_data.u);
+ }
}
}
void _wapi_handle_register_capabilities (WapiHandleType type,
WapiHandleCapability caps)
{
- handle_caps[type]=caps;
+ handle_caps[type] = caps;
}
gboolean _wapi_handle_test_capabilities (gpointer handle,
guint32 idx = GPOINTER_TO_UINT(handle);
WapiHandleType type;
- type = _wapi_private_handles[idx].type;
+ type = _WAPI_PRIVATE_HANDLES(idx).type;
#ifdef DEBUG
g_message ("%s: testing 0x%x against 0x%x (%d)", __func__,
return((handle_caps[type] & caps) != 0);
}
-void _wapi_handle_ops_close (gpointer handle)
+static void (*_wapi_handle_ops_get_close_func (WapiHandleType type))(gpointer, gpointer)
+{
+ if (handle_ops[type] != NULL &&
+ handle_ops[type]->close != NULL) {
+ return (handle_ops[type]->close);
+ }
+
+ return (NULL);
+}
+
+void _wapi_handle_ops_close (gpointer handle, gpointer data)
{
guint32 idx = GPOINTER_TO_UINT(handle);
WapiHandleType type;
- type = _wapi_private_handles[idx].type;
+ type = _WAPI_PRIVATE_HANDLES(idx).type;
if (handle_ops[type] != NULL &&
handle_ops[type]->close != NULL) {
- handle_ops[type]->close (handle);
+ handle_ops[type]->close (handle, data);
}
}
guint32 idx = GPOINTER_TO_UINT(handle);
WapiHandleType type;
- type = _wapi_private_handles[idx].type;
+ type = _WAPI_PRIVATE_HANDLES(idx).type;
if (handle_ops[type] != NULL && handle_ops[type]->signal != NULL) {
handle_ops[type]->signal (handle);
guint32 idx = GPOINTER_TO_UINT(handle);
WapiHandleType type;
- type = _wapi_private_handles[idx].type;
+ type = _WAPI_PRIVATE_HANDLES(idx).type;
if (handle_ops[type] != NULL && handle_ops[type]->own_handle != NULL) {
return(handle_ops[type]->own_handle (handle));
guint32 idx = GPOINTER_TO_UINT(handle);
WapiHandleType type;
- type = _wapi_private_handles[idx].type;
+ type = _WAPI_PRIVATE_HANDLES(idx).type;
if (handle_ops[type] != NULL && handle_ops[type]->is_owned != NULL) {
return(handle_ops[type]->is_owned (handle));
}
}
+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
*/
gboolean CloseHandle(gpointer handle)
{
- if (handle == NULL) {
- return(FALSE);
- }
-
_wapi_handle_unref (handle);
return(TRUE);
/* Lock all the handles, with backoff */
again:
+ thr_ret = _wapi_handle_lock_shared_handles ();
+ g_assert (thr_ret == 0);
+
for(i=0; i<numhandles; i++) {
gpointer handle = handles[i];
guint32 idx = GPOINTER_TO_UINT(handle);
- guint32 now = (guint32)(time(NULL) & 0xFFFFFFFF);
#ifdef DEBUG
g_message ("%s: attempting to lock %p", __func__, handle);
#endif
- type = _wapi_private_handles[idx].type;
+ type = _WAPI_PRIVATE_HANDLES(idx).type;
- if (_WAPI_SHARED_HANDLE(type)) {
- /* We don't lock shared handles, but we need
- * to be able to simultaneously check the
- * signal state of all handles in the array
- *
- * We do this by atomically putting the
- * least-significant 32 bits of time(2) into
- * the 'checking' field if it is zero. If it
- * isn't zero, then it means that either
- * another thread is looking at this handle
- * right now, or someone crashed here. Assume
- * that if the time value is more than 10
- * seconds old, its a crash and override it.
- * 10 seconds should be enough for anyone...
- *
- * If the time value is within 10 seconds,
- * back off and try again as per the
- * non-shared case.
- */
- thr_ret = _wapi_timestamp_exclusion (&WAPI_SHARED_HANDLE_METADATA(handle).checking, now);
- } else {
- thr_ret = _wapi_handle_trylock_handle (handle);
- }
+ thr_ret = _wapi_handle_trylock_handle (handle);
if (thr_ret != 0) {
/* Bummer */
handle, strerror (thr_ret));
#endif
+ thr_ret = _wapi_handle_unlock_shared_handles ();
+ g_assert (thr_ret == 0);
+
while (i--) {
handle = handles[i];
idx = GPOINTER_TO_UINT(handle);
- if (_WAPI_SHARED_HANDLE(type)) {
- /* Reset the checking field */
- thr_ret = _wapi_timestamp_release (&WAPI_SHARED_HANDLE_METADATA(handle).checking, now);
- } else{
- thr_ret = _wapi_handle_unlock_handle (handle);
- }
+ thr_ret = _wapi_handle_unlock_handle (handle);
g_assert (thr_ret == 0);
}
gpointer handle = handles[i];
guint32 idx = GPOINTER_TO_UINT(handle);
- type = _wapi_private_handles[idx].type;
+ type = _WAPI_PRIVATE_HANDLES(idx).type;
_wapi_handle_ref (handle);
(_WAPI_SHARED_HANDLE(type) &&
WAPI_SHARED_HANDLE_METADATA(handle).signalled == TRUE) ||
(!_WAPI_SHARED_HANDLE(type) &&
- _wapi_private_handles[idx].signalled == TRUE)) {
+ _WAPI_PRIVATE_HANDLES(idx).signalled == TRUE)) {
count++;
#ifdef DEBUG
guint32 i;
int thr_ret;
+ thr_ret = _wapi_handle_unlock_shared_handles ();
+ g_assert (thr_ret == 0);
+
for(i=0; i<numhandles; i++) {
gpointer handle = handles[i];
- guint32 idx = GPOINTER_TO_UINT(handle);
- WapiHandleType type = _wapi_private_handles[idx].type;
#ifdef DEBUG
g_message ("%s: unlocking handle %p", __func__, handle);
#endif
- if (_WAPI_SHARED_HANDLE(type)) {
- WAPI_SHARED_HANDLE_METADATA(handle).checking = 0;
- } else {
- thr_ret = mono_mutex_unlock (&_wapi_private_handles[idx].signal_mutex);
- g_assert (thr_ret == 0);
- }
+ thr_ret = _wapi_handle_unlock_handle (handle);
+ g_assert (thr_ret == 0);
+ }
+}
+
+static int timedwait_signal_poll_cond (pthread_cond_t *cond, mono_mutex_t *mutex, struct timespec *timeout)
+{
+ struct timespec fake_timeout;
+ int ret;
+
+ _wapi_calc_timeout (&fake_timeout, 100);
+
+ if (timeout != NULL && ((fake_timeout.tv_sec > timeout->tv_sec) ||
+ (fake_timeout.tv_sec == timeout->tv_sec &&
+ fake_timeout.tv_nsec > timeout->tv_nsec))) {
+ /* Real timeout is less than 100ms time */
+ ret=mono_cond_timedwait (cond, mutex, timeout);
+ } else {
+ ret=mono_cond_timedwait (cond, mutex, &fake_timeout);
- _wapi_handle_unref (handle);
+ /* Mask the fake timeout, this will cause
+ * another poll if the cond was not really signaled
+ */
+ if (ret==ETIMEDOUT) {
+ ret=0;
+ }
}
+
+ return(ret);
}
int _wapi_handle_wait_signal (void)
{
- return(mono_cond_wait (&_wapi_global_signal_cond,
- &_wapi_global_signal_mutex));
+ return timedwait_signal_poll_cond (&_wapi_global_signal_cond, &_wapi_global_signal_mutex, NULL);
}
int _wapi_handle_timedwait_signal (struct timespec *timeout)
{
- return(mono_cond_timedwait (&_wapi_global_signal_cond,
- &_wapi_global_signal_mutex,
- timeout));
+ return timedwait_signal_poll_cond (&_wapi_global_signal_cond, &_wapi_global_signal_mutex, timeout);
}
int _wapi_handle_wait_signal_poll_share (void)
{
- struct timespec fake_timeout;
- guint32 signal_count = _wapi_shared_layout->signal_count;
- int ret;
-
#ifdef DEBUG
g_message ("%s: poll private and shared handles", __func__);
#endif
-
- while(1) {
- _wapi_calc_timeout (&fake_timeout, 100);
- ret = mono_cond_timedwait (&_wapi_global_signal_cond,
- &_wapi_global_signal_mutex,
- &fake_timeout);
-
- /* Check the shared signal counter */
- if (ret == ETIMEDOUT) {
- if (signal_count != _wapi_shared_layout->signal_count) {
-#ifdef DEBUG
- g_message ("%s: A shared handle was signalled",
- __func__);
-#endif
-
- return (0);
- }
- } else {
- /* This will be 0 indicating a private handle
- * was signalled, or an error
- */
-#ifdef DEBUG
- g_message ("%s: returning: %d", __func__, ret);
-#endif
-
- return (ret);
- }
-
- /* If timeout and no shared handle was signalled, go
- * round again
- */
- }
+ return timedwait_signal_poll_cond (&_wapi_global_signal_cond, &_wapi_global_signal_mutex, NULL);
}
int _wapi_handle_timedwait_signal_poll_share (struct timespec *timeout)
{
- struct timespec fake_timeout;
- guint32 signal_count = _wapi_shared_layout->signal_count;
- int ret;
-
#ifdef DEBUG
g_message ("%s: poll private and shared handles", __func__);
#endif
- do {
- _wapi_calc_timeout (&fake_timeout, 100);
-
- if ((fake_timeout.tv_sec > timeout->tv_sec) ||
- (fake_timeout.tv_sec == timeout->tv_sec &&
- fake_timeout.tv_nsec > timeout->tv_nsec)) {
- /* Real timeout is less than 100ms time */
-
-#ifdef DEBUG
- g_message ("%s: last few ms", __func__);
-#endif
-
- ret = mono_cond_timedwait (&_wapi_global_signal_cond,
- &_wapi_global_signal_mutex,
- timeout);
- } else {
- ret = mono_cond_timedwait (&_wapi_global_signal_cond,
- &_wapi_global_signal_mutex,
- &fake_timeout);
-
- /* Mask the fake timeout, this will cause
- * another poll if the shared counter hasn't
- * changed
- */
- if (ret == ETIMEDOUT) {
- ret = 0;
- }
- }
-
- if (ret != ETIMEDOUT) {
- /* Either a private handle was signalled, or
- * an error
- */
-#ifdef DEBUG
- g_message ("%s: returning: %d", __func__, ret);
-#endif
- return (ret);
- }
-
- /* Check the shared signal counter */
- if (signal_count != _wapi_shared_layout->signal_count) {
-#ifdef DEBUG
- g_message ("%s: A shared handle was signalled",
- __func__);
-#endif
- return (0);
- }
- } while (ret != ETIMEDOUT);
-
-#ifdef DEBUG
- g_message ("%s: returning ETIMEDOUT", __func__);
-#endif
-
- return (ret);
+ return timedwait_signal_poll_cond (&_wapi_global_signal_cond, &_wapi_global_signal_mutex, timeout);
}
int _wapi_handle_wait_signal_handle (gpointer handle)
{
- guint32 idx = GPOINTER_TO_UINT(handle);
-
#ifdef DEBUG
g_message ("%s: waiting for %p", __func__, handle);
#endif
- if (_WAPI_SHARED_HANDLE (_wapi_handle_type (handle))) {
- while(1) {
- if (WAPI_SHARED_HANDLE_METADATA(handle).signalled == TRUE) {
- return (0);
- }
-
- _wapi_handle_spin (100);
- }
- } else {
- return(mono_cond_wait (&_wapi_private_handles[idx].signal_cond,
- &_wapi_private_handles[idx].signal_mutex));
- }
+ return _wapi_handle_timedwait_signal_handle (handle, NULL);
}
int _wapi_handle_timedwait_signal_handle (gpointer handle,
struct timespec *timeout)
{
- guint32 idx = GPOINTER_TO_UINT(handle);
-
#ifdef DEBUG
g_message ("%s: waiting for %p (type %s)", __func__, handle,
_wapi_handle_typename[_wapi_handle_type (handle)]);
#endif
if (_WAPI_SHARED_HANDLE (_wapi_handle_type (handle))) {
- struct timespec fake_timeout;
-
- while (1) {
- if (WAPI_SHARED_HANDLE_METADATA(handle).signalled == TRUE) {
- return (0);
- }
-
+ if (WAPI_SHARED_HANDLE_METADATA(handle).signalled == TRUE) {
+ return (0);
+ }
+ if (timeout != NULL) {
+ struct timespec fake_timeout;
_wapi_calc_timeout (&fake_timeout, 100);
if ((fake_timeout.tv_sec > timeout->tv_sec) ||
- (fake_timeout.tv_sec == timeout->tv_sec &&
- fake_timeout.tv_nsec > timeout->tv_nsec)) {
+ (fake_timeout.tv_sec == timeout->tv_sec &&
+ fake_timeout.tv_nsec > timeout->tv_nsec)) {
/* FIXME: Real timeout is less than
* 100ms time, but is it really worth
* calculating to the exact ms?
*/
_wapi_handle_spin (100);
-
+
if (WAPI_SHARED_HANDLE_METADATA(handle).signalled == TRUE) {
return (0);
} else {
return (ETIMEDOUT);
}
- } else {
- _wapi_handle_spin (100);
- }
- }
- } else {
- return(mono_cond_timedwait (&_wapi_private_handles[idx].signal_cond, &_wapi_private_handles[idx].signal_mutex, timeout));
- }
-}
-
-gboolean _wapi_handle_process_fork (guint32 cmd, guint32 env, guint32 dir,
- gboolean inherit, guint32 flags,
- gpointer stdin_handle,
- gpointer stdout_handle,
- gpointer stderr_handle,
- gpointer *process_handle,
- gpointer *thread_handle, guint32 *pid,
- guint32 *tid)
-{
-#if 0
- WapiHandleRequest fork_proc={0};
- WapiHandleResponse fork_proc_resp={0};
- int in_fd, out_fd, err_fd;
-
- if(shared!=TRUE) {
- return(FALSE);
- }
-
- fork_proc.type=WapiHandleRequestType_ProcessFork;
- fork_proc.u.process_fork.cmd=cmd;
- fork_proc.u.process_fork.env=env;
- fork_proc.u.process_fork.dir=dir;
- fork_proc.u.process_fork.stdin_handle=GPOINTER_TO_UINT (stdin_handle);
- fork_proc.u.process_fork.stdout_handle=GPOINTER_TO_UINT (stdout_handle);
- fork_proc.u.process_fork.stderr_handle=GPOINTER_TO_UINT (stderr_handle);
- fork_proc.u.process_fork.inherit=inherit;
- fork_proc.u.process_fork.flags=flags;
-
- in_fd = GPOINTER_TO_UINT (stdin_handle);
- out_fd = GPOINTER_TO_UINT (stdout_handle);
- err_fd = GPOINTER_TO_UINT (stderr_handle);
-
- if(in_fd==-1 || out_fd==-1 || err_fd==-1) {
- /* We were given duff handles */
- /* FIXME: error code */
- return(FALSE);
- }
-
- _wapi_daemon_request_response_with_fds (daemon_sock, &fork_proc,
- &fork_proc_resp, in_fd,
- out_fd, err_fd);
- if(fork_proc_resp.type==WapiHandleResponseType_ProcessFork) {
- *process_handle=GUINT_TO_POINTER (fork_proc_resp.u.process_fork.process_handle);
- *thread_handle=GUINT_TO_POINTER (fork_proc_resp.u.process_fork.thread_handle);
- *pid=fork_proc_resp.u.process_fork.pid;
- *tid=fork_proc_resp.u.process_fork.tid;
-
- /* If there was an internal error, the handles will be
- * 0. If there was an error forking or execing, the
- * handles will have values, and process_handle's
- * exec_errno will be set, and the handle will be
- * signalled immediately.
- */
- if(*process_handle==0 || *thread_handle==0) {
- return(FALSE);
- } else {
- /* This call returns new handles, so we need to do
- * a little bookkeeping
- */
- if (_wapi_private_data != NULL) {
- guint32 segment, idx;
-
- _wapi_handle_segment (*process_handle,
- &segment, &idx);
- _wapi_handle_ensure_mapped (segment);
- _wapi_handle_get_private_segment (segment)->handles[idx].type = WAPI_HANDLE_PROCESS;
-
- _wapi_handle_segment (*thread_handle,
- &segment, &idx);
- _wapi_handle_ensure_mapped (segment);
- _wapi_handle_get_private_segment (segment)->handles[idx].type = WAPI_HANDLE_THREAD;
}
-
- return(TRUE);
}
+ _wapi_handle_spin (100);
+ return (0);
+
} else {
- g_warning ("%s: bogus daemon response, type %d", __func__,
- fork_proc_resp.type);
- g_assert_not_reached ();
- }
-
- return(FALSE);
-#else
- return(FALSE);
-#endif
-}
-
-gboolean
-_wapi_handle_process_kill (pid_t process, guint32 signo, gint *errnum)
-{
-#if 0
- WapiHandleRequest killproc = {0};
- WapiHandleResponse killprocresp = {0};
- gint result;
-
- if (shared != TRUE) {
- if (errnum) *errnum = EINVAL;
- return FALSE;
- }
-
- killproc.type = WapiHandleRequestType_ProcessKill;
- killproc.u.process_kill.pid = process;
- killproc.u.process_kill.signo = signo;
-
- _wapi_daemon_request_response (daemon_sock, &killproc, &killprocresp);
-
- if (killprocresp.type != WapiHandleResponseType_ProcessKill) {
- g_warning ("%s: bogus daemon response, type %d", __func__,
- killprocresp.type);
- g_assert_not_reached ();
+ guint32 idx = GPOINTER_TO_UINT(handle);
+ return timedwait_signal_poll_cond (&_WAPI_PRIVATE_HANDLES(idx).signal_cond, &_WAPI_PRIVATE_HANDLES(idx).signal_mutex, timeout);
}
-
- result = killprocresp.u.process_kill.err;
- if (result != 0 && errnum != NULL)
- *errnum = (result == FALSE) ? result : 0;
-
- return (result == 0);
-#else
- return(FALSE);
-#endif
}
gboolean _wapi_handle_get_or_set_share (dev_t device, ino_t inode,
_WAPI_HANDLE_COLLECTION_UNSAFE;
/* Prevent new entries racing with us */
- thr_ret = _wapi_timestamp_exclusion (&_wapi_fileshare_layout->share_check, now);
+ thr_ret = _wapi_shm_sem_lock (_WAPI_SHARED_SEM_SHARE);
g_assert (thr_ret == 0);
/* If a linear scan gets too slow we'll have to fit a hash
file_share->device = device;
file_share->inode = inode;
+ file_share->opened_by_pid = getpid ();
file_share->sharemode = new_sharemode;
file_share->access = new_access;
file_share->handle_refs = 1;
*share_info = file_share;
}
}
+
+ if (*share_info != NULL) {
+ InterlockedExchange (&(*share_info)->timestamp, now);
+ }
- thr_ret = _wapi_timestamp_release (&_wapi_fileshare_layout->share_check, now);
- g_assert (thr_ret == 0);
+ thr_ret = _wapi_shm_sem_unlock (_WAPI_SHARED_SEM_SHARE);
_WAPI_HANDLE_COLLECTION_SAFE;
return(exists);
}
+/* If we don't have the info in /proc, check if the process that
+ * opened this share info is still there (it's not a perfect method,
+ * due to pid reuse)
+ */
+static void _wapi_handle_check_share_by_pid (struct _WapiFileShare *share_info)
+{
+ if (kill (share_info->opened_by_pid, 0) == -1 &&
+ (errno == ESRCH ||
+ errno == EPERM)) {
+ /* It's gone completely (or there's a new process
+ * owned by someone else) so mark this share info as
+ * dead
+ */
+#ifdef DEBUG
+ g_message ("%s: Didn't find it, destroying entry", __func__);
+#endif
+
+ memset (share_info, '\0', sizeof(struct _WapiFileShare));
+ }
+}
+
/* Scan /proc/<pids>/fd/ for open file descriptors to the file in
* question. If there are none, reset the share info.
*
* implement their own ways of finding out if a particular file is
* open by a process.
*/
-void _wapi_handle_check_share (struct _WapiFileShare *share_info)
+void _wapi_handle_check_share (struct _WapiFileShare *share_info, int fd)
{
- DIR *proc_dir;
- struct dirent *proc_entry;
- gboolean found = FALSE;
+ gboolean found = FALSE, proc_fds = FALSE;
pid_t self = getpid();
int pid;
- guint32 now = (guint32)(time(NULL) & 0xFFFFFFFF);
- int thr_ret;
+ int thr_ret, i;
- proc_dir = opendir ("/proc");
- if (proc_dir == NULL) {
+ /* If there is no /proc, there's nothing more we can do here */
+ if (access ("/proc", F_OK) == -1) {
+ _wapi_handle_check_share_by_pid (share_info);
return;
}
_WAPI_HANDLE_COLLECTION_UNSAFE;
/* Prevent new entries racing with us */
- thr_ret = _wapi_timestamp_exclusion (&_wapi_fileshare_layout->share_check, now);
+ thr_ret = _wapi_shm_sem_lock (_WAPI_SHARED_SEM_SHARE);
g_assert (thr_ret == 0);
- while ((proc_entry = readdir (proc_dir)) != NULL) {
- /* We only care about numerically-named directories */
- pid = atoi (proc_entry->d_name);
- if (pid != 0 && pid != self) {
- /* Look in /proc/<pid>/fd/ but ignore
- * ourselves, as we have the file open too
- */
+ for (i = 0; i < _WAPI_HANDLE_INITIAL_COUNT; i++) {
+ struct _WapiHandleShared *shared;
+ struct _WapiHandleSharedMetadata *meta;
+ struct _WapiHandle_process *process_handle;
+
+ meta = &_wapi_shared_layout->metadata[i];
+ shared = &_wapi_shared_layout->handles[meta->offset];
+
+ if (shared->type == WAPI_HANDLE_PROCESS) {
DIR *fd_dir;
struct dirent *fd_entry;
char subdir[_POSIX_PATH_MAX];
-
+
+ process_handle = &shared->u.process;
+ pid = process_handle->id;
+
+ /* Look in /proc/<pid>/fd/ but ignore
+ * /proc/<our pid>/fd/<fd>, as we have the
+ * file open too
+ */
g_snprintf (subdir, _POSIX_PATH_MAX, "/proc/%d/fd",
pid);
if (fd_dir == NULL) {
continue;
}
+
+#ifdef DEBUG
+ g_message ("%s: Looking in %s", __func__, subdir);
+#endif
+
+ proc_fds = TRUE;
while ((fd_entry = readdir (fd_dir)) != NULL) {
char path[_POSIX_PATH_MAX];
struct stat link_stat;
if (!strcmp (fd_entry->d_name, ".") ||
- !strcmp (fd_entry->d_name, "..")) {
+ !strcmp (fd_entry->d_name, "..") ||
+ (pid == self &&
+ fd == atoi (fd_entry->d_name))) {
continue;
}
closedir (fd_dir);
}
}
-
- closedir (proc_dir);
- if (found == FALSE) {
+ if (proc_fds == FALSE) {
+ _wapi_handle_check_share_by_pid (share_info);
+ } else if (found == FALSE) {
/* Blank out this entry, as it is stale */
#ifdef DEBUG
g_message ("%s: Didn't find it, destroying entry", __func__);
memset (share_info, '\0', sizeof(struct _WapiFileShare));
}
- thr_ret = _wapi_timestamp_release (&_wapi_fileshare_layout->share_check, now);
- g_assert (thr_ret == 0);
+ thr_ret = _wapi_shm_sem_unlock (_WAPI_SHARED_SEM_SHARE);
_WAPI_HANDLE_COLLECTION_SAFE;
}
void _wapi_handle_dump (void)
{
struct _WapiHandleUnshared *handle_data;
- guint32 i;
+ guint32 i, k;
- for (i = 0; i < _wapi_private_handle_count; i++) {
- handle_data = &_wapi_private_handles[i];
+ for(i = SLOT_INDEX (0); _wapi_private_handles [i] != NULL; i++) {
+ for (k = SLOT_OFFSET (0); k < _WAPI_HANDLE_INITIAL_COUNT; k++) {
+ handle_data = &_wapi_private_handles [i][k];
- if (handle_data->type == WAPI_HANDLE_UNUSED) {
- continue;
- }
+ if (handle_data->type == WAPI_HANDLE_UNUSED) {
+ continue;
+ }
- g_print ("%3x [%7s] %s %d ", i,
- _wapi_handle_typename[handle_data->type],
- handle_data->signalled?"Sg":"Un", handle_data->ref);
- handle_details[handle_data->type](&handle_data->u);
- g_print ("\n");
+ g_print ("%3x [%7s] %s %d ",
+ i * _WAPI_HANDLE_INITIAL_COUNT + k,
+ _wapi_handle_typename[handle_data->type],
+ handle_data->signalled?"Sg":"Un",
+ handle_data->ref);
+ handle_details[handle_data->type](&handle_data->u);
+ g_print ("\n");
+ }
}
}
void _wapi_handle_update_refs (void)
{
- guint32 i;
+ guint32 i, k;
+ int thr_ret;
- for (i = 0; i < _wapi_private_handle_count; i++) {
- struct _WapiHandleUnshared *handle = &_wapi_private_handles[i];
- guint32 now = (guint32)(time (NULL) & 0xFFFFFFFF);
+ _WAPI_HANDLE_COLLECTION_UNSAFE;
- if (_WAPI_SHARED_HANDLE(handle->type)) {
- struct _WapiHandleSharedMetadata *shared_meta;
-
- shared_meta = &_wapi_shared_layout->metadata[handle->u.shared.offset];
+ /* Prevent file share entries racing with us */
+ thr_ret = _wapi_shm_sem_lock (_WAPI_SHARED_SEM_SHARE);
+ g_assert(thr_ret == 0);
+
+ for(i = SLOT_INDEX (0); _wapi_private_handles [i] != NULL; i++) {
+ for (k = SLOT_OFFSET (0); k < _WAPI_HANDLE_INITIAL_COUNT; k++) {
+ struct _WapiHandleUnshared *handle = &_wapi_private_handles [i][k];
+ guint32 now = (guint32)(time (NULL) & 0xFFFFFFFF);
+ if (_WAPI_SHARED_HANDLE(handle->type)) {
+ struct _WapiHandleSharedMetadata *shared_meta;
+
#ifdef DEBUG
- g_message ("%s: (%d) Updating timstamp of handle 0x%x",
- __func__, getpid(),
- handle->u.shared.offset);
+ g_message ("%s: (%d) handle 0x%x is SHARED (%s)", __func__,
+ getpid (), i * _WAPI_HANDLE_INITIAL_COUNT + k, _wapi_handle_typename[handle->type]);
#endif
- InterlockedExchange (&shared_meta->timestamp, now);
- } else if (handle->type == WAPI_HANDLE_FILE) {
- struct _WapiHandle_file *file_handle = &handle->u.file;
-
- g_assert (file_handle->share_info != NULL);
+ shared_meta = &_wapi_shared_layout->metadata[handle->u.shared.offset];
#ifdef DEBUG
- g_message ("%s: (%d) Inc refs on fileshare 0x%x",
- __func__, getpid(),
- (file_handle->share_info - &_wapi_fileshare_layout->share_info[0]) / sizeof(struct _WapiFileShare));
+ g_message ("%s: (%d) Updating timestamp of handle 0x%x",
+ __func__, getpid(),
+ handle->u.shared.offset);
#endif
- InterlockedExchange (&file_handle->share_info->timestamp, now);
+ InterlockedExchange (&shared_meta->timestamp, now);
+ } else if (handle->type == WAPI_HANDLE_FILE) {
+ struct _WapiHandle_file *file_handle = &handle->u.file;
+
+#ifdef DEBUG
+ g_message ("%s: (%d) handle 0x%x is FILE", __func__,
+ getpid (), i * _WAPI_HANDLE_INITIAL_COUNT + k);
+#endif
+
+ g_assert (file_handle->share_info != NULL);
+
+#ifdef DEBUG
+ g_message ("%s: (%d) Inc refs on fileshare 0x%x",
+ __func__, getpid(),
+ (file_handle->share_info - &_wapi_fileshare_layout->share_info[0]) / sizeof(struct _WapiFileShare));
+#endif
+
+ InterlockedExchange (&file_handle->share_info->timestamp, now);
+ }
}
}
+
+ thr_ret = _wapi_shm_sem_unlock (_WAPI_SHARED_SEM_SHARE);
+
+ _WAPI_HANDLE_COLLECTION_SAFE;
}