2 * mutexes.c: Mutex handles
5 * Dick Porter (dick@ximian.com)
7 * (C) 2002 Ximian, Inc.
16 #include <mono/io-layer/wapi.h>
17 #include <mono/io-layer/wapi-private.h>
18 #include <mono/io-layer/misc-private.h>
19 #include <mono/io-layer/handles-private.h>
20 #include <mono/io-layer/mono-mutex.h>
21 #include <mono/io-layer/mutex-private.h>
25 /* This is used to serialise mutex creation when names are given
27 static mono_mutex_t named_mutex_mutex;
29 static void mutex_close_shared (gpointer handle);
30 static void mutex_signal(gpointer handle);
31 static void mutex_own (gpointer handle);
32 static gboolean mutex_is_owned (gpointer handle);
34 struct _WapiHandleOps _wapi_mutex_ops = {
35 mutex_close_shared, /* close_shared */
36 NULL, /* close_private */
37 mutex_signal, /* signal */
39 mutex_is_owned, /* is_owned */
42 static mono_once_t mutex_ops_once=MONO_ONCE_INIT;
44 static void mutex_ops_init (void)
47 #if defined(_POSIX_THREAD_PROCESS_SHARED) && _POSIX_THREAD_PROCESS_SHARED != -1
48 pthread_mutexattr_t mutex_shared_attr;
50 thr_ret = mono_mutexattr_init (&mutex_shared_attr);
51 g_assert (thr_ret == 0);
53 thr_ret = mono_mutexattr_setpshared (&mutex_shared_attr,
54 PTHREAD_PROCESS_SHARED);
55 g_assert (thr_ret == 0);
57 thr_ret = mono_mutex_init (&named_mutex_mutex, &mutex_shared_attr);
58 g_assert (thr_ret == 0);
60 thr_ret = mono_mutex_init (&named_mutex_mutex, NULL);
63 _wapi_handle_register_capabilities (WAPI_HANDLE_MUTEX,
64 WAPI_HANDLE_CAP_WAIT |
65 WAPI_HANDLE_CAP_SIGNAL |
69 static void mutex_close_shared (gpointer handle)
71 struct _WapiHandle_mutex *mutex_handle;
74 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_MUTEX,
75 (gpointer *)&mutex_handle, NULL);
77 g_warning (G_GNUC_PRETTY_FUNCTION
78 ": error looking up mutex handle %p", handle);
83 g_message(G_GNUC_PRETTY_FUNCTION ": closing mutex handle %p", handle);
86 if(mutex_handle->sharedns.name!=0) {
87 _wapi_handle_scratch_delete (mutex_handle->sharedns.name);
88 mutex_handle->sharedns.name=0;
92 static void mutex_signal(gpointer handle)
97 static void mutex_own (gpointer handle)
99 struct _WapiHandle_mutex *mutex_handle;
102 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_MUTEX,
103 (gpointer *)&mutex_handle, NULL);
105 g_warning (G_GNUC_PRETTY_FUNCTION
106 ": error looking up mutex handle %p", handle);
111 g_message(G_GNUC_PRETTY_FUNCTION ": owning mutex handle %p", handle);
114 _wapi_handle_set_signal_state (handle, FALSE, FALSE);
116 mutex_handle->pid=getpid ();
117 mutex_handle->tid=pthread_self ();
118 mutex_handle->recursion++;
121 g_message (G_GNUC_PRETTY_FUNCTION
122 ": mutex handle %p locked %d times by %d:%ld", handle,
123 mutex_handle->recursion, mutex_handle->pid,
128 static gboolean mutex_is_owned (gpointer handle)
130 struct _WapiHandle_mutex *mutex_handle;
133 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_MUTEX,
134 (gpointer *)&mutex_handle, NULL);
136 g_warning (G_GNUC_PRETTY_FUNCTION
137 ": error looking up mutex handle %p", handle);
142 g_message(G_GNUC_PRETTY_FUNCTION
143 ": testing ownership mutex handle %p", handle);
146 if(mutex_handle->recursion>0 &&
147 mutex_handle->pid==getpid () &&
148 mutex_handle->tid==pthread_self ()) {
150 g_message (G_GNUC_PRETTY_FUNCTION
151 ": mutex handle %p owned by %d:%ld", handle,
152 getpid (), pthread_self ());
158 g_message (G_GNUC_PRETTY_FUNCTION
159 ": mutex handle %p not owned by %d:%ld, but locked %d times by %d:%ld", handle, getpid (), pthread_self (), mutex_handle->recursion, mutex_handle->pid, mutex_handle->tid);
166 struct mutex_check_data
172 static gboolean mutex_check (gpointer handle, gpointer user_data)
174 struct _WapiHandle_mutex *mutex_handle;
176 struct mutex_check_data *data = (struct mutex_check_data *)user_data;
179 ok = _wapi_lookup_handle (handle, WAPI_HANDLE_MUTEX,
180 (gpointer *)&mutex_handle, NULL);
182 g_warning (G_GNUC_PRETTY_FUNCTION
183 ": error looking up mutex handle %p", handle);
187 pthread_cleanup_push ((void(*)(void *))_wapi_handle_unlock_handle,
189 thr_ret = _wapi_handle_lock_handle (handle);
190 g_assert (thr_ret == 0);
192 if (mutex_handle->pid == data->pid &&
193 mutex_handle->tid == data->tid) {
195 g_message (G_GNUC_PRETTY_FUNCTION
196 ": Mutex handle %p abandoned!", handle);
199 mutex_handle->recursion = 0;
200 mutex_handle->pid = 0;
201 mutex_handle->tid = 0;
203 _wapi_handle_set_signal_state (handle, TRUE, FALSE);
206 thr_ret = _wapi_handle_unlock_handle (handle);
207 g_assert (thr_ret == 0);
208 pthread_cleanup_pop (0);
210 /* Return false to keep searching */
214 /* When a thread exits, any mutexes it still holds need to be signalled */
215 void _wapi_mutex_check_abandoned (pid_t pid, pthread_t tid)
217 struct mutex_check_data data;
222 _wapi_search_handle (WAPI_HANDLE_MUTEX, mutex_check, &data, NULL,
228 * @security: Ignored for now.
229 * @owned: If %TRUE, the mutex is created with the calling thread
230 * already owning the mutex.
231 * @name:Pointer to a string specifying the name of this mutex, or
234 * Creates a new mutex handle. A mutex is signalled when no thread
235 * owns it. A thread acquires ownership of the mutex by waiting for
236 * it with WaitForSingleObject() or WaitForMultipleObjects(). A
237 * thread relinquishes ownership with ReleaseMutex().
239 * A thread that owns a mutex can specify the same mutex in repeated
240 * wait function calls without blocking. The thread must call
241 * ReleaseMutex() an equal number of times to release the mutex.
243 * Return value: A new handle, or %NULL on error.
245 gpointer CreateMutex(WapiSecurityAttributes *security G_GNUC_UNUSED, gboolean owned,
246 const gunichar2 *name)
248 struct _WapiHandle_mutex *mutex_handle;
255 mono_once (&mutex_ops_once, mutex_ops_init);
257 /* w32 seems to guarantee that opening named mutexes can't
260 pthread_cleanup_push ((void(*)(void *))mono_mutex_unlock_in_cleanup,
261 (void *)&named_mutex_mutex);
262 thr_ret = mono_mutex_lock (&named_mutex_mutex);
263 g_assert (thr_ret == 0);
265 /* Need to blow away any old errors here, because code tests
266 * for ERROR_ALREADY_EXISTS on success (!) to see if a mutex
267 * was freshly created
269 SetLastError (ERROR_SUCCESS);
272 utf8_name=g_utf16_to_utf8 (name, -1, NULL, NULL, NULL);
278 g_message (G_GNUC_PRETTY_FUNCTION ": Creating mutex (name [%s])",
279 utf8_name==NULL?"<unnamed>":utf8_name);
283 handle=_wapi_search_handle_namespace (
284 WAPI_HANDLE_MUTEX, utf8_name,
285 (gpointer *)&mutex_handle, NULL);
286 if(handle==_WAPI_HANDLE_INVALID) {
287 /* The name has already been used for a different
291 SetLastError (ERROR_INVALID_HANDLE);
293 } else if (handle!=NULL) {
295 _wapi_handle_ref (handle);
298 /* Not an error, but this is how the caller is
299 * informed that the mutex wasn't freshly
302 SetLastError (ERROR_ALREADY_EXISTS);
305 /* Otherwise fall through to create the mutex. */
308 handle=_wapi_handle_new (WAPI_HANDLE_MUTEX);
309 if(handle==_WAPI_HANDLE_INVALID) {
310 g_warning (G_GNUC_PRETTY_FUNCTION
311 ": error creating mutex handle");
312 if(utf8_name!=NULL) {
318 pthread_cleanup_push ((void(*)(void *))_wapi_handle_unlock_handle,
320 thr_ret = _wapi_handle_lock_handle (handle);
321 g_assert (thr_ret == 0);
323 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_MUTEX,
324 (gpointer *)&mutex_handle, NULL);
326 g_warning (G_GNUC_PRETTY_FUNCTION
327 ": error looking up mutex handle %p", handle);
328 if(utf8_name!=NULL) {
336 if(utf8_name!=NULL) {
337 mutex_handle->sharedns.name=_wapi_handle_scratch_store (
338 utf8_name, strlen (utf8_name));
344 _wapi_handle_set_signal_state (handle, TRUE, FALSE);
348 g_message (G_GNUC_PRETTY_FUNCTION ": returning mutex handle %p",
352 if(utf8_name!=NULL) {
357 thr_ret = _wapi_handle_unlock_handle (handle);
358 g_assert (thr_ret == 0);
359 pthread_cleanup_pop (0);
362 thr_ret = mono_mutex_unlock (&named_mutex_mutex);
363 g_assert (thr_ret == 0);
364 pthread_cleanup_pop (0);
371 * @handle: The mutex handle.
373 * Releases ownership if the mutex handle @handle.
375 * Return value: %TRUE on success, %FALSE otherwise. This function
376 * fails if the calling thread does not own the mutex @handle.
378 gboolean ReleaseMutex(gpointer handle)
380 struct _WapiHandle_mutex *mutex_handle;
382 pthread_t tid=pthread_self();
385 gboolean ret = FALSE;
387 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_MUTEX,
388 (gpointer *)&mutex_handle, NULL);
390 g_warning (G_GNUC_PRETTY_FUNCTION
391 ": error looking up mutex handle %p", handle);
395 pthread_cleanup_push ((void(*)(void *))_wapi_handle_unlock_handle,
397 thr_ret = _wapi_handle_lock_handle (handle);
398 g_assert (thr_ret == 0);
401 g_message(G_GNUC_PRETTY_FUNCTION ": Releasing mutex handle %p",
405 if(mutex_handle->tid!=tid || mutex_handle->pid!=pid) {
407 g_message(G_GNUC_PRETTY_FUNCTION ": We don't own mutex handle %p (owned by %d:%ld, me %d:%ld)", handle, mutex_handle->pid, mutex_handle->tid, pid, tid);
414 /* OK, we own this mutex */
415 mutex_handle->recursion--;
417 if(mutex_handle->recursion==0) {
419 g_message(G_GNUC_PRETTY_FUNCTION ": Unlocking mutex handle %p",
425 _wapi_handle_set_signal_state (handle, TRUE, FALSE);
429 thr_ret = _wapi_handle_unlock_handle (handle);
430 g_assert (thr_ret == 0);
431 pthread_cleanup_pop (0);