X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mono%2Fio-layer%2Fhandles.c;h=0dbc5ed2e6d0170e8ec2363b66d26fed35a4231f;hb=bf7e68c32960f9e28f96341e4512bba48d00caf6;hp=f9de22c044a3c17f77de957d275a095f0b8bb6b8;hpb=b2262f41726a89c8209facb3ea9e4be9582422b5;p=mono.git diff --git a/mono/io-layer/handles.c b/mono/io-layer/handles.c index f9de22c044a..0dbc5ed2e6d 100644 --- a/mono/io-layer/handles.c +++ b/mono/io-layer/handles.c @@ -14,14 +14,20 @@ #include #include #include -#include -#include -#include -#include +#ifdef HAVE_SYS_SOCKET_H +# include +#endif +#ifdef HAVE_SYS_UN_H +# include +#endif +#ifdef HAVE_SYS_MMAN_H +# include +#endif +#ifdef HAVE_DIRENT_H +# include +#endif #include -#include - #include #include #include @@ -30,6 +36,7 @@ #include #include #include +#include #undef DEBUG #undef DEBUG_REFS @@ -45,7 +52,9 @@ static struct _WapiHandleOps *handle_ops[WAPI_HANDLE_COUNT]={ &_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, @@ -100,16 +109,41 @@ const char *_wapi_handle_typename[] = { 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 @@ -118,6 +152,8 @@ int _wapi_sem_id; 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 (); @@ -184,24 +220,53 @@ static void handle_cleanup (void) } _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 (); @@ -209,16 +274,22 @@ static void shared_init (void) _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 @@ -232,6 +303,8 @@ static void _wapi_handle_init_shared (struct _WapiHandleShared *handle, WapiHandleType type, gpointer handle_specific) { + g_assert (_wapi_has_shut_down == FALSE); + handle->type = type; handle->timestamp = (guint32)(time (NULL) & 0xFFFFFFFF); handle->signalled = FALSE; @@ -247,6 +320,8 @@ static void _wapi_handle_init (struct _WapiHandleUnshared *handle, { int thr_ret; + g_assert (_wapi_has_shut_down == FALSE); + handle->type = type; handle->signalled = FALSE; handle->ref = 1; @@ -272,6 +347,8 @@ static guint32 _wapi_handle_new_shared (WapiHandleType type, 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 */ @@ -327,6 +404,8 @@ static guint32 _wapi_handle_new_internal (WapiHandleType type, 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 @@ -341,17 +420,19 @@ static guint32 _wapi_handle_new_internal (WapiHandleType type, 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++; } } @@ -366,14 +447,12 @@ again: 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]); @@ -392,11 +471,12 @@ gpointer _wapi_handle_new (WapiHandleType type, gpointer handle_specific) 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); @@ -425,6 +505,7 @@ gpointer _wapi_handle_new (WapiHandleType type, gpointer handle_specific) 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 */ @@ -444,6 +525,15 @@ 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) { @@ -453,6 +543,8 @@ gpointer _wapi_handle_new_from_offset (WapiHandleType type, guint32 offset, 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 @@ -475,14 +567,16 @@ gpointer _wapi_handle_new_from_offset (WapiHandleType type, guint32 offset, 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; + } } } } @@ -536,6 +630,7 @@ 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); @@ -560,12 +655,35 @@ done: 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 @@ -584,6 +702,10 @@ gpointer _wapi_handle_new_fd (WapiHandleType type, int fd, 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) { @@ -621,6 +743,10 @@ gboolean _wapi_lookup_handle (gpointer handle, WapiHandleType type, 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); @@ -668,14 +794,16 @@ _wapi_handle_foreach (WapiHandleType type, 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; + } } } } @@ -699,7 +827,7 @@ gpointer _wapi_search_handle (WapiHandleType type, gboolean search_shared) { struct _WapiHandleUnshared *handle_data = NULL; - struct _WapiHandleShared *shared; + struct _WapiHandleShared *shared = NULL; gpointer ret = NULL; guint32 i, k; gboolean found = FALSE; @@ -710,21 +838,23 @@ gpointer _wapi_search_handle (WapiHandleType type, 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; + } } } } @@ -1337,8 +1467,6 @@ again: type = _WAPI_PRIVATE_HANDLES(idx).type; - _wapi_handle_ref (handle); - #ifdef DEBUG g_message ("%s: Checking handle %p", __func__, handle); #endif @@ -1434,14 +1562,14 @@ static int timedwait_signal_poll_cond (pthread_cond_t *cond, mono_mutex_t *mutex 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, TRUE); + 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, TRUE); + return _wapi_handle_timedwait_signal_handle (_wapi_global_signal_handle, timeout, TRUE, poll); } int _wapi_handle_wait_signal_handle (gpointer handle, gboolean alertable) @@ -1450,11 +1578,11 @@ int _wapi_handle_wait_signal_handle (gpointer handle, gboolean alertable) g_message ("%s: waiting for %p", __func__, handle); #endif - return _wapi_handle_timedwait_signal_handle (handle, NULL, alertable); + return _wapi_handle_timedwait_signal_handle (handle, NULL, alertable, FALSE); } int _wapi_handle_timedwait_signal_handle (gpointer handle, - struct timespec *timeout, gboolean alertable) + struct timespec *timeout, gboolean alertable, gboolean poll) { #ifdef DEBUG g_message ("%s: waiting for %p (type %s)", __func__, handle, @@ -1490,10 +1618,62 @@ int _wapi_handle_timedwait_signal_handle (gpointer 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, alertable); + 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, @@ -1514,55 +1694,36 @@ gboolean _wapi_handle_get_or_set_share (dev_t device, ino_t inode, /* 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 (); @@ -1570,11 +1731,73 @@ gboolean _wapi_handle_get_or_set_share (dev_t device, ino_t inode, 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); + } + + 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); + if (*share_info != NULL) { + InterlockedExchange ((gint32 *)&(*share_info)->timestamp, now); + } } thr_ret = _wapi_shm_sem_unlock (_WAPI_SHARED_SEM_FILESHARE); @@ -1605,6 +1828,7 @@ static void _wapi_handle_check_share_by_pid (struct _WapiFileShare *share_info) } } +#ifdef __linux__ /* Scan /proc//fd/ for open file descriptors to the file in * question. If there are none, reset the share info. * @@ -1640,19 +1864,21 @@ void _wapi_handle_check_share (struct _WapiFileShare *share_info, int fd) * 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; + } } } } @@ -1736,6 +1962,29 @@ 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) { @@ -1748,21 +1997,23 @@ 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"); + } } } @@ -1795,38 +2046,40 @@ void _wapi_handle_update_refs (void) (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); + } } } }