X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mono%2Fio-layer%2Fmutexes.c;h=e4f51eb6280fe41f2b01ee3246a1913c4a727763;hb=3c666ed0337fc5bbbbb5ec6322826573d5509297;hp=36f98f3071e0a4d346d7732016332f501ed9512c;hpb=7e18ed47c9606f3981e7b18cbc238d6781843153;p=mono.git diff --git a/mono/io-layer/mutexes.c b/mono/io-layer/mutexes.c index 36f98f3071e..e4f51eb6280 100644 --- a/mono/io-layer/mutexes.c +++ b/mono/io-layer/mutexes.c @@ -4,7 +4,7 @@ * Author: * Dick Porter (dick@ximian.com) * - * (C) 2002 Ximian, Inc. + * (C) 2002-2006 Ximian, Inc. */ #include @@ -29,12 +29,15 @@ static gboolean mutex_is_owned (gpointer handle); static void namedmutex_signal (gpointer handle); static gboolean namedmutex_own (gpointer handle); static gboolean namedmutex_is_owned (gpointer handle); +static void namedmutex_prewait (gpointer handle); struct _WapiHandleOps _wapi_mutex_ops = { NULL, /* close */ mutex_signal, /* signal */ mutex_own, /* own */ mutex_is_owned, /* is_owned */ + NULL, /* special_wait */ + NULL /* prewait */ }; void _wapi_mutex_details (gpointer handle_info) @@ -55,6 +58,8 @@ struct _WapiHandleOps _wapi_namedmutex_ops = { namedmutex_signal, /* signal */ namedmutex_own, /* own */ namedmutex_is_owned, /* is_owned */ + NULL, /* special_wait */ + namedmutex_prewait /* prewait */ }; static gboolean mutex_release (gpointer handle); @@ -110,7 +115,7 @@ static gboolean mutex_own (gpointer handle) return(FALSE); } - _wapi_thread_own_mutex (pthread_self (), handle); + _wapi_thread_own_mutex (handle); #ifdef DEBUG g_message("%s: owning mutex handle %p", __func__, handle); @@ -118,7 +123,7 @@ static gboolean mutex_own (gpointer handle) _wapi_handle_set_signal_state (handle, FALSE, FALSE); - mutex_handle->pid = getpid (); + mutex_handle->pid = _wapi_getpid (); mutex_handle->tid = pthread_self (); mutex_handle->recursion++; @@ -149,17 +154,17 @@ static gboolean mutex_is_owned (gpointer handle) #endif if (mutex_handle->recursion > 0 && - mutex_handle->pid == getpid () && - mutex_handle->tid == pthread_self ()) { + mutex_handle->pid == _wapi_getpid () && + pthread_equal (mutex_handle->tid, pthread_self ())) { #ifdef DEBUG g_message ("%s: mutex handle %p owned by %d:%ld", __func__, - handle, getpid (), pthread_self ()); + handle, _wapi_getpid (), pthread_self ()); #endif return(TRUE); } else { #ifdef DEBUG - g_message ("%s: mutex handle %p not owned by %d:%ld, but locked %d times by %d:%ld", __func__, handle, getpid (), pthread_self (), mutex_handle->recursion, mutex_handle->pid, mutex_handle->tid); + g_message ("%s: mutex handle %p not owned by %d:%ld, but locked %d times by %d:%ld", __func__, handle, _wapi_getpid (), pthread_self (), mutex_handle->recursion, mutex_handle->pid, mutex_handle->tid); #endif return(FALSE); @@ -189,9 +194,9 @@ static gboolean namedmutex_own (gpointer handle) return(FALSE); } - _wapi_thread_own_mutex (pthread_self (), handle); + _wapi_thread_own_mutex (handle); - namedmutex_handle->pid = getpid (); + namedmutex_handle->pid = _wapi_getpid (); namedmutex_handle->tid = pthread_self (); namedmutex_handle->recursion++; @@ -224,23 +229,130 @@ static gboolean namedmutex_is_owned (gpointer handle) #endif if (namedmutex_handle->recursion > 0 && - namedmutex_handle->pid == getpid () && - namedmutex_handle->tid == pthread_self ()) { + namedmutex_handle->pid == _wapi_getpid () && + pthread_equal (namedmutex_handle->tid, pthread_self ())) { #ifdef DEBUG g_message ("%s: mutex handle %p owned by %d:%ld", __func__, - handle, getpid (), pthread_self ()); + handle, _wapi_getpid (), pthread_self ()); #endif return(TRUE); } else { #ifdef DEBUG - g_message ("%s: mutex handle %p not owned by %d:%ld, but locked %d times by %d:%ld", __func__, handle, getpid (), pthread_self (), namedmutex_handle->recursion, namedmutex_handle->pid, namedmutex_handle->tid); + g_message ("%s: mutex handle %p not owned by %d:%ld, but locked %d times by %d:%ld", __func__, handle, _wapi_getpid (), pthread_self (), namedmutex_handle->recursion, namedmutex_handle->pid, namedmutex_handle->tid); #endif return(FALSE); } } +/* The shared state is not locked when prewait methods are called */ +static void namedmutex_prewait (gpointer handle) +{ + /* If the mutex is not currently owned, do nothing and let the + * usual wait carry on. If it is owned, check that the owner + * is still alive; if it isn't we override the previous owner + * and assume that process exited abnormally and failed to + * clean up. + */ + struct _WapiHandle_namedmutex *namedmutex_handle; + gboolean ok; + + ok = _wapi_lookup_handle (handle, WAPI_HANDLE_NAMEDMUTEX, + (gpointer *)&namedmutex_handle); + if (ok == FALSE) { + g_warning ("%s: error looking up named mutex handle %p", + __func__, handle); + return; + } + +#ifdef DEBUG + g_message ("%s: Checking ownership of named mutex handle %p", __func__, + handle); +#endif + + if (namedmutex_handle->recursion == 0) { +#ifdef DEBUG + g_message ("%s: Named mutex handle %p not owned", __func__, + handle); +#endif + } else if (namedmutex_handle->pid == _wapi_getpid ()) { +#ifdef DEBUG + g_message ("%s: Named mutex handle %p owned by this process", + __func__, handle); +#endif + } else { + guint32 *pids = g_new0 (guint32, 32); + guint32 count = 32, needed_bytes, i; + gboolean ret; + int thr_ret; + +#ifdef DEBUG + g_message ("%s: Named mutex handle %p owned by another process", __func__, handle); +#endif + + ret = EnumProcesses (pids, count * sizeof(guint32), + &needed_bytes); + if (ret == FALSE) { + do { + count = needed_bytes / sizeof(guint32); +#ifdef DEBUG + g_message ("%s: Retrying pid lookup with %d slots", __func__, count); +#endif + pids = g_renew (guint32, pids, count); + ret = EnumProcesses (pids, needed_bytes, + &needed_bytes); + } while (ret == FALSE); + } + + count = needed_bytes / sizeof(guint32); + +#ifdef DEBUG + g_message ("%s: Need to look at %d pids for named mutex handle %p", __func__, count, handle); +#endif + + thr_ret = _wapi_handle_lock_shared_handles (); + g_assert (thr_ret == 0); + + for (i = 0; i < count; i++) { +#ifdef DEBUG + g_message ("%s: Checking pid %d for named mutex handle %p", __func__, pids[i], handle); +#endif + + if (pids[i] == namedmutex_handle->pid) { + /* Must be still alive, because + * EnumProcesses() checks for us + */ +#ifdef DEBUG + g_message ("%s: Found active pid %d for named mutex handle %p", __func__, pids[i], handle); +#endif + + break; + } + } + + g_free (pids); + + if (i == count) { + /* Didn't find the process that this handle + * was owned by, overriding it + */ + +#ifdef DEBUG + g_message ("%s: overriding old owner of named mutex handle %p", __func__, handle); +#endif + + namedmutex_handle->pid = 0; + namedmutex_handle->tid = 0; + namedmutex_handle->recursion = 0; + + _wapi_shared_handle_set_signal_state (handle, TRUE); + } + + _wapi_handle_unlock_shared_handles (); + } +} + static void mutex_abandon (gpointer handle, pid_t pid, pthread_t tid) { struct _WapiHandle_mutex *mutex_handle; @@ -261,7 +373,7 @@ static void mutex_abandon (gpointer handle, pid_t pid, pthread_t tid) g_assert (thr_ret == 0); if (mutex_handle->pid == pid && - mutex_handle->tid == tid) { + pthread_equal (mutex_handle->tid, tid)) { #ifdef DEBUG g_message ("%s: Mutex handle %p abandoned!", __func__, handle); #endif @@ -296,7 +408,7 @@ static void namedmutex_abandon (gpointer handle, pid_t pid, pthread_t tid) g_assert (thr_ret == 0); if (mutex_handle->pid == pid && - mutex_handle->tid == tid) { + pthread_equal (mutex_handle->tid, tid)) { #ifdef DEBUG g_message ("%s: Mutex handle %p abandoned!", __func__, handle); #endif @@ -385,10 +497,9 @@ static gpointer namedmutex_create (WapiSecurityAttributes *security G_GNUC_UNUSE guint32 namelen; gint32 offset; - /* w32 seems to guarantee that opening named mutexes can't + /* w32 seems to guarantee that opening named objects can't * race each other */ - pthread_cleanup_push ((void(*)(void *))_wapi_namespace_unlock, NULL); thr_ret = _wapi_namespace_lock (); g_assert (thr_ret == 0); @@ -419,19 +530,20 @@ static gpointer namedmutex_create (WapiSecurityAttributes *security G_GNUC_UNUSE SetLastError (ERROR_ALREADY_EXISTS); } /* Fall through to create the mutex handle. */ - - if (strlen (utf8_name) < MAX_PATH) { - namelen = strlen (utf8_name); - } else { - namelen = MAX_PATH; - } - - memcpy (&namedmutex_handle.sharedns.name, utf8_name, namelen); if (offset == 0) { /* A new named mutex, so create both the private and * shared parts */ + + if (strlen (utf8_name) < MAX_PATH) { + namelen = strlen (utf8_name); + } else { + namelen = MAX_PATH; + } + + memcpy (&namedmutex_handle.sharedns.name, utf8_name, namelen); + handle = _wapi_handle_new (WAPI_HANDLE_NAMEDMUTEX, &namedmutex_handle); } else { @@ -473,7 +585,6 @@ cleanup: g_free (utf8_name); _wapi_namespace_unlock (NULL); - pthread_cleanup_pop (0); return(ret); } @@ -513,8 +624,8 @@ static gboolean mutex_release (gpointer handle) { struct _WapiHandle_mutex *mutex_handle; gboolean ok; - pthread_t tid=pthread_self(); - pid_t pid=getpid (); + pthread_t tid = pthread_self (); + pid_t pid = _wapi_getpid (); int thr_ret; gboolean ret = FALSE; @@ -535,9 +646,10 @@ static gboolean mutex_release (gpointer handle) g_message("%s: Releasing mutex handle %p", __func__, handle); #endif - if(mutex_handle->tid!=tid || mutex_handle->pid!=pid) { + if (!pthread_equal (mutex_handle->tid, tid) || + mutex_handle->pid != pid) { #ifdef DEBUG - g_message("%s: We don't own mutex handle %p (owned by %d:%ld, me %d:%ld)", __func__, handle, mutex_handle->pid, mutex_handle->tid, pid, tid); + g_message("%s: We don't own mutex handle %p (owned by %d:%ld, me %d:%ld)", __func__, handle, mutex_handle->pid, mutex_handle->tid, _wapi_getpid (), tid); #endif goto cleanup; @@ -548,7 +660,7 @@ static gboolean mutex_release (gpointer handle) mutex_handle->recursion--; if(mutex_handle->recursion==0) { - _wapi_thread_disown_mutex (tid, handle); + _wapi_thread_disown_mutex (handle); #ifdef DEBUG g_message("%s: Unlocking mutex handle %p", __func__, handle); @@ -571,8 +683,8 @@ static gboolean namedmutex_release (gpointer handle) { struct _WapiHandle_namedmutex *mutex_handle; gboolean ok; - pthread_t tid=pthread_self(); - pid_t pid=getpid (); + pthread_t tid = pthread_self (); + pid_t pid = _wapi_getpid (); int thr_ret; gboolean ret = FALSE; @@ -591,9 +703,10 @@ static gboolean namedmutex_release (gpointer handle) g_message("%s: Releasing mutex handle %p", __func__, handle); #endif - if(mutex_handle->tid!=tid || mutex_handle->pid!=pid) { + if (!pthread_equal (mutex_handle->tid, tid) || + mutex_handle->pid != pid) { #ifdef DEBUG - g_message("%s: We don't own mutex handle %p (owned by %d:%ld, me %d:%ld)", __func__, handle, mutex_handle->pid, mutex_handle->tid, pid, tid); + g_message("%s: We don't own mutex handle %p (owned by %d:%ld, me %d:%ld)", __func__, handle, mutex_handle->pid, mutex_handle->tid, _wapi_getpid (), tid); #endif goto cleanup; @@ -604,7 +717,7 @@ static gboolean namedmutex_release (gpointer handle) mutex_handle->recursion--; if(mutex_handle->recursion==0) { - _wapi_thread_disown_mutex (tid, handle); + _wapi_thread_disown_mutex (handle); #ifdef DEBUG g_message("%s: Unlocking mutex handle %p", __func__, handle); @@ -648,3 +761,64 @@ gboolean ReleaseMutex(gpointer handle) return(mutex_ops[type].release (handle)); } + +gpointer OpenMutex (guint32 access G_GNUC_UNUSED, gboolean inherit G_GNUC_UNUSED, const gunichar2 *name) +{ + gpointer handle; + gchar *utf8_name; + int thr_ret; + gpointer ret = NULL; + gint32 offset; + + mono_once (&mutex_ops_once, mutex_ops_init); + + /* w32 seems to guarantee that opening named objects can't + * race each other + */ + thr_ret = _wapi_namespace_lock (); + g_assert (thr_ret == 0); + + utf8_name = g_utf16_to_utf8 (name, -1, NULL, NULL, NULL); + +#ifdef DEBUG + g_message ("%s: Opening named mutex [%s]", __func__, utf8_name); +#endif + + offset = _wapi_search_handle_namespace (WAPI_HANDLE_NAMEDMUTEX, + utf8_name); + if (offset == -1) { + /* The name has already been used for a different + * object. + */ + SetLastError (ERROR_INVALID_HANDLE); + goto cleanup; + } else if (offset == 0) { + /* This name doesn't exist */ + SetLastError (ERROR_FILE_NOT_FOUND); /* yes, really */ + goto cleanup; + } + + /* A new reference to an existing named mutex, so just create + * the private part + */ + handle = _wapi_handle_new_from_offset (WAPI_HANDLE_NAMEDMUTEX, offset, + TRUE); + + if (handle == _WAPI_HANDLE_INVALID) { + g_warning ("%s: error opening named mutex handle", __func__); + SetLastError (ERROR_GEN_FAILURE); + goto cleanup; + } + ret = handle; + +#ifdef DEBUG + g_message ("%s: returning named mutex handle %p", __func__, handle); +#endif + +cleanup: + g_free (utf8_name); + + _wapi_namespace_unlock (NULL); + + return(ret); +}