static gboolean mutex_is_owned (gpointer handle) { struct _WapiHandle_mutex *mutex_handle; gboolean ok; ok=_wapi_lookup_handle (handle, WAPI_HANDLE_MUTEX, (gpointer *)&mutex_handle); if(ok==FALSE) { g_warning ("%s: error looking up mutex handle %p", __func__, handle); return(FALSE); } #ifdef DEBUG g_message("%s: testing ownership mutex handle %p", __func__, handle); #endif if (mutex_handle->recursion > 0 && 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, _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, _wapi_getpid (), pthread_self (), mutex_handle->recursion, mutex_handle->pid, mutex_handle->tid); #endif return(FALSE); } }
static gboolean namedmutex_is_owned (gpointer handle) { 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 mutex handle %p", __func__, handle); return(FALSE); } DEBUG ("%s: testing ownership mutex handle %p", __func__, handle); if (namedmutex_handle->recursion > 0 && namedmutex_handle->pid == _wapi_getpid () && pthread_equal (namedmutex_handle->tid, pthread_self ())) { DEBUG ("%s: mutex handle %p owned by %d:%ld", __func__, handle, _wapi_getpid (), pthread_self ()); return(TRUE); } else { DEBUG ("%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); return(FALSE); } }
/* NB, always called with the shared handle lock held */ static gboolean namedmutex_own (gpointer handle) { struct _WapiHandle_namedmutex *namedmutex_handle; gboolean ok; DEBUG ("%s: owning named mutex handle %p", __func__, handle); 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(FALSE); } _wapi_thread_own_mutex (handle); namedmutex_handle->pid = _wapi_getpid (); namedmutex_handle->tid = pthread_self (); namedmutex_handle->recursion++; _wapi_shared_handle_set_signal_state (handle, FALSE); DEBUG ("%s: mutex handle %p locked %d times by %d:%ld", __func__, handle, namedmutex_handle->recursion, namedmutex_handle->pid, namedmutex_handle->tid); return(TRUE); }
static gboolean mutex_own (gpointer handle) { struct _WapiHandle_mutex *mutex_handle; gboolean ok; ok = _wapi_lookup_handle (handle, WAPI_HANDLE_MUTEX, (gpointer *)&mutex_handle); if (ok == FALSE) { g_warning ("%s: error looking up mutex handle %p", __func__, handle); return(FALSE); } _wapi_thread_own_mutex (handle); #ifdef DEBUG g_message("%s: owning mutex handle %p", __func__, handle); #endif _wapi_handle_set_signal_state (handle, FALSE, FALSE); mutex_handle->pid = _wapi_getpid (); mutex_handle->tid = pthread_self (); mutex_handle->recursion++; #ifdef DEBUG g_message ("%s: mutex handle %p locked %d times by %d:%ld", __func__, handle, mutex_handle->recursion, mutex_handle->pid, mutex_handle->tid); #endif return(TRUE); }
static void shm_semaphores_remove (void) { int thr_ret; int proc_count; gchar *shm_name; DEBUGLOG ("%s: Checking process count (%d)", __func__, _wapi_getpid ()); thr_ret = _wapi_shm_sem_lock (_WAPI_SHARED_SEM_PROCESS_COUNT_LOCK); g_assert (thr_ret == 0); proc_count = semctl (_wapi_sem_id, _WAPI_SHARED_SEM_PROCESS_COUNT, GETVAL); g_assert (proc_count > 0); if (proc_count == 1) { /* * Just us, so blow away the semaphores and the shared * files */ DEBUGLOG ("%s: Removing semaphores! (%d)", __func__, _wapi_getpid ()); semctl (_wapi_sem_id, 0, IPC_RMID); #ifdef USE_SHM shm_name = _wapi_shm_shm_name (WAPI_SHM_DATA); shm_unlink (shm_name); g_free (shm_name); shm_name = _wapi_shm_shm_name (WAPI_SHM_FILESHARE); shm_unlink (shm_name); g_free (shm_name); #endif unlink (_wapi_shm_file (WAPI_SHM_DATA)); unlink (_wapi_shm_file (WAPI_SHM_FILESHARE)); } else { /* * "else" clause, because there's no point unlocking * the semaphore if we've just blown it away... */ _wapi_shm_sem_unlock (_WAPI_SHARED_SEM_PROCESS_COUNT_LOCK); } }
/* 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; } DEBUG ("%s: Checking ownership of named mutex handle %p", __func__, handle); if (namedmutex_handle->recursion == 0) { DEBUG ("%s: Named mutex handle %p not owned", __func__, handle); } else if (namedmutex_handle->pid == _wapi_getpid ()) { DEBUG ("%s: Named mutex handle %p owned by this process", __func__, handle); } else { int thr_ret; gpointer proc_handle; DEBUG ("%s: Named mutex handle %p owned by another process", __func__, handle); proc_handle = OpenProcess (0, 0, namedmutex_handle->pid); if (proc_handle == NULL) { /* Didn't find the process that this handle * was owned by, overriding it */ DEBUG ("%s: overriding old owner of named mutex handle %p", __func__, handle); thr_ret = _wapi_handle_lock_shared_handles (); g_assert (thr_ret == 0); 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 (); } else { DEBUG ("%s: Found active pid %d for named mutex handle %p", __func__, namedmutex_handle->pid, handle); } if (proc_handle != NULL) CloseProcess (proc_handle); } }
/* Called by thread_exit(), but maybe indirectly by * mono_thread_manage() via mono_thread_signal_self() too */ static void _wapi_thread_abandon_mutexes (gpointer handle) { struct _WapiHandle_thread *thread_handle; gboolean ok; int i; pid_t pid = _wapi_getpid (); pthread_t tid = pthread_self (); #ifdef DEBUG g_message ("%s: Thread %p abandoning held mutexes", __func__, handle); #endif if (handle == NULL) { handle = _wapi_thread_handle_from_id (pthread_self ()); if (handle == NULL) { /* Something gone badly wrong... */ return; } } ok = _wapi_lookup_handle (handle, WAPI_HANDLE_THREAD, (gpointer *)&thread_handle); if (ok == FALSE) { g_warning ("%s: error looking up thread handle %p", __func__, handle); return; } if (!pthread_equal (thread_handle->id, tid)) { return; } for (i = 0; i < thread_handle->owned_mutexes->len; i++) { gpointer mutex = g_ptr_array_index (thread_handle->owned_mutexes, i); _wapi_mutex_abandon (mutex, pid, tid); _wapi_thread_disown_mutex (mutex); } }
static void shm_semaphores_init (void) { key_t key; key_t oldkey; int thr_ret; struct _WapiHandleSharedLayout *tmp_shared; gchar *ftmp; gchar *filename; /* * Yet more barmy API - this union is a well-defined parameter * in a syscall, yet I still have to define it here as it * doesn't appear in a header */ union semun { int val; struct semid_ds *buf; ushort *array; } defs; ushort def_vals[_WAPI_SHARED_SEM_COUNT]; int i; int retries = 0; for (i = 0; i < _WAPI_SHARED_SEM_COUNT; i++) { def_vals[i] = 1; } /* * Process count must start at '0' - the 1 for all the others * sets the semaphore to "unlocked" */ def_vals[_WAPI_SHARED_SEM_PROCESS_COUNT] = 0; defs.array = def_vals; /* *Temporarily attach the shared data so we can read the * semaphore key. We release this mapping and attach again * after getting the semaphores to avoid a race condition * where a terminating process can delete the shared files * between a new process attaching the file and getting access * to the semaphores (which increments the process count, * preventing destruction of the shared data...) */ tmp_shared = _wapi_shm_attach (WAPI_SHM_DATA); g_assert (tmp_shared != NULL); #ifdef USE_SHM ftmp=_wapi_shm_shm_name (WAPI_SHM_DATA); filename = g_build_filename ("/dev/shm", ftmp, NULL); g_assert (filename!=NULL); key = ftok (filename, 'M'); g_free (ftmp); g_free (filename); #else key = ftok ( _wapi_shm_file (WAPI_SHM_DATA), 'M'); #endif again: retries++; oldkey = tmp_shared->sem_key; if (oldkey == 0) { DEBUGLOG ("%s: Creating with new key (0x%x)", __func__, key); /* * The while loop attempts to make some sense of the * bonkers 'think of a random number' method of * picking a key without collision with other * applications */ while ((_wapi_sem_id = semget (key, _WAPI_SHARED_SEM_COUNT, IPC_CREAT | IPC_EXCL | 0600)) == -1) { if (errno == ENOMEM) { g_error ("%s: semget error: %s", __func__, g_strerror (errno)); } else if (errno == ENOSPC) { g_error ("%s: semget error: %s. Try deleting some semaphores with ipcs and ipcrm\nor increase the maximum number of semaphore in the system.", __func__, g_strerror (errno)); } else if (errno != EEXIST) { if (retries > 3) g_warning ("%s: semget error: %s key 0x%x - trying again", __func__, g_strerror (errno), key); } key++; DEBUGLOG ("%s: Got (%s), trying with new key (0x%x)", __func__, g_strerror (errno), key); } /* * Got a semaphore array, so initialise it and install * the key into the shared memory */ if (semctl (_wapi_sem_id, 0, SETALL, defs) == -1) { if (retries > 3) g_warning ("%s: semctl init error: %s - trying again", __func__, g_strerror (errno)); /* * Something went horribly wrong, so try * getting a new set from scratch */ semctl (_wapi_sem_id, 0, IPC_RMID); goto again; } if (InterlockedCompareExchange (&tmp_shared->sem_key, key, 0) != 0) { /* * Someone else created one and installed the * key while we were working, so delete the * array we created and fall through to the * 'key already known' case. */ semctl (_wapi_sem_id, 0, IPC_RMID); oldkey = tmp_shared->sem_key; } else { /* * We've installed this semaphore set's key into * the shared memory */ goto done; } } DEBUGLOG ("%s: Trying with old key 0x%x", __func__, oldkey); _wapi_sem_id = semget (oldkey, _WAPI_SHARED_SEM_COUNT, 0600); if (_wapi_sem_id == -1) { if (retries > 3) g_warning ("%s: semget error opening old key 0x%x (%s) - trying again", __func__, oldkey,g_strerror (errno)); /* * Someone must have deleted the semaphore set, so * blow away the bad key and try again */ InterlockedCompareExchange (&tmp_shared->sem_key, 0, oldkey); goto again; } done: /* Increment the usage count of this semaphore set */ thr_ret = _wapi_shm_sem_lock (_WAPI_SHARED_SEM_PROCESS_COUNT_LOCK); g_assert (thr_ret == 0); DEBUGLOG ("%s: Incrementing the process count (%d)", __func__, _wapi_getpid ()); /* * We only ever _unlock_ this semaphore, letting the kernel * restore (ie decrement) this unlock when this process exits. * We lock another semaphore around it so we can serialise * access when we're testing the value of this semaphore when * we exit cleanly, so we can delete the whole semaphore set. */ _wapi_shm_sem_unlock (_WAPI_SHARED_SEM_PROCESS_COUNT); DEBUGLOG ("%s: Process count is now %d (%d)", __func__, semctl (_wapi_sem_id, _WAPI_SHARED_SEM_PROCESS_COUNT, GETVAL), _wapi_getpid ()); _wapi_shm_sem_unlock (_WAPI_SHARED_SEM_PROCESS_COUNT_LOCK); if (_wapi_shm_disabled) g_free (tmp_shared); else munmap (tmp_shared, sizeof(struct _WapiHandleSharedLayout)); }