X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mono%2Fio-layer%2Fhandles.c;h=17f3fb6c4fe8dfa27a834a25c062accd011ec28b;hb=4b857e0841fc1f78a27a6b8e43c02845f8dd61d6;hp=12e383504e8cf277cf83e70c430df1087f898891;hpb=44f4429237816e808e42136783c6fb885e13a5dd;p=mono.git diff --git a/mono/io-layer/handles.c b/mono/io-layer/handles.c index 12e383504e8..17f3fb6c4fe 100644 --- a/mono/io-layer/handles.c +++ b/mono/io-layer/handles.c @@ -6,6 +6,7 @@ * * (C) 2002-2011 Novell, Inc. * Copyright 2011 Xamarin Inc + * Licensed under the MIT license. See LICENSE file in the project root for full license information. */ #include @@ -39,24 +40,51 @@ #include #include #include -#include #include +#include #include #include #include #include +#include #undef DEBUG_REFS -#if 0 -#define DEBUG(...) g_message(__VA_ARGS__) -#else -#define DEBUG(...) -#endif +#define _WAPI_PRIVATE_MAX_SLOTS (1024 * 16) + +/* must be a power of 2 */ +#define _WAPI_HANDLE_INITIAL_COUNT (256) + +struct _WapiHandleUnshared +{ + WapiHandleType type; + guint ref; + gboolean signalled; + mono_mutex_t signal_mutex; + mono_cond_t signal_cond; + + union + { + struct _WapiHandle_event event; + struct _WapiHandle_file file; + struct _WapiHandle_find find; + struct _WapiHandle_mutex mutex; + struct _WapiHandle_sem sem; + struct _WapiHandle_socket sock; + struct _WapiHandle_thread thread; + struct _WapiHandle_process process; + struct _WapiHandle_shared_ref shared; + struct _WapiHandle_namedmutex namedmutex; + struct _WapiHandle_namedsem namedsem; + struct _WapiHandle_namedevent namedevent; + } u; +}; + +typedef struct _WapiHandleUnshared _WapiHandleUnshared; static void (*_wapi_handle_ops_get_close_func (WapiHandleType type))(gpointer, gpointer); -static WapiHandleCapability handle_caps[WAPI_HANDLE_COUNT]={0}; +static WapiHandleCapability handle_caps[WAPI_HANDLE_COUNT] = { (WapiHandleCapability)0 }; static struct _WapiHandleOps *handle_ops[WAPI_HANDLE_COUNT]={ NULL, &_wapi_file_ops, @@ -124,13 +152,6 @@ 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 @@ -152,8 +173,8 @@ guint32 _wapi_fd_reserve; 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; +static mono_mutex_t *_wapi_global_signal_mutex; +static mono_cond_t *_wapi_global_signal_cond; int _wapi_sem_id; gboolean _wapi_has_shut_down = FALSE; @@ -182,6 +203,189 @@ pid_t _wapi_getpid (void) static mono_mutex_t scan_mutex; +#define _WAPI_PRIVATE_HANDLES(x) (_wapi_private_handles [SLOT_INDEX ((guint32) x)][SLOT_OFFSET ((guint32) x)]) + +static gboolean +_WAPI_PRIVATE_HAVE_SLOT (guint32 x) +{ + return (x / _WAPI_PRIVATE_MAX_SLOTS) < _WAPI_PRIVATE_MAX_SLOTS && _wapi_private_handles [SLOT_INDEX (x)]; +} + +static gboolean +_WAPI_PRIVATE_VALID_SLOT (guint32 x) +{ + return SLOT_INDEX (x) < _WAPI_PRIVATE_MAX_SLOTS; +} + +WapiHandleType +_wapi_handle_type (gpointer handle) +{ + guint32 idx = GPOINTER_TO_UINT(handle); + + if (!_WAPI_PRIVATE_VALID_SLOT (idx) || !_WAPI_PRIVATE_HAVE_SLOT (idx)) + return WAPI_HANDLE_UNUSED; /* An impossible type */ + + return _WAPI_PRIVATE_HANDLES(idx).type; +} + +void +_wapi_handle_set_signal_state (gpointer handle, gboolean state, gboolean broadcast) +{ + guint32 idx = GPOINTER_TO_UINT(handle); + struct _WapiHandleUnshared *handle_data; + int thr_ret; + + if (!_WAPI_PRIVATE_VALID_SLOT (idx)) { + return; + } + + handle_data = &_WAPI_PRIVATE_HANDLES(idx); + +#ifdef DEBUG + g_message ("%s: setting state of %p to %s (broadcast %s)", __func__, + handle, state?"TRUE":"FALSE", broadcast?"TRUE":"FALSE"); +#endif + + if (state == TRUE) { + /* Tell everyone blocking on a single handle */ + + /* The condition the global signal cond is waiting on is the signalling of + * _any_ handle. So lock it before setting the signalled state. + */ + thr_ret = mono_os_mutex_lock (_wapi_global_signal_mutex); + if (thr_ret != 0) + g_warning ("Bad call to mono_os_mutex_lock result %d for global signal mutex", thr_ret); + g_assert (thr_ret == 0); + + /* This function _must_ be called with + * handle->signal_mutex locked + */ + handle_data->signalled=state; + + if (broadcast == TRUE) { + thr_ret = mono_os_cond_broadcast (&handle_data->signal_cond); + if (thr_ret != 0) + g_warning ("Bad call to mono_os_cond_broadcast result %d for handle %p", thr_ret, handle); + g_assert (thr_ret == 0); + } else { + thr_ret = mono_os_cond_signal (&handle_data->signal_cond); + if (thr_ret != 0) + g_warning ("Bad call to mono_os_cond_signal result %d for handle %p", thr_ret, handle); + g_assert (thr_ret == 0); + } + + /* Tell everyone blocking on multiple handles that something + * was signalled + */ + thr_ret = mono_os_cond_broadcast (_wapi_global_signal_cond); + if (thr_ret != 0) + g_warning ("Bad call to mono_os_cond_broadcast result %d for handle %p", thr_ret, handle); + g_assert (thr_ret == 0); + + thr_ret = mono_os_mutex_unlock (_wapi_global_signal_mutex); + if (thr_ret != 0) + g_warning ("Bad call to mono_os_mutex_unlock result %d for global signal mutex", thr_ret); + g_assert (thr_ret == 0); + } else { + handle_data->signalled=state; + } +} + +gboolean +_wapi_handle_issignalled (gpointer handle) +{ + guint32 idx = GPOINTER_TO_UINT(handle); + + if (!_WAPI_PRIVATE_VALID_SLOT (idx)) { + return(FALSE); + } + + return _WAPI_PRIVATE_HANDLES (idx).signalled; +} + +int +_wapi_handle_lock_signal_mutex (void) +{ +#ifdef DEBUG + g_message ("%s: lock global signal mutex", __func__); +#endif + + return(mono_os_mutex_lock (_wapi_global_signal_mutex)); +} + +int +_wapi_handle_unlock_signal_mutex (void) +{ +#ifdef DEBUG + g_message ("%s: unlock global signal mutex", __func__); +#endif + + return(mono_os_mutex_unlock (_wapi_global_signal_mutex)); +} + +int +_wapi_handle_lock_handle (gpointer handle) +{ + guint32 idx = GPOINTER_TO_UINT(handle); + +#ifdef DEBUG + g_message ("%s: locking handle %p", __func__, handle); +#endif + + if (!_WAPI_PRIVATE_VALID_SLOT (idx)) { + return(0); + } + + _wapi_handle_ref (handle); + + return(mono_os_mutex_lock (&_WAPI_PRIVATE_HANDLES(idx).signal_mutex)); +} + +int +_wapi_handle_trylock_handle (gpointer handle) +{ + guint32 idx = GPOINTER_TO_UINT(handle); + int ret; + +#ifdef DEBUG + g_message ("%s: locking handle %p", __func__, handle); +#endif + + if (!_WAPI_PRIVATE_VALID_SLOT (idx)) { + return(0); + } + + _wapi_handle_ref (handle); + + ret = mono_os_mutex_trylock (&_WAPI_PRIVATE_HANDLES(idx).signal_mutex); + if (ret != 0) { + _wapi_handle_unref (handle); + } + + return(ret); +} + +int +_wapi_handle_unlock_handle (gpointer handle) +{ + guint32 idx = GPOINTER_TO_UINT(handle); + int ret; + +#ifdef DEBUG + g_message ("%s: unlocking handle %p", __func__, handle); +#endif + + if (!_WAPI_PRIVATE_VALID_SLOT (idx)) { + return(0); + } + + ret = mono_os_mutex_unlock (&_WAPI_PRIVATE_HANDLES(idx).signal_mutex); + + _wapi_handle_unref (handle); + + return(ret); +} + static void handle_cleanup (void) { int i, j, k; @@ -199,8 +403,6 @@ static void handle_cleanup (void) 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_full (handle, TRUE); } } @@ -208,9 +410,6 @@ 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); mono_os_mutex_destroy (&file_share_hash_mutex); @@ -257,20 +456,7 @@ wapi_init (void) } 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); - - 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); - } - -#if !defined (DISABLE_SHARED_HANDLES) - if (_wapi_shm_enabled ()) - _wapi_collection_init (); -#endif + _wapi_io_init (); mono_os_mutex_init (&scan_mutex); @@ -295,22 +481,6 @@ wapi_cleanup (void) handle_cleanup (); } -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; - handle->handle_refs = 1; - - if (handle_specific != NULL) { - memcpy (&handle->u, handle_specific, sizeof (handle->u)); - } -} - static size_t _wapi_handle_struct_size (WapiHandleType type) { size_t type_size; @@ -369,68 +539,17 @@ static void _wapi_handle_init (struct _WapiHandleUnshared *handle, handle->signalled = FALSE; handle->ref = 1; - if (!_WAPI_SHARED_HANDLE(type)) { - thr_ret = pthread_cond_init (&handle->signal_cond, NULL); - g_assert (thr_ret == 0); - - thr_ret = mono_os_mutex_init (&handle->signal_mutex); - g_assert (thr_ret == 0); - - if (handle_specific != NULL) { - type_size = _wapi_handle_struct_size (type); - memcpy (&handle->u, handle_specific, - type_size); - } - } -} - -static guint32 _wapi_handle_new_shared (WapiHandleType type, - gpointer handle_specific) -{ - guint32 offset; - 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 */ - for(offset = last; offset <_WAPI_HANDLE_INITIAL_COUNT; offset++) { - struct _WapiHandleShared *handle = &_wapi_shared_layout->handles[offset]; - - if(handle->type == WAPI_HANDLE_UNUSED) { - thr_ret = _wapi_handle_lock_shared_handles (); - g_assert (thr_ret == 0); - - if (InterlockedCompareExchange ((gint32 *)&handle->type, type, WAPI_HANDLE_UNUSED) == WAPI_HANDLE_UNUSED) { - last = offset + 1; + thr_ret = mono_os_cond_init (&handle->signal_cond); + g_assert (thr_ret == 0); - _wapi_handle_init_shared (handle, type, - handle_specific); - - _wapi_handle_unlock_shared_handles (); - - return(offset); - } else { - /* Someone else beat us to it, just - * continue looking - */ - } - - _wapi_handle_unlock_shared_handles (); - } - } + thr_ret = mono_os_mutex_init (&handle->signal_mutex); + g_assert (thr_ret == 0); - if(last > 1) { - /* Try again from the beginning */ - last = 1; - goto again; + if (handle_specific != NULL) { + type_size = _wapi_handle_struct_size (type); + memcpy (&handle->u, handle_specific, + type_size); } - - /* Will need to expand the array. The caller will sort it out */ - - return(0); } /* @@ -500,7 +619,7 @@ _wapi_handle_new (WapiHandleType type, gpointer handle_specific) g_assert (_wapi_has_shut_down == FALSE); - DEBUG ("%s: Creating new handle of type %s", __func__, + MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Creating new handle of type %s", __func__, _wapi_handle_typename[type]); g_assert(!_WAPI_FD_HANDLE(type)); @@ -536,132 +655,9 @@ _wapi_handle_new (WapiHandleType type, gpointer handle_specific) handle = GUINT_TO_POINTER (handle_idx); - DEBUG ("%s: Allocated new handle %p", __func__, handle); - - if (_WAPI_SHARED_HANDLE(type)) { - /* Add the shared section too */ - guint32 ref; - - ref = _wapi_handle_new_shared (type, handle_specific); - if (ref == 0) { - _wapi_handle_collect (); - ref = _wapi_handle_new_shared (type, handle_specific); - if (ref == 0) { - /* FIXME: grow the arrays */ - handle = _WAPI_HANDLE_INVALID; - goto done; - } - } - - _WAPI_PRIVATE_HANDLES(handle_idx).u.shared.offset = ref; - DEBUG ("%s: New shared handle at offset 0x%x", __func__, - ref); - } - -done: - return(handle); -} + MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Allocated new handle %p", __func__, handle); -gpointer _wapi_handle_new_from_offset (WapiHandleType type, guint32 offset, - gboolean timestamp) -{ - guint32 handle_idx = 0; - gpointer handle = INVALID_HANDLE_VALUE; - int thr_ret, i, k; - struct _WapiHandleShared *shared; - - g_assert (_wapi_has_shut_down == FALSE); - - DEBUG ("%s: Creating new handle of type %s to offset %d", __func__, - _wapi_handle_typename[type], offset); - - g_assert(!_WAPI_FD_HANDLE(type)); - g_assert(_WAPI_SHARED_HANDLE(type)); - g_assert(offset != 0); - - 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); - } - - thr_ret = mono_os_mutex_lock (&scan_mutex); - g_assert (thr_ret == 0); - - 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; - } - } - } - } - -first_pass_done: - thr_ret = mono_os_mutex_unlock (&scan_mutex); - g_assert (thr_ret == 0); - - if (handle != INVALID_HANDLE_VALUE) { - _wapi_handle_ref (handle); - - DEBUG ("%s: Returning old handle %p referencing 0x%x", - __func__, handle, offset); - return (handle); - } - - /* Prevent entries expiring under us as we search */ - thr_ret = _wapi_handle_lock_shared_handles (); - g_assert (thr_ret == 0); - - if (shared->type == WAPI_HANDLE_UNUSED) { - /* Someone deleted this handle while we were working */ - DEBUG ("%s: Handle at 0x%x unused", __func__, offset); - goto done; - } - - if (shared->type != type) { - DEBUG ("%s: Wrong type at %d 0x%x! Found %s wanted %s", - __func__, offset, offset, - _wapi_handle_typename[shared->type], - _wapi_handle_typename[type]); - goto done; - } - - thr_ret = mono_os_mutex_lock (&scan_mutex); - g_assert (thr_ret == 0); - - while ((handle_idx = _wapi_handle_new_internal (type, NULL)) == 0) { - /* Try and expand the array, and have another go */ - int idx = SLOT_INDEX (_wapi_private_handle_count); - _wapi_private_handles [idx] = g_new0 (struct _WapiHandleUnshared, - _WAPI_HANDLE_INITIAL_COUNT); - - _wapi_private_handle_count += _WAPI_HANDLE_INITIAL_COUNT; - _wapi_private_handle_slot_count ++; - } - - thr_ret = mono_os_mutex_unlock (&scan_mutex); - g_assert (thr_ret == 0); - - /* Make sure we left the space for fd mappings */ - g_assert (handle_idx >= _wapi_fd_reserve); - - handle = GUINT_TO_POINTER (handle_idx); - - _WAPI_PRIVATE_HANDLES(handle_idx).u.shared.offset = offset; - InterlockedIncrement ((gint32 *)&shared->handle_refs); - - DEBUG ("%s: Allocated new handle %p referencing 0x%x (shared refs %d)", __func__, handle, offset, shared->handle_refs); - done: - _wapi_handle_unlock_shared_handles (); - return(handle); } @@ -691,14 +687,13 @@ gpointer _wapi_handle_new_fd (WapiHandleType type, int fd, g_assert (_wapi_has_shut_down == FALSE); - DEBUG ("%s: Creating new handle of type %s", __func__, + MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Creating new handle of type %s", __func__, _wapi_handle_typename[type]); g_assert(_WAPI_FD_HANDLE(type)); - g_assert(!_WAPI_SHARED_HANDLE(type)); - + if (fd >= _wapi_fd_reserve) { - DEBUG ("%s: fd %d is too big", __func__, fd); + MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: fd %d is too big", __func__, fd); return(GUINT_TO_POINTER (_WAPI_HANDLE_INVALID)); } @@ -710,13 +705,13 @@ gpointer _wapi_handle_new_fd (WapiHandleType type, int fd, handle = &_WAPI_PRIVATE_HANDLES(fd); if (handle->type != WAPI_HANDLE_UNUSED) { - DEBUG ("%s: fd %d is already in use!", __func__, fd); + MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%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 */ } - DEBUG ("%s: Assigning new fd handle %d", __func__, fd); + MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Assigning new fd handle %d", __func__, fd); /* Prevent file share entries racing with us, when the file * handle is only half initialised @@ -731,7 +726,8 @@ gpointer _wapi_handle_new_fd (WapiHandleType type, int fd, return(GUINT_TO_POINTER(fd)); } -gboolean _wapi_lookup_handle (gpointer handle, WapiHandleType type, +gboolean +_wapi_lookup_handle (gpointer handle, WapiHandleType type, gpointer *handle_specific) { struct _WapiHandleUnshared *handle_data; @@ -755,23 +751,7 @@ gboolean _wapi_lookup_handle (gpointer handle, WapiHandleType type, return(FALSE); } - if (_WAPI_SHARED_HANDLE(type)) { - struct _WapiHandle_shared_ref *ref; - struct _WapiHandleShared *shared_handle_data; - - ref = &handle_data->u.shared; - shared_handle_data = &_wapi_shared_layout->handles[ref->offset]; - - if (shared_handle_data->type != type) { - /* The handle must have been deleted on us - */ - return (FALSE); - } - - *handle_specific = &shared_handle_data->u; - } else { - *handle_specific = &handle_data->u; - } + *handle_specific = &handle_data->u; return(TRUE); } @@ -822,7 +802,6 @@ gpointer _wapi_search_handle (WapiHandleType type, gboolean search_shared) { struct _WapiHandleUnshared *handle_data = NULL; - struct _WapiHandleShared *shared = NULL; gpointer ret = NULL; guint32 i, k; gboolean found = FALSE; @@ -841,11 +820,6 @@ gpointer _wapi_search_handle (WapiHandleType type, if (check (ret, user_data) == TRUE) { _wapi_handle_ref (ret); found = TRUE; - - if (_WAPI_SHARED_HANDLE (type)) { - shared = &_wapi_shared_layout->handles[i]; - } - break; } } @@ -856,152 +830,84 @@ gpointer _wapi_search_handle (WapiHandleType type, thr_ret = mono_os_mutex_unlock (&scan_mutex); g_assert (thr_ret == 0); - if (!found && search_shared && _WAPI_SHARED_HANDLE (type)) { - /* Not found yet, so search the shared memory too */ - DEBUG ("%s: Looking at other shared handles...", __func__); - - for (i = 0; i < _WAPI_HANDLE_INITIAL_COUNT; i++) { - shared = &_wapi_shared_layout->handles[i]; - - if (shared->type == type) { - /* Tell new_from_offset to not - * timestamp this handle, because - * otherwise it will ping every handle - * in the list and they will never - * expire - */ - ret = _wapi_handle_new_from_offset (type, i, - FALSE); - if (ret == INVALID_HANDLE_VALUE) { - /* This handle was deleted - * while we were looking at it - */ - continue; - } - - 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 - * away (after new_from_offset - * successfully opened it,) if its - * timestamp is too old. The check - * function needs to be aware of this, - * and cope if the handle has - * vanished. - */ - if (check (ret, user_data) == TRUE) { - /* Timestamp this handle, but make - * sure it still exists first - */ - thr_ret = _wapi_handle_lock_shared_handles (); - g_assert (thr_ret == 0); - - if (shared->type == type) { - guint32 now = (guint32)(time (NULL) & 0xFFFFFFFF); - InterlockedExchange ((gint32 *)&shared->timestamp, now); - - found = TRUE; - handle_data = &_WAPI_PRIVATE_HANDLES(GPOINTER_TO_UINT(ret)); - - _wapi_handle_unlock_shared_handles (); - break; - } else { - /* It's been deleted, - * so just keep - * looking - */ - _wapi_handle_unlock_shared_handles (); - } - } - - /* 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) { ret = NULL; goto done; } if(handle_specific != NULL) { - if (_WAPI_SHARED_HANDLE(type)) { - g_assert(shared->type == type); - - *handle_specific = &shared->u; - } else { - *handle_specific = &handle_data->u; - } + *handle_specific = &handle_data->u; } done: return(ret); } -/* Returns the offset of the metadata array, or -1 on error, or 0 for - * not found (0 is not a valid offset) +/* Returns the offset of the metadata array, or _WAPI_HANDLE_INVALID on error, or NULL for + * not found */ -gint32 _wapi_search_handle_namespace (WapiHandleType type, +gpointer _wapi_search_handle_namespace (WapiHandleType type, gchar *utf8_name) { - struct _WapiHandleShared *shared_handle_data; - guint32 i; - gint32 ret = 0; + struct _WapiHandleUnshared *handle_data; + guint32 i, k; + gpointer ret = NULL; int thr_ret; - g_assert(_WAPI_SHARED_HANDLE(type)); + g_assert(_WAPI_SHARED_NAMESPACE(type)); - DEBUG ("%s: Lookup for handle named [%s] type %s", __func__, + MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Lookup for handle named [%s] type %s", __func__, utf8_name, _wapi_handle_typename[type]); - /* Do a handle collection before starting to look, so that any - * stale cruft gets removed - */ - _wapi_handle_collect (); - - thr_ret = _wapi_handle_lock_shared_handles (); + thr_ret = mono_os_mutex_lock (&scan_mutex); g_assert (thr_ret == 0); - for(i = 1; i < _WAPI_HANDLE_INITIAL_COUNT; i++) { - WapiSharedNamespace *sharedns; - - shared_handle_data = &_wapi_shared_layout->handles[i]; - - /* Check mutex, event, semaphore, timer, job and - * file-mapping object names. So far only mutex, - * semaphore and event are implemented. - */ - if (!_WAPI_SHARED_NAMESPACE (shared_handle_data->type)) { + for(i = SLOT_INDEX (0); i < _wapi_private_handle_slot_count; i++) { + if (!_wapi_private_handles [i]) continue; - } + for (k = SLOT_OFFSET (0); k < _WAPI_HANDLE_INITIAL_COUNT; k++) { + WapiSharedNamespace *sharedns; + + handle_data = &_wapi_private_handles [i][k]; - DEBUG ("%s: found a shared namespace handle at 0x%x (type %s)", __func__, i, _wapi_handle_typename[shared_handle_data->type]); + /* Check mutex, event, semaphore, timer, job and + * file-mapping object names. So far only mutex, + * semaphore and event are implemented. + */ + if (!_WAPI_SHARED_NAMESPACE (handle_data->type)) { + continue; + } - sharedns=(WapiSharedNamespace *)&shared_handle_data->u; - - 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 */ - 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 { - DEBUG ("%s: handle 0x%x matches name and type", __func__, i); - ret = i; - goto done; + MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: found a shared namespace handle at 0x%x (type %s)", __func__, i, _wapi_handle_typename[handle_data->type]); + + switch (handle_data->type) { + case WAPI_HANDLE_NAMEDMUTEX: sharedns = &handle_data->u.namedmutex.sharedns; break; + case WAPI_HANDLE_NAMEDSEM: sharedns = &handle_data->u.namedsem.sharedns; break; + case WAPI_HANDLE_NAMEDEVENT: sharedns = &handle_data->u.namedevent.sharedns; break; + default: + g_assert_not_reached (); + } + + MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: name is [%s]", __func__, sharedns->name); + + if (strcmp (sharedns->name, utf8_name) == 0) { + if (handle_data->type != type) { + /* Its the wrong type, so fail now */ + MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: handle 0x%x matches name but is wrong type: %s", __func__, i, _wapi_handle_typename[handle_data->type]); + ret = _WAPI_HANDLE_INVALID; + goto done; + } else { + MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: handle 0x%x matches name and type", __func__, i); + ret = handle_data; + goto done; + } } } } done: - _wapi_handle_unlock_shared_handles (); + thr_ret = mono_os_mutex_unlock (&scan_mutex); + g_assert (thr_ret == 0); return(ret); } @@ -1012,29 +918,18 @@ void _wapi_handle_ref (gpointer handle) struct _WapiHandleUnshared *handle_data; if (!_WAPI_PRIVATE_VALID_SLOT (idx)) { + MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Attempting to ref invalid private handle %p", __func__, handle); return; } if (_wapi_handle_type (handle) == WAPI_HANDLE_UNUSED) { - g_warning ("%s: Attempting to ref unused handle %p", __func__, - handle); + MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Attempting to ref unused handle %p", __func__, handle); return; } handle_data = &_WAPI_PRIVATE_HANDLES(idx); InterlockedIncrement ((gint32 *)&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 _WapiHandleShared *shared_data = &_wapi_shared_layout->handles[handle_data->u.shared.offset]; - guint32 now = (guint32)(time (NULL) & 0xFFFFFFFF); - InterlockedExchange ((gint32 *)&shared_data->timestamp, now); - } #ifdef DEBUG_REFS g_message ("%s: %s handle %p ref now %d", __func__, @@ -1083,23 +978,12 @@ static void _wapi_handle_unref_full (gpointer handle, gboolean ignore_private_bu * same fd racing the memset()) */ struct _WapiHandleUnshared handle_data; - struct _WapiHandleShared shared_handle_data; WapiHandleType type = _WAPI_PRIVATE_HANDLES(idx).type; void (*close_func)(gpointer, gpointer) = _wapi_handle_ops_get_close_func (type); - gboolean is_shared = _WAPI_SHARED_HANDLE(type); - if (is_shared) { - /* If this is a shared handle we need to take - * the shared lock outside of the scan_mutex - * lock to avoid deadlocks - */ - thr_ret = _wapi_handle_lock_shared_handles (); - g_assert (thr_ret == 0); - } - thr_ret = mono_os_mutex_lock (&scan_mutex); - DEBUG ("%s: Destroying handle %p", __func__, handle); + MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Destroying handle %p", __func__, handle); memcpy (&handle_data, &_WAPI_PRIVATE_HANDLES(idx), sizeof (struct _WapiHandleUnshared)); @@ -1108,46 +992,25 @@ static void _wapi_handle_unref_full (gpointer handle, gboolean ignore_private_bu sizeof(_WAPI_PRIVATE_HANDLES(idx).u)); _WAPI_PRIVATE_HANDLES(idx).type = WAPI_HANDLE_UNUSED; - - if (!is_shared) { - /* 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_os_mutex_destroy (&_WAPI_PRIVATE_HANDLES(idx).signal_mutex); - /*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]; - memcpy (&shared_handle_data, shared, - sizeof (struct _WapiHandleShared)); - - /* It's possible that this handle is already - * pointing at a deleted shared section - */ -#ifdef DEBUG_REFS - g_message ("%s: %s handle %p shared refs before dec %d", __func__, _wapi_handle_typename[type], handle, shared->handle_refs); -#endif + /* 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_os_mutex_destroy (&_WAPI_PRIVATE_HANDLES(idx).signal_mutex); + /*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); - if (shared->handle_refs > 0) { - shared->handle_refs--; - if (shared->handle_refs == 0) { - memset (shared, '\0', sizeof (struct _WapiHandleShared)); - } - } + thr_ret = mono_os_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); } thr_ret = mono_os_mutex_unlock (&scan_mutex); @@ -1155,16 +1018,9 @@ static void _wapi_handle_unref_full (gpointer handle, gboolean ignore_private_bu if (early_exit) return; - if (is_shared) { - _wapi_handle_unlock_shared_handles (); - } if (close_func != NULL) { - if (is_shared) { - close_func (handle, &shared_handle_data.u); - } else { - close_func (handle, &handle_data.u); - } + close_func (handle, &handle_data.u); } } } @@ -1192,7 +1048,7 @@ gboolean _wapi_handle_test_capabilities (gpointer handle, type = _WAPI_PRIVATE_HANDLES(idx).type; - DEBUG ("%s: testing 0x%x against 0x%x (%d)", __func__, + MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: testing 0x%x against 0x%x (%d)", __func__, handle_caps[type], caps, handle_caps[type] & caps); return((handle_caps[type] & caps) != 0); @@ -1386,14 +1242,11 @@ gboolean _wapi_handle_count_signalled_handles (guint32 numhandles, /* Lock all the handles, with backoff */ again: - thr_ret = _wapi_handle_lock_shared_handles (); - g_assert (thr_ret == 0); - for(i=0; ii) { *lowest=i; @@ -1464,7 +1311,7 @@ again: } } - DEBUG ("%s: %d event handles signalled", __func__, count); + MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: %d event handles signalled", __func__, count); if ((waitall == TRUE && count == numhandles) || (waitall == FALSE && count > 0)) { @@ -1473,7 +1320,7 @@ again: ret=FALSE; } - DEBUG ("%s: Returning %d", __func__, ret); + MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Returning %d", __func__, ret); *retcount=count; @@ -1485,29 +1332,20 @@ void _wapi_handle_unlock_handles (guint32 numhandles, gpointer *handles) guint32 i; int thr_ret; - thr_ret = _wapi_handle_unlock_shared_handles (); - g_assert (thr_ret == 0); - for(i=0; idevice == s2->device && s1->inode == s2->inode) ? 1 : 0; } @@ -1645,7 +1460,7 @@ wapi_share_info_equal (gconstpointer ka, gconstpointer kb) static guint wapi_share_info_hash (gconstpointer data) { - const _WapiFileShare *s = data; + const _WapiFileShare *s = (const _WapiFileShare *)data; return s->inode; } @@ -1658,242 +1473,58 @@ gboolean _wapi_handle_get_or_set_share (guint64 device, guint64 inode, struct _WapiFileShare **share_info) { struct _WapiFileShare *file_share; - guint32 now = (guint32)(time(NULL) & 0xFFFFFFFF); - int thr_ret, i, first_unused = -1; + int thr_ret; gboolean exists = FALSE; - /* Prevents entries from expiring under us as we search - */ - 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); - 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 (!file_share_hash) { - file_share_hash = g_hash_table_new_full (wapi_share_info_hash, wapi_share_info_equal, NULL, g_free); - mono_os_mutex_init_recursive (&file_share_hash_mutex); - } - - 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; - - InterlockedIncrement ((gint32 *)&file_share->handle_refs); - exists = TRUE; - } else { - file_share = g_new0 (_WapiFileShare, 1); - - 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; - - 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]; + _WapiFileShare tmp; - /* 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); - - _wapi_handle_unlock_shared_handles (); - - 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 defined(__native_client__) - g_assert_not_reached (); -#elif defined(HAVE_KILL) - 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 - */ - DEBUG ("%s: Didn't find it, destroying entry", __func__); - - _wapi_free_share_info (share_info); - } -#endif -} - -#ifdef __linux__ -/* Scan /proc//fd/ for open file descriptors to the file in - * question. If there are none, reset the share info. - * - * This implementation is Linux-specific; legacy systems will have to - * implement their own ways of finding out if a particular file is - * open by a process. - */ -void _wapi_handle_check_share (struct _WapiFileShare *share_info, int fd) -{ - gboolean found = FALSE, proc_fds = FALSE; - int thr_ret, i; - - /* Prevents entries from expiring under us if we remove this - * one + /* + * 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. */ - 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); - - /* 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); - goto done; + if (!file_share_hash) { + file_share_hash = g_hash_table_new_full (wapi_share_info_hash, wapi_share_info_equal, NULL, g_free); + mono_os_mutex_init_recursive (&file_share_hash_mutex); } - /* If there's another handle that thinks it owns this fd, then even - * if the fd has been closed behind our back consider it still owned. - * See bugs 75764 and 75891 - */ - for (i = 0; i < _wapi_fd_reserve; i++) { - if (_wapi_private_handles [SLOT_INDEX (i)]) { - struct _WapiHandleUnshared *handle = &_WAPI_PRIVATE_HANDLES(i); + tmp.device = device; + tmp.inode = inode; - if (i != fd && - handle->type == WAPI_HANDLE_FILE) { - struct _WapiHandle_file *file_handle = &handle->u.file; + file_share_hash_lock (); - if (file_handle->share_info == share_info) { - DEBUG ("%s: handle 0x%x has this file open!", - __func__, i); + file_share = (_WapiFileShare *)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; - goto done; - } - } - } - } + InterlockedIncrement ((gint32 *)&file_share->handle_refs); + exists = TRUE; + } else { + file_share = g_new0 (_WapiFileShare, 1); - if (proc_fds == FALSE) { - _wapi_handle_check_share_by_pid (share_info); - } else if (found == FALSE) { - /* Blank out this entry, as it is stale */ - DEBUG ("%s: Didn't find it, destroying entry", __func__); + 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; - _wapi_free_share_info (share_info); + g_hash_table_insert (file_share_hash, file_share, file_share); } -done: - thr_ret = _wapi_shm_sem_unlock (_WAPI_SHARED_SEM_FILESHARE); - - _wapi_handle_unlock_shared_handles (); -} -#else -// -// Other implementations (non-Linux) -// -void _wapi_handle_check_share (struct _WapiFileShare *share_info, int fd) -{ - int thr_ret; + file_share_hash_unlock (); - /* 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 (); + + return(exists); } -#endif void _wapi_handle_dump (void) { @@ -1935,57 +1566,3 @@ static void _wapi_shared_details (gpointer handle_info) g_print ("offset: 0x%x", shared->offset); } - -void _wapi_handle_update_refs (void) -{ - guint32 i, k; - int thr_ret; - guint32 now = (guint32)(time (NULL) & 0xFFFFFFFF); - - thr_ret = _wapi_handle_lock_shared_handles (); - g_assert (thr_ret == 0); - - /* Prevent file share entries racing with us */ - thr_ret = _wapi_shm_sem_lock (_WAPI_SHARED_SEM_FILESHARE); - g_assert(thr_ret == 0); - - thr_ret = mono_os_mutex_lock (&scan_mutex); - - 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; - - 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]; - - 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; - - DEBUG ("%s: (%d) handle 0x%x is FILE", __func__, _wapi_getpid (), i * _WAPI_HANDLE_INITIAL_COUNT + k); - - g_assert (file_handle->share_info != NULL); - - 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); - } - } - } - } - - thr_ret = mono_os_mutex_unlock (&scan_mutex); - g_assert (thr_ret == 0); - - thr_ret = _wapi_shm_sem_unlock (_WAPI_SHARED_SEM_FILESHARE); - - _wapi_handle_unlock_shared_handles (); -} -