#include <unistd.h>
#include <string.h>
#include <sys/types.h>
-#include <sys/socket.h>
-#include <sys/un.h>
-#include <sys/mman.h>
-#include <dirent.h>
+#ifdef HAVE_SYS_SOCKET_H
+# include <sys/socket.h>
+#endif
+#ifdef HAVE_SYS_UN_H
+# include <sys/un.h>
+#endif
+#ifdef HAVE_SYS_MMAN_H
+# include <sys/mman.h>
+#endif
+#ifdef HAVE_DIRENT_H
+# include <dirent.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/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
#undef DEBUG_REFS
&_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,
struct _WapiHandleUnshared *_wapi_private_handles [_WAPI_PRIVATE_MAX_SLOTS];
static guint32 _wapi_private_handle_count = 0;
+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;
-mono_mutex_t _wapi_global_signal_mutex;
-pthread_cond_t _wapi_global_signal_cond;
+/*
+ * This is an internal handle which is used for handling waiting for multiple handles.
+ * Threads which wait for multiple handles wait on this one handle, and when a handle
+ * is signalled, this handle is signalled too.
+ */
+static gpointer _wapi_global_signal_handle;
+
+/* Point to the mutex/cond inside _wapi_global_signal_handle */
+mono_mutex_t *_wapi_global_signal_mutex;
+pthread_cond_t *_wapi_global_signal_cond;
int _wapi_sem_id;
+gboolean _wapi_has_shut_down = FALSE;
/* Use this instead of getpid(), to cope with linuxthreads. It's a
* function rather than a variable lookup because we need to get at
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 pid_init (void)
{
_wapi_pid = getpid ();
}
_wapi_shm_semaphores_remove ();
+
+ _wapi_shm_detach (WAPI_SHM_DATA);
+ _wapi_shm_detach (WAPI_SHM_FILESHARE);
+
+ 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]);
+}
+
+void _wapi_cleanup ()
+{
+ g_assert (_wapi_has_shut_down == FALSE);
+
+ _wapi_has_shut_down = TRUE;
+
+ _wapi_critical_section_cleanup ();
+ _wapi_error_cleanup ();
+ _wapi_thread_cleanup ();
}
static mono_once_t shared_init_once = MONO_ONCE_INIT;
static void shared_init (void)
{
- int thr_ret;
- int idx = 0;
-
g_assert ((sizeof (handle_ops) / sizeof (handle_ops[0]))
== WAPI_HANDLE_COUNT);
_wapi_fd_reserve = getdtablesize();
+ /* This is needed by the code in _wapi_handle_new_internal */
+ _wapi_fd_reserve = (_wapi_fd_reserve + (_WAPI_HANDLE_INITIAL_COUNT - 1)) & ~(_WAPI_HANDLE_INITIAL_COUNT - 1);
+
do {
+ /*
+ * The entries in _wapi_private_handles reserved for fds are allocated lazily to
+ * save memory.
+ */
+ /*
_wapi_private_handles [idx++] = g_new0 (struct _WapiHandleUnshared,
_WAPI_HANDLE_INITIAL_COUNT);
+ */
_wapi_private_handle_count += _WAPI_HANDLE_INITIAL_COUNT;
+ _wapi_private_handle_slot_count ++;
} while(_wapi_fd_reserve > _wapi_private_handle_count);
_wapi_shm_semaphores_init ();
_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);
-
- _wapi_collection_init ();
-
- thr_ret = pthread_cond_init(&_wapi_global_signal_cond, NULL);
- g_assert (thr_ret == 0);
+ 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);
+ }
- thr_ret = mono_mutex_init(&_wapi_global_signal_mutex, NULL);
- g_assert (thr_ret == 0);
+#if !defined (DISABLE_SHARED_HANDLES)
+ if (_wapi_shm_enabled ())
+ _wapi_collection_init ();
+#endif
+
+ /* 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_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
WapiHandleType type,
gpointer handle_specific)
{
+ g_assert (_wapi_has_shut_down == FALSE);
+
handle->type = type;
handle->timestamp = (guint32)(time (NULL) & 0xFFFFFFFF);
handle->signalled = FALSE;
{
int thr_ret;
+ g_assert (_wapi_has_shut_down == FALSE);
+
handle->type = type;
handle->signalled = FALSE;
handle->ref = 1;
static guint32 last = 1;
int thr_ret;
+ g_assert (_wapi_has_shut_down == FALSE);
+
/* Leave the first slot empty as a guard */
again:
/* FIXME: expandable array */
static guint32 last = 0;
gboolean retry = FALSE;
+ g_assert (_wapi_has_shut_down == FALSE);
+
/* 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
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 = SLOT_INDEX (count); i < _wapi_private_handle_slot_count; i++) {
+ if (_wapi_private_handles [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;
+ if(handle->type == WAPI_HANDLE_UNUSED) {
+ last = count + 1;
- _wapi_handle_init (handle, type, handle_specific);
- return (count);
+ _wapi_handle_init (handle, type, handle_specific);
+ return (count);
+ }
+ count++;
}
- count++;
}
}
return(0);
}
-gpointer _wapi_handle_new (WapiHandleType type, gpointer handle_specific)
+static gpointer _wapi_handle_real_new (WapiHandleType type, gpointer handle_specific)
{
guint32 handle_idx = 0;
gpointer handle;
int thr_ret;
- mono_once (&shared_init_once, shared_init);
-
#ifdef DEBUG
g_message ("%s: Creating new handle of type %s", __func__,
_wapi_handle_typename[type]);
if (idx >= _WAPI_PRIVATE_MAX_SLOTS) {
break;
}
-
+
_wapi_private_handles [idx] = g_new0 (struct _WapiHandleUnshared,
_WAPI_HANDLE_INITIAL_COUNT);
_wapi_private_handle_count += _WAPI_HANDLE_INITIAL_COUNT;
+ _wapi_private_handle_slot_count ++;
}
thr_ret = mono_mutex_unlock (&scan_mutex);
ref = _wapi_handle_new_shared (type, handle_specific);
if (ref == 0) {
_wapi_handle_collect ();
+ _wapi_process_reap ();
ref = _wapi_handle_new_shared (type, handle_specific);
if (ref == 0) {
/* FIXME: grow the arrays */
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)
{
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
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++) {
- struct _WapiHandleUnshared *handle_data = &_wapi_private_handles [i][k];
+ for (i = SLOT_INDEX (0); i < _wapi_private_handle_slot_count; i++) {
+ if (_wapi_private_handles [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);
- goto first_pass_done;
+ if (handle_data->type == type &&
+ handle_data->u.shared.offset == offset) {
+ handle = GUINT_TO_POINTER (i * _WAPI_HANDLE_INITIAL_COUNT + k);
+ goto first_pass_done;
+ }
}
}
}
_WAPI_HANDLE_INITIAL_COUNT);
_wapi_private_handle_count += _WAPI_HANDLE_INITIAL_COUNT;
+ _wapi_private_handle_slot_count ++;
}
thr_ret = mono_mutex_unlock (&scan_mutex);
return(handle);
}
+static void
+init_handles_slot (int idx)
+{
+ 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);
+
+ if (_wapi_private_handles [idx] == NULL) {
+ _wapi_private_handles [idx] = g_new0 (struct _WapiHandleUnshared,
+ _WAPI_HANDLE_INITIAL_COUNT);
+ g_assert (_wapi_private_handles [idx]);
+ }
+
+ thr_ret = mono_mutex_unlock (&scan_mutex);
+ g_assert (thr_ret == 0);
+ pthread_cleanup_pop (0);
+}
+
gpointer _wapi_handle_new_fd (WapiHandleType type, int fd,
gpointer handle_specific)
{
struct _WapiHandleUnshared *handle;
int thr_ret;
+ g_assert (_wapi_has_shut_down == FALSE);
+
mono_once (&shared_init_once, shared_init);
#ifdef DEBUG
return(GUINT_TO_POINTER (_WAPI_HANDLE_INVALID));
}
+ /* Initialize the array entries on demand */
+ if (_wapi_private_handles [SLOT_INDEX (fd)] == NULL)
+ init_handles_slot (SLOT_INDEX (fd));
+
handle = &_WAPI_PRIVATE_HANDLES(fd);
if (handle->type != WAPI_HANDLE_UNUSED) {
if (!_WAPI_PRIVATE_VALID_SLOT (handle_idx)) {
return(FALSE);
}
+
+ /* Initialize the array entries on demand */
+ if (_wapi_private_handles [SLOT_INDEX (handle_idx)] == NULL)
+ init_handles_slot (SLOT_INDEX (handle_idx));
handle_data = &_WAPI_PRIVATE_HANDLES(handle_idx);
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;
+ for (i = SLOT_INDEX (0); i < _wapi_private_handle_slot_count; i++) {
+ if (_wapi_private_handles [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;
+ }
}
}
}
gboolean search_shared)
{
struct _WapiHandleUnshared *handle_data = NULL;
- struct _WapiHandleShared *shared;
+ struct _WapiHandleShared *shared = NULL;
gpointer ret = NULL;
guint32 i, k;
gboolean found = FALSE;
thr_ret = mono_mutex_lock (&scan_mutex);
g_assert (thr_ret == 0);
- 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];
+ for (i = SLOT_INDEX (0); !found && i < _wapi_private_handle_slot_count; i++) {
+ if (_wapi_private_handles [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 (check (ret, user_data) == TRUE) {
- _wapi_handle_ref (ret);
- found = TRUE;
+ if (handle_data->type == type) {
+ ret = GUINT_TO_POINTER (i * _WAPI_HANDLE_INITIAL_COUNT + k);
+ if (check (ret, user_data) == TRUE) {
+ _wapi_handle_ref (ret);
+ found = TRUE;
- if (_WAPI_SHARED_HANDLE (type)) {
- shared = &_wapi_shared_layout->handles[i];
- }
+ if (_WAPI_SHARED_HANDLE (type)) {
+ shared = &_wapi_shared_layout->handles[i];
+ }
- break;
+ break;
+ }
}
}
}
return(FALSE);
}
}
+ if (handle == _WAPI_HANDLE_INVALID){
+ SetLastError (ERROR_INVALID_PARAMETER);
+ return(FALSE);
+ }
_wapi_handle_unref (handle);
type = _WAPI_PRIVATE_HANDLES(idx).type;
- _wapi_handle_ref (handle);
-
#ifdef DEBUG
g_message ("%s: Checking handle %p", __func__, handle);
#endif
}
}
-static int timedwait_signal_poll_cond (pthread_cond_t *cond, mono_mutex_t *mutex, struct timespec *timeout)
+static int timedwait_signal_poll_cond (pthread_cond_t *cond, mono_mutex_t *mutex, struct timespec *timeout, gboolean alertable)
{
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);
+
+ if (!alertable) {
+ if (timeout)
+ ret=mono_cond_timedwait (cond, mutex, timeout);
+ else
+ ret=mono_cond_wait (cond, mutex);
} else {
- ret=mono_cond_timedwait (cond, mutex, &fake_timeout);
+ _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);
- /* Mask the fake timeout, this will cause
- * another poll if the cond was not really signaled
- */
- if (ret==ETIMEDOUT) {
- ret=0;
+ /* 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)
+int _wapi_handle_wait_signal (gboolean poll)
{
- return timedwait_signal_poll_cond (&_wapi_global_signal_cond, &_wapi_global_signal_mutex, NULL);
+ return _wapi_handle_timedwait_signal_handle (_wapi_global_signal_handle, NULL, TRUE, poll);
}
-int _wapi_handle_timedwait_signal (struct timespec *timeout)
+int _wapi_handle_timedwait_signal (struct timespec *timeout, gboolean poll)
{
- return timedwait_signal_poll_cond (&_wapi_global_signal_cond, &_wapi_global_signal_mutex, timeout);
+ return _wapi_handle_timedwait_signal_handle (_wapi_global_signal_handle, timeout, TRUE, poll);
}
-int _wapi_handle_wait_signal_handle (gpointer handle)
+int _wapi_handle_wait_signal_handle (gpointer handle, gboolean alertable)
{
#ifdef DEBUG
g_message ("%s: waiting for %p", __func__, handle);
#endif
- return _wapi_handle_timedwait_signal_handle (handle, NULL);
+ return _wapi_handle_timedwait_signal_handle (handle, NULL, alertable, FALSE);
}
int _wapi_handle_timedwait_signal_handle (gpointer handle,
- struct timespec *timeout)
+ struct timespec *timeout, gboolean alertable, gboolean poll)
{
#ifdef DEBUG
g_message ("%s: waiting for %p (type %s)", __func__, handle,
} 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);
+ int res;
+ pthread_cond_t *cond;
+ mono_mutex_t *mutex;
+
+ if (alertable && !wapi_thread_set_wait_handle (handle))
+ return 0;
+
+ cond = &_WAPI_PRIVATE_HANDLES (idx).signal_cond;
+ mutex = &_WAPI_PRIVATE_HANDLES (idx).signal_mutex;
+
+ if (poll) {
+ /* This is needed when waiting for process handles */
+ res = timedwait_signal_poll_cond (cond, mutex, timeout, alertable);
+ } else {
+ if (timeout)
+ res = mono_cond_timedwait (cond, mutex, timeout);
+ else
+ res = mono_cond_wait (cond, mutex);
+ }
+
+ if (alertable)
+ wapi_thread_clear_wait_handle (handle);
+
+ return res;
}
}
+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 ();
+ } 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->handle_refs == 0) {
- 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->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);
}
}
+#ifdef __linux__
/* Scan /proc/<pids>/fd/ for open file descriptors to the file in
* question. If there are none, reset the share info.
*
* See bugs 75764 and 75891
*/
for (i = 0; i < _wapi_fd_reserve; i++) {
- struct _WapiHandleUnshared *handle = &_WAPI_PRIVATE_HANDLES(i);
+ if (_wapi_private_handles [SLOT_INDEX (i)]) {
+ struct _WapiHandleUnshared *handle = &_WAPI_PRIVATE_HANDLES(i);
- if (i != fd &&
- handle->type == WAPI_HANDLE_FILE) {
- struct _WapiHandle_file *file_handle = &handle->u.file;
+ if (i != fd &&
+ handle->type == WAPI_HANDLE_FILE) {
+ struct _WapiHandle_file *file_handle = &handle->u.file;
- if (file_handle->share_info == share_info) {
+ if (file_handle->share_info == share_info) {
#ifdef DEBUG
- g_message ("%s: handle 0x%x has this file open!",
- __func__, i);
+ g_message ("%s: handle 0x%x has this file open!",
+ __func__, i);
#endif
- goto done;
+ goto done;
+ }
}
}
}
_wapi_handle_unlock_shared_handles ();
}
+#else
+//
+// Other implementations (non-Linux)
+//
+void _wapi_handle_check_share (struct _WapiFileShare *share_info, int fd)
+{
+ int thr_ret;
+
+ /* Prevents entries from expiring under us if we remove this
+ * one */
+ thr_ret = _wapi_handle_lock_shared_handles ();
+ g_assert (thr_ret == 0);
+
+ /* Prevent new entries racing with us */
+ thr_ret = _wapi_shm_sem_lock (_WAPI_SHARED_SEM_FILESHARE);
+ g_assert (thr_ret == 0);
+
+ _wapi_handle_check_share_by_pid (share_info);
+
+ thr_ret = _wapi_shm_sem_unlock (_WAPI_SHARED_SEM_FILESHARE);
+ _wapi_handle_unlock_shared_handles ();
+}
+#endif
void _wapi_handle_dump (void)
{
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];
+ for(i = SLOT_INDEX (0); i < _wapi_private_handle_slot_count; i++) {
+ if (_wapi_private_handles [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_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");
+ 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 *)&scan_mutex);
thr_ret = mono_mutex_lock (&scan_mutex);
- 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];
+ for(i = SLOT_INDEX (0); i < _wapi_private_handle_slot_count; i++) {
+ if (_wapi_private_handles [i]) {
+ for (k = SLOT_OFFSET (0); k < _WAPI_HANDLE_INITIAL_COUNT; k++) {
+ struct _WapiHandleUnshared *handle = &_wapi_private_handles [i][k];
- if (_WAPI_SHARED_HANDLE(handle->type)) {
- struct _WapiHandleShared *shared_data;
+ 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]);
+ 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
- shared_data = &_wapi_shared_layout->handles[handle->u.shared.offset];
+ 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);
+ g_message ("%s: (%d) Updating timestamp of handle 0x%x", __func__, _wapi_getpid (), handle->u.shared.offset);
#endif
- InterlockedExchange ((gint32 *)&shared_data->timestamp, now);
- } else if (handle->type == WAPI_HANDLE_FILE) {
- struct _WapiHandle_file *file_handle = &handle->u.file;
+ 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);
+ g_message ("%s: (%d) handle 0x%x is FILE", __func__, _wapi_getpid (), i * _WAPI_HANDLE_INITIAL_COUNT + k);
#endif
- g_assert (file_handle->share_info != NULL);
+ 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));
+ 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
- InterlockedExchange ((gint32 *)&file_handle->share_info->timestamp, now);
+ InterlockedExchange ((gint32 *)&file_handle->share_info->timestamp, now);
+ }
}
}
}