* Author:
* Dick Porter (dick@ximian.com)
*
- * (C) 2002-2006 Novell, Inc.
+ * (C) 2002-2011 Novell, Inc.
+ * Copyright 2011 Xamarin Inc
*/
#include <config.h>
#include <pthread.h>
#include <errno.h>
#include <unistd.h>
+#include <signal.h>
#include <string.h>
#include <sys/types.h>
#ifdef HAVE_SYS_SOCKET_H
#endif
#include <sys/stat.h>
-#include <mono/os/gc_wrapper.h>
-
#include <mono/io-layer/wapi.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/misc-private.h>
#include <mono/io-layer/shared.h>
#include <mono/io-layer/collection.h>
#include <mono/io-layer/process-private.h>
#include <mono/io-layer/critical-section-private.h>
-#undef DEBUG
+#include <mono/utils/mono-mutex.h>
#undef DEBUG_REFS
+#if 0
+#define DEBUG(...) g_message(__VA_ARGS__)
+#else
+#define DEBUG(...)
+#endif
+
static void (*_wapi_handle_ops_get_close_func (WapiHandleType type))(gpointer, gpointer);
static WapiHandleCapability handle_caps[WAPI_HANDLE_COUNT]={0};
&_wapi_sem_ops,
&_wapi_mutex_ops,
&_wapi_event_ops,
+#ifndef DISABLE_SOCKETS
&_wapi_socket_ops,
+#endif
&_wapi_find_ops,
&_wapi_process_ops,
&_wapi_pipe_ops,
static guint32 _wapi_private_handle_slot_count = 0;
struct _WapiHandleSharedLayout *_wapi_shared_layout = NULL;
+
+/*
+ * If SHM is enabled, this will point to shared memory, otherwise it will be NULL.
+ */
struct _WapiFileShareLayout *_wapi_fileshare_layout = NULL;
+/*
+ * If SHM is disabled, this will point to a hash of _WapiFileShare structures, otherwise
+ * it will be NULL. We use this instead of _wapi_fileshare_layout to avoid allocating a
+ * 4MB array.
+ */
+static GHashTable *file_share_hash;
+static CRITICAL_SECTION file_share_hash_mutex;
+
+#define file_share_hash_lock() EnterCriticalSection (&file_share_hash_mutex)
+#define file_share_hash_unlock() LeaveCriticalSection (&file_share_hash_mutex)
+
guint32 _wapi_fd_reserve;
/*
static pid_t _wapi_pid;
static mono_once_t pid_init_once = MONO_ONCE_INIT;
-static gpointer _wapi_handle_real_new (WapiHandleType type, gpointer handle_specific);
+static void _wapi_handle_unref_full (gpointer handle, gboolean ignore_private_busy_handles);
static void pid_init (void)
{
}
-static mono_mutex_t scan_mutex = MONO_MUTEX_INITIALIZER;
+static mono_mutex_t scan_mutex;
static void handle_cleanup (void)
{
int i, j, k;
- _wapi_process_signal_self ();
-
/* Every shared handle we were using ought really to be closed
* by now, but to make sure just blow them all away. The
* exiting finalizer thread in particular races us to the
for(i = SLOT_INDEX (0); _wapi_private_handles[i] != NULL; i++) {
for(j = SLOT_OFFSET (0); j < _WAPI_HANDLE_INITIAL_COUNT; j++) {
struct _WapiHandleUnshared *handle_data = &_wapi_private_handles[i][j];
- int type = handle_data->type;
-
-
- if (_WAPI_SHARED_HANDLE (type)) {
- gpointer handle = GINT_TO_POINTER (i*_WAPI_HANDLE_INITIAL_COUNT+j);
-
- if (type == WAPI_HANDLE_THREAD) {
- /* Special-case thread handles
- * because they need extra
- * cleanup. This also avoids
- * a race condition between
- * the application exit and
- * the finalizer thread - if
- * it finishes up between now
- * and actual app termination
- * it will find all its handle
- * details have been blown
- * away, so this sets those
- * anyway.
- */
- _wapi_thread_set_termination_details (handle, 0);
- }
-
- for(k = handle_data->ref; k > 0; k--) {
-#ifdef DEBUG
- g_message ("%s: unreffing %s handle %p", __func__, _wapi_handle_typename[type], handle);
-#endif
+ gpointer handle = GINT_TO_POINTER (i*_WAPI_HANDLE_INITIAL_COUNT+j);
+
+ for(k = handle_data->ref; k > 0; k--) {
+ DEBUG ("%s: unreffing %s handle %p", __func__, _wapi_handle_typename[type], handle);
- _wapi_handle_unref (handle);
- }
+ _wapi_handle_unref_full (handle, TRUE);
}
}
}
_wapi_shm_semaphores_remove ();
-}
-void _wapi_cleanup ()
-{
- g_assert (_wapi_has_shut_down == FALSE);
-
- _wapi_has_shut_down = TRUE;
+ _wapi_shm_detach (WAPI_SHM_DATA);
+ _wapi_shm_detach (WAPI_SHM_FILESHARE);
- _wapi_critical_section_cleanup ();
- _wapi_error_cleanup ();
- _wapi_thread_cleanup ();
+ if (file_share_hash) {
+ g_hash_table_destroy (file_share_hash);
+ DeleteCriticalSection (&file_share_hash_mutex);
+ }
+
+ for (i = 0; i < _WAPI_PRIVATE_MAX_SLOTS; ++i)
+ g_free (_wapi_private_handles [i]);
}
-static mono_once_t shared_init_once = MONO_ONCE_INIT;
-static void shared_init (void)
+/*
+ * wapi_init:
+ *
+ * Initialize the io-layer.
+ */
+void
+wapi_init (void)
{
g_assert ((sizeof (handle_ops) / sizeof (handle_ops[0]))
== WAPI_HANDLE_COUNT);
_wapi_shared_layout = _wapi_shm_attach (WAPI_SHM_DATA);
g_assert (_wapi_shared_layout != NULL);
- _wapi_fileshare_layout = _wapi_shm_attach (WAPI_SHM_FILESHARE);
- g_assert (_wapi_fileshare_layout != NULL);
+ if (_wapi_shm_enabled ()) {
+ /* This allocates a 4mb array, so do it only if SHM is enabled */
+ _wapi_fileshare_layout = _wapi_shm_attach (WAPI_SHM_FILESHARE);
+ g_assert (_wapi_fileshare_layout != NULL);
+ }
- _wapi_collection_init ();
+#if !defined (DISABLE_SHARED_HANDLES)
+ if (_wapi_shm_enabled ())
+ _wapi_collection_init ();
+#endif
+ _wapi_io_init ();
+ mono_mutex_init (&scan_mutex);
- /* Can't call wapi_handle_new as it calls us recursively */
- _wapi_global_signal_handle = _wapi_handle_real_new (WAPI_HANDLE_EVENT, NULL);
+ _wapi_global_signal_handle = _wapi_handle_new (WAPI_HANDLE_EVENT, NULL);
_wapi_global_signal_cond = &_WAPI_PRIVATE_HANDLES (GPOINTER_TO_UINT (_wapi_global_signal_handle)).signal_cond;
_wapi_global_signal_mutex = &_WAPI_PRIVATE_HANDLES (GPOINTER_TO_UINT (_wapi_global_signal_handle)).signal_mutex;
+
/* Using g_atexit here instead of an explicit function call in
* a cleanup routine lets us cope when a third-party library
* calls exit (eg if an X client loses the connection to its
g_atexit (handle_cleanup);
}
+void
+wapi_cleanup (void)
+{
+ g_assert (_wapi_has_shut_down == FALSE);
+
+ _wapi_has_shut_down = TRUE;
+
+ _wapi_error_cleanup ();
+ _wapi_thread_cleanup ();
+}
+
static void _wapi_handle_init_shared (struct _WapiHandleShared *handle,
WapiHandleType type,
gpointer handle_specific)
thr_ret = pthread_cond_init (&handle->signal_cond, NULL);
g_assert (thr_ret == 0);
- thr_ret = mono_mutex_init (&handle->signal_mutex, NULL);
+ thr_ret = mono_mutex_init (&handle->signal_mutex);
g_assert (thr_ret == 0);
if (handle_specific != NULL) {
return(0);
}
-static gpointer _wapi_handle_real_new (WapiHandleType type, gpointer handle_specific)
+gpointer
+_wapi_handle_new (WapiHandleType type, gpointer handle_specific)
{
guint32 handle_idx = 0;
gpointer handle;
int thr_ret;
-
-#ifdef DEBUG
- g_message ("%s: Creating new handle of type %s", __func__,
+
+ g_assert (_wapi_has_shut_down == FALSE);
+
+ DEBUG ("%s: Creating new handle of type %s", __func__,
_wapi_handle_typename[type]);
-#endif
g_assert(!_WAPI_FD_HANDLE(type));
handle = GUINT_TO_POINTER (handle_idx);
-#ifdef DEBUG
- g_message ("%s: Allocated new handle %p", __func__, handle);
-#endif
+ DEBUG ("%s: Allocated new handle %p", __func__, handle);
if (_WAPI_SHARED_HANDLE(type)) {
/* Add the shared section too */
}
_WAPI_PRIVATE_HANDLES(handle_idx).u.shared.offset = ref;
-#ifdef DEBUG
- g_message ("%s: New shared handle at offset 0x%x", __func__,
+ DEBUG ("%s: New shared handle at offset 0x%x", __func__,
ref);
-#endif
}
done:
return(handle);
}
-gpointer _wapi_handle_new (WapiHandleType type, gpointer handle_specific)
-{
- g_assert (_wapi_has_shut_down == FALSE);
-
- mono_once (&shared_init_once, shared_init);
-
- return _wapi_handle_real_new (type, handle_specific);
-}
-
gpointer _wapi_handle_new_from_offset (WapiHandleType type, guint32 offset,
gboolean timestamp)
{
gpointer handle = INVALID_HANDLE_VALUE;
int thr_ret, i, k;
struct _WapiHandleShared *shared;
- guint32 now = (guint32)(time (NULL) & 0xFFFFFFFF);
g_assert (_wapi_has_shut_down == FALSE);
- mono_once (&shared_init_once, shared_init);
-
-#ifdef DEBUG
- g_message ("%s: Creating new handle of type %s to offset %d", __func__,
+ DEBUG ("%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));
shared = &_wapi_shared_layout->handles[offset];
if (timestamp) {
+ guint32 now = (guint32)(time (NULL) & 0xFFFFFFFF);
/* Bump up the timestamp for this offset */
InterlockedExchange ((gint32 *)&shared->timestamp, now);
}
if (handle != INVALID_HANDLE_VALUE) {
_wapi_handle_ref (handle);
-#ifdef DEBUG
- g_message ("%s: Returning old handle %p referencing 0x%x",
+ DEBUG ("%s: Returning old handle %p referencing 0x%x",
__func__, handle, offset);
-#endif
return (handle);
}
if (shared->type == WAPI_HANDLE_UNUSED) {
/* Someone deleted this handle while we were working */
-#ifdef DEBUG
- g_message ("%s: Handle at 0x%x unused", __func__, offset);
-#endif
+ DEBUG ("%s: Handle at 0x%x unused", __func__, offset);
goto done;
}
if (shared->type != type) {
-#ifdef DEBUG
- g_message ("%s: Wrong type at %d 0x%x! Found %s wanted %s",
+ DEBUG ("%s: Wrong type at %d 0x%x! Found %s wanted %s",
__func__, offset, offset,
_wapi_handle_typename[shared->type],
_wapi_handle_typename[type]);
-#endif
goto done;
}
_WAPI_PRIVATE_HANDLES(handle_idx).u.shared.offset = offset;
InterlockedIncrement ((gint32 *)&shared->handle_refs);
-#ifdef DEBUG
- g_message ("%s: Allocated new handle %p referencing 0x%x (shared refs %d)", __func__, handle, offset, shared->handle_refs);
-#endif
+ DEBUG ("%s: Allocated new handle %p referencing 0x%x (shared refs %d)", __func__, handle, offset, shared->handle_refs);
done:
_wapi_handle_unlock_shared_handles ();
g_assert (_wapi_has_shut_down == FALSE);
- mono_once (&shared_init_once, shared_init);
-
-#ifdef DEBUG
- g_message ("%s: Creating new handle of type %s", __func__,
+ DEBUG ("%s: Creating new handle of type %s", __func__,
_wapi_handle_typename[type]);
-#endif
g_assert(_WAPI_FD_HANDLE(type));
g_assert(!_WAPI_SHARED_HANDLE(type));
if (fd >= _wapi_fd_reserve) {
-#ifdef DEBUG
- g_message ("%s: fd %d is too big", __func__, fd);
-#endif
+ DEBUG ("%s: fd %d is too big", __func__, fd);
return(GUINT_TO_POINTER (_WAPI_HANDLE_INVALID));
}
handle = &_WAPI_PRIVATE_HANDLES(fd);
if (handle->type != WAPI_HANDLE_UNUSED) {
-#ifdef DEBUG
- g_message ("%s: fd %d is already in use!", __func__, fd);
-#endif
+ DEBUG ("%s: fd %d is already in use!", __func__, fd);
/* FIXME: clean up this handle? We can't do anything
* with the fd, cos thats the new one
*/
}
-#ifdef DEBUG
- g_message ("%s: Assigning new fd handle %d", __func__, fd);
-#endif
+ DEBUG ("%s: Assigning new fd handle %d", __func__, fd);
/* Prevent file share entries racing with us, when the file
* handle is only half initialised
* unreffed if the check function returns FALSE, so callers must not
* rely on the handle persisting (unless the check function returns
* TRUE)
+ * The caller owns the returned handle.
*/
gpointer _wapi_search_handle (WapiHandleType type,
gboolean (*check)(gpointer test, gpointer user),
if (!found && search_shared && _WAPI_SHARED_HANDLE (type)) {
/* Not found yet, so search the shared memory too */
-#ifdef DEBUG
- g_message ("%s: Looking at other shared handles...", __func__);
-#endif
+ DEBUG ("%s: Looking at other shared handles...", __func__);
for (i = 0; i < _WAPI_HANDLE_INITIAL_COUNT; i++) {
shared = &_wapi_shared_layout->handles[i];
continue;
}
-#ifdef DEBUG
- g_message ("%s: Opened tmp handle %p (type %s) from offset %d", __func__, ret, _wapi_handle_typename[type], i);
-#endif
+ DEBUG ("%s: Opened tmp handle %p (type %s) from offset %d", __func__, ret, _wapi_handle_typename[type], i);
/* It's possible that the shared part
* of this handle has now been blown
g_assert(_WAPI_SHARED_HANDLE(type));
-#ifdef DEBUG
- g_message ("%s: Lookup for handle named [%s] type %s", __func__,
+ DEBUG ("%s: Lookup for handle named [%s] type %s", __func__,
utf8_name, _wapi_handle_typename[type]);
-#endif
/* Do a handle collection before starting to look, so that any
* stale cruft gets removed
continue;
}
-#ifdef DEBUG
- g_message ("%s: found a shared namespace handle at 0x%x (type %s)", __func__, i, _wapi_handle_typename[shared_handle_data->type]);
-#endif
+ DEBUG ("%s: found a shared namespace handle at 0x%x (type %s)", __func__, i, _wapi_handle_typename[shared_handle_data->type]);
sharedns=(WapiSharedNamespace *)&shared_handle_data->u;
-#ifdef DEBUG
- g_message ("%s: name is [%s]", __func__, sharedns->name);
-#endif
+ DEBUG ("%s: name is [%s]", __func__, sharedns->name);
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
+ DEBUG ("%s: handle 0x%x matches name but is wrong type: %s", __func__, i, _wapi_handle_typename[shared_handle_data->type]);
ret = -1;
goto done;
} else {
-#ifdef DEBUG
- g_message ("%s: handle 0x%x matches name and type", __func__, i);
-#endif
+ DEBUG ("%s: handle 0x%x matches name and type", __func__, i);
ret = i;
goto done;
}
void _wapi_handle_ref (gpointer handle)
{
guint32 idx = GPOINTER_TO_UINT(handle);
- guint32 now = (guint32)(time (NULL) & 0xFFFFFFFF);
struct _WapiHandleUnshared *handle_data;
if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
*/
if (_WAPI_SHARED_HANDLE(handle_data->type)) {
struct _WapiHandleShared *shared_data = &_wapi_shared_layout->handles[handle_data->u.shared.offset];
-
+ guint32 now = (guint32)(time (NULL) & 0xFFFFFFFF);
InterlockedExchange ((gint32 *)&shared_data->timestamp, now);
}
}
/* The handle must not be locked on entry to this function */
-void _wapi_handle_unref (gpointer handle)
+static void _wapi_handle_unref_full (gpointer handle, gboolean ignore_private_busy_handles)
{
guint32 idx = GPOINTER_TO_UINT(handle);
- gboolean destroy = FALSE;
+ gboolean destroy = FALSE, early_exit = FALSE;
int thr_ret;
if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
pthread_cleanup_push ((void(*)(void *))mono_mutex_unlock_in_cleanup, (void *)&scan_mutex);
thr_ret = mono_mutex_lock (&scan_mutex);
-#ifdef DEBUG
- g_message ("%s: Destroying handle %p", __func__, handle);
-#endif
+ DEBUG ("%s: Destroying handle %p", __func__, handle);
memcpy (&handle_data, &_WAPI_PRIVATE_HANDLES(idx),
sizeof (struct _WapiHandleUnshared));
* "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);
+ /*WARNING gross hack to make cleanup not crash when exiting without the whole runtime teardown.*/
+ if (thr_ret == EBUSY && ignore_private_busy_handles) {
+ early_exit = TRUE;
+ } else {
+ if (thr_ret != 0)
+ g_error ("Error destroying handle %p mutex due to %d\n", handle, thr_ret);
+
+ thr_ret = pthread_cond_destroy (&_WAPI_PRIVATE_HANDLES(idx).signal_cond);
+ if (thr_ret == EBUSY && ignore_private_busy_handles)
+ early_exit = TRUE;
+ else if (thr_ret != 0)
+ g_error ("Error destroying handle %p cond var due to %d\n", handle, thr_ret);
+ }
} else {
struct _WapiHandleShared *shared = &_wapi_shared_layout->handles[handle_data.u.shared.offset];
g_assert (thr_ret == 0);
pthread_cleanup_pop (0);
+ if (early_exit)
+ return;
if (is_shared) {
_wapi_handle_unlock_shared_handles ();
}
}
}
+void _wapi_handle_unref (gpointer handle)
+{
+ _wapi_handle_unref_full (handle, FALSE);
+}
+
void _wapi_handle_register_capabilities (WapiHandleType type,
WapiHandleCapability caps)
{
type = _WAPI_PRIVATE_HANDLES(idx).type;
-#ifdef DEBUG
- g_message ("%s: testing 0x%x against 0x%x (%d)", __func__,
+ DEBUG ("%s: testing 0x%x against 0x%x (%d)", __func__,
handle_caps[type], caps, handle_caps[type] & caps);
-#endif
return((handle_caps[type] & caps) != 0);
}
}
}
-guint32 _wapi_handle_ops_special_wait (gpointer handle, guint32 timeout)
+guint32 _wapi_handle_ops_special_wait (gpointer handle, guint32 timeout, gboolean alertable)
{
guint32 idx = GPOINTER_TO_UINT(handle);
WapiHandleType type;
if (handle_ops[type] != NULL &&
handle_ops[type]->special_wait != NULL) {
- return(handle_ops[type]->special_wait (handle, timeout));
+ return(handle_ops[type]->special_wait (handle, timeout, alertable));
} else {
return(WAIT_FAILED);
}
gpointer handle = handles[i];
guint32 idx = GPOINTER_TO_UINT(handle);
-#ifdef DEBUG
- g_message ("%s: attempting to lock %p", __func__, handle);
-#endif
+ DEBUG ("%s: attempting to lock %p", __func__, handle);
type = _WAPI_PRIVATE_HANDLES(idx).type;
if (thr_ret != 0) {
/* Bummer */
-#ifdef DEBUG
- g_message ("%s: attempt failed for %p: %s", __func__,
+ DEBUG ("%s: attempt failed for %p: %s", __func__,
handle, strerror (thr_ret));
-#endif
thr_ret = _wapi_handle_unlock_shared_handles ();
g_assert (thr_ret == 0);
iter=1;
}
-#ifdef DEBUG
- g_message ("%s: Backing off for %d ms", __func__,
+ DEBUG ("%s: Backing off for %d ms", __func__,
iter*10);
-#endif
_wapi_handle_spin (10 * iter);
goto again;
}
}
-#ifdef DEBUG
- g_message ("%s: Locked all handles", __func__);
-#endif
+ DEBUG ("%s: Locked all handles", __func__);
count=0;
*lowest=numhandles;
type = _WAPI_PRIVATE_HANDLES(idx).type;
-#ifdef DEBUG
- g_message ("%s: Checking handle %p", __func__, handle);
-#endif
+ DEBUG ("%s: Checking handle %p", __func__, handle);
if(((_wapi_handle_test_capabilities (handle, WAPI_HANDLE_CAP_OWN)==TRUE) &&
(_wapi_handle_ops_isowned (handle) == TRUE)) ||
_WAPI_PRIVATE_HANDLES(idx).signalled == TRUE)) {
count++;
-#ifdef DEBUG
- g_message ("%s: Handle %p signalled", __func__,
+ DEBUG ("%s: Handle %p signalled", __func__,
handle);
-#endif
if(*lowest>i) {
*lowest=i;
}
}
}
-#ifdef DEBUG
- g_message ("%s: %d event handles signalled", __func__, count);
-#endif
+ DEBUG ("%s: %d event handles signalled", __func__, count);
if ((waitall == TRUE && count == numhandles) ||
(waitall == FALSE && count > 0)) {
ret=FALSE;
}
-#ifdef DEBUG
- g_message ("%s: Returning %d", __func__, ret);
-#endif
+ DEBUG ("%s: Returning %d", __func__, ret);
*retcount=count;
for(i=0; i<numhandles; i++) {
gpointer handle = handles[i];
-#ifdef DEBUG
- g_message ("%s: unlocking handle %p", __func__, handle);
-#endif
+ DEBUG ("%s: unlocking handle %p", __func__, handle);
thr_ret = _wapi_handle_unlock_handle (handle);
g_assert (thr_ret == 0);
int _wapi_handle_wait_signal_handle (gpointer handle, gboolean alertable)
{
-#ifdef DEBUG
- g_message ("%s: waiting for %p", __func__, handle);
-#endif
+ DEBUG ("%s: waiting for %p", __func__, handle);
return _wapi_handle_timedwait_signal_handle (handle, NULL, alertable, FALSE);
}
int _wapi_handle_timedwait_signal_handle (gpointer handle,
struct timespec *timeout, gboolean alertable, gboolean poll)
{
-#ifdef DEBUG
- g_message ("%s: waiting for %p (type %s)", __func__, handle,
+ DEBUG ("%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_DATA(handle).signalled == TRUE) {
}
}
+void
+_wapi_free_share_info (_WapiFileShare *share_info)
+{
+ if (!_wapi_shm_enabled ()) {
+ file_share_hash_lock ();
+ g_hash_table_remove (file_share_hash, share_info);
+ file_share_hash_unlock ();
+ /* The hashtable dtor frees share_info */
+ } else {
+ memset (share_info, '\0', sizeof(struct _WapiFileShare));
+ }
+}
+
+static gint
+wapi_share_info_equal (gconstpointer ka, gconstpointer kb)
+{
+ const _WapiFileShare *s1 = ka;
+ const _WapiFileShare *s2 = kb;
+
+ return (s1->device == s2->device && s1->inode == s2->inode) ? 1 : 0;
+}
+
+static guint
+wapi_share_info_hash (gconstpointer data)
+{
+ const _WapiFileShare *s = data;
+
+ return s->inode;
+}
+
gboolean _wapi_handle_get_or_set_share (dev_t device, ino_t inode,
guint32 new_sharemode,
guint32 new_access,
/* Prevent new entries racing with us */
thr_ret = _wapi_shm_sem_lock (_WAPI_SHARED_SEM_FILESHARE);
g_assert (thr_ret == 0);
-
- /* If a linear scan gets too slow we'll have to fit a hash
- * table onto the shared mem backing store
- */
- *share_info = NULL;
- for (i = 0; i <= _wapi_fileshare_layout->hwm; i++) {
- file_share = &_wapi_fileshare_layout->share_info[i];
- /* Make a note of an unused slot, in case we need to
- * store share info
+ if (!_wapi_shm_enabled ()) {
+ _WapiFileShare tmp;
+
+ /*
+ * Instead of allocating a 4MB array, we use a hash table to keep track of this
+ * info. This is needed even if SHM is disabled, to track sharing inside
+ * the current process.
*/
- if (first_unused == -1 && file_share->handle_refs == 0) {
- first_unused = i;
- continue;
+ if (!file_share_hash) {
+ file_share_hash = g_hash_table_new_full (wapi_share_info_hash, wapi_share_info_equal, NULL, g_free);
+ InitializeCriticalSection (&file_share_hash_mutex);
}
-
- if (file_share->handle_refs == 0) {
- continue;
- }
-
- if (file_share->device == device &&
- file_share->inode == inode) {
+
+ tmp.device = device;
+ tmp.inode = inode;
+
+ file_share_hash_lock ();
+
+ file_share = g_hash_table_lookup (file_share_hash, &tmp);
+ if (file_share) {
*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 ((gint32 *)&file_share->handle_refs);
-
exists = TRUE;
- break;
- }
- }
-
- 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 = g_new0 (_WapiFileShare, 1);
+
file_share->device = device;
file_share->inode = inode;
file_share->opened_by_pid = _wapi_getpid ();
file_share->access = new_access;
file_share->handle_refs = 1;
*share_info = file_share;
+
+ g_hash_table_insert (file_share_hash, file_share, file_share);
}
- }
- if (*share_info != NULL) {
- InterlockedExchange ((gint32 *)&(*share_info)->timestamp, now);
+ file_share_hash_unlock ();
+ } else {
+ /* 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 ((gint32 *)&file_share->handle_refs);
+
+ exists = TRUE;
+ break;
+ }
+ }
+
+ 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 = _wapi_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 ((gint32 *)&(*share_info)->timestamp, now);
+ }
}
thr_ret = _wapi_shm_sem_unlock (_WAPI_SHARED_SEM_FILESHARE);
*/
static void _wapi_handle_check_share_by_pid (struct _WapiFileShare *share_info)
{
+#if defined(__native_client__)
+ g_assert_not_reached ();
+#else
if (kill (share_info->opened_by_pid, 0) == -1 &&
(errno == ESRCH ||
errno == EPERM)) {
* owned by someone else) so mark this share info as
* dead
*/
-#ifdef DEBUG
- g_message ("%s: Didn't find it, destroying entry", __func__);
-#endif
+ DEBUG ("%s: Didn't find it, destroying entry", __func__);
- memset (share_info, '\0', sizeof(struct _WapiFileShare));
+ _wapi_free_share_info (share_info);
}
+#endif
}
#ifdef __linux__
struct _WapiHandle_file *file_handle = &handle->u.file;
if (file_handle->share_info == share_info) {
-#ifdef DEBUG
- g_message ("%s: handle 0x%x has this file open!",
+ DEBUG ("%s: handle 0x%x has this file open!",
__func__, i);
-#endif
goto done;
}
continue;
}
-#ifdef DEBUG
- g_message ("%s: Looking in %s", __func__, subdir);
-#endif
+ DEBUG ("%s: Looking in %s", __func__, subdir);
proc_fds = TRUE;
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",
+ DEBUG ("%s: Found it at %s",
__func__, path);
-#endif
found = TRUE;
}
_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
+ DEBUG ("%s: Didn't find it, destroying entry", __func__);
- memset (share_info, '\0', sizeof(struct _WapiFileShare));
+ _wapi_free_share_info (share_info);
}
done:
if (_WAPI_SHARED_HANDLE(handle->type)) {
struct _WapiHandleShared *shared_data;
-#ifdef DEBUG
- g_message ("%s: (%d) handle 0x%x is SHARED (%s)", __func__, _wapi_getpid (), i * _WAPI_HANDLE_INITIAL_COUNT + k, _wapi_handle_typename[handle->type]);
-#endif
+ DEBUG ("%s: (%d) handle 0x%x is SHARED (%s)", __func__, _wapi_getpid (), i * _WAPI_HANDLE_INITIAL_COUNT + k, _wapi_handle_typename[handle->type]);
shared_data = &_wapi_shared_layout->handles[handle->u.shared.offset];
-#ifdef DEBUG
- g_message ("%s: (%d) Updating timestamp of handle 0x%x", __func__, _wapi_getpid (), handle->u.shared.offset);
-#endif
+ DEBUG ("%s: (%d) Updating timestamp of handle 0x%x", __func__, _wapi_getpid (), handle->u.shared.offset);
InterlockedExchange ((gint32 *)&shared_data->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__, _wapi_getpid (), i * _WAPI_HANDLE_INITIAL_COUNT + k);
-#endif
+ DEBUG ("%s: (%d) handle 0x%x is FILE", __func__, _wapi_getpid (), i * _WAPI_HANDLE_INITIAL_COUNT + k);
g_assert (file_handle->share_info != NULL);
-#ifdef DEBUG
- g_message ("%s: (%d) Inc refs on fileshare 0x%x", __func__, _wapi_getpid (), (file_handle->share_info - &_wapi_fileshare_layout->share_info[0]) / sizeof(struct _WapiFileShare));
-#endif
+ DEBUG ("%s: (%d) Inc refs on fileshare 0x%x", __func__, _wapi_getpid (), (file_handle->share_info - &_wapi_fileshare_layout->share_info[0]) / sizeof(struct _WapiFileShare));
InterlockedExchange ((gint32 *)&file_handle->share_info->timestamp, now);
}