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
26 * (FIXME: make it process-shared)
28 static mono_mutex_t named_mutex_mutex = MONO_MUTEX_INITIALIZER;
30 static void mutex_close_shared (gpointer handle);
31 static void mutex_signal(gpointer handle);
32 static void mutex_own (gpointer handle);
33 static gboolean mutex_is_owned (gpointer handle);
35 struct _WapiHandleOps _wapi_mutex_ops = {
36 mutex_close_shared, /* close_shared */
37 NULL, /* close_private */
38 mutex_signal, /* signal */
40 mutex_is_owned, /* is_owned */
43 static mono_once_t mutex_ops_once=MONO_ONCE_INIT;
45 static void mutex_ops_init (void)
47 _wapi_handle_register_capabilities (WAPI_HANDLE_MUTEX,
48 WAPI_HANDLE_CAP_WAIT |
49 WAPI_HANDLE_CAP_SIGNAL |
53 static void mutex_close_shared (gpointer handle)
55 struct _WapiHandle_mutex *mutex_handle;
58 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_MUTEX,
59 (gpointer *)&mutex_handle, NULL);
61 g_warning (G_GNUC_PRETTY_FUNCTION
62 ": error looking up mutex handle %p", handle);
67 g_message(G_GNUC_PRETTY_FUNCTION ": closing mutex handle %p", handle);
70 if(mutex_handle->sharedns.name!=0) {
71 _wapi_handle_scratch_delete (mutex_handle->sharedns.name);
72 mutex_handle->sharedns.name=0;
76 static void mutex_signal(gpointer handle)
81 static void mutex_own (gpointer handle)
83 struct _WapiHandle_mutex *mutex_handle;
86 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_MUTEX,
87 (gpointer *)&mutex_handle, NULL);
89 g_warning (G_GNUC_PRETTY_FUNCTION
90 ": error looking up mutex handle %p", handle);
95 g_message(G_GNUC_PRETTY_FUNCTION ": owning mutex handle %p", handle);
98 _wapi_handle_set_signal_state (handle, FALSE, FALSE);
100 mutex_handle->pid=getpid ();
101 mutex_handle->tid=pthread_self ();
102 mutex_handle->recursion++;
105 g_message (G_GNUC_PRETTY_FUNCTION
106 ": mutex handle %p locked %d times by %d:%ld", handle,
107 mutex_handle->recursion, mutex_handle->pid,
112 static gboolean mutex_is_owned (gpointer handle)
114 struct _WapiHandle_mutex *mutex_handle;
117 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_MUTEX,
118 (gpointer *)&mutex_handle, NULL);
120 g_warning (G_GNUC_PRETTY_FUNCTION
121 ": error looking up mutex handle %p", handle);
126 g_message(G_GNUC_PRETTY_FUNCTION
127 ": testing ownership mutex handle %p", handle);
130 if(mutex_handle->recursion>0 &&
131 mutex_handle->pid==getpid () &&
132 mutex_handle->tid==pthread_self ()) {
134 g_message (G_GNUC_PRETTY_FUNCTION
135 ": mutex handle %p owned by %d:%ld", handle,
136 getpid (), pthread_self ());
142 g_message (G_GNUC_PRETTY_FUNCTION
143 ": mutex handle %p not owned by %d:%ld", handle,
144 getpid (), pthread_self ());
153 * @security: Ignored for now.
154 * @owned: If %TRUE, the mutex is created with the calling thread
155 * already owning the mutex.
156 * @name:Pointer to a string specifying the name of this mutex, or
159 * Creates a new mutex handle. A mutex is signalled when no thread
160 * owns it. A thread acquires ownership of the mutex by waiting for
161 * it with WaitForSingleObject() or WaitForMultipleObjects(). A
162 * thread relinquishes ownership with ReleaseMutex().
164 * A thread that owns a mutex can specify the same mutex in repeated
165 * wait function calls without blocking. The thread must call
166 * ReleaseMutex() an equal number of times to release the mutex.
168 * Return value: A new handle, or %NULL on error.
170 gpointer CreateMutex(WapiSecurityAttributes *security G_GNUC_UNUSED, gboolean owned,
171 const gunichar2 *name)
173 struct _WapiHandle_mutex *mutex_handle;
180 mono_once (&mutex_ops_once, mutex_ops_init);
182 /* w32 seems to guarantee that opening named mutexes can't
185 pthread_cleanup_push ((void(*)(void *))mono_mutex_unlock_in_cleanup,
186 (void *)&named_mutex_mutex);
187 thr_ret = mono_mutex_lock (&named_mutex_mutex);
188 g_assert (thr_ret == 0);
191 utf8_name=g_utf16_to_utf8 (name, -1, NULL, NULL, NULL);
197 g_message (G_GNUC_PRETTY_FUNCTION ": Creating mutex (name [%s])",
198 utf8_name==NULL?"<unnamed>":utf8_name);
202 handle=_wapi_search_handle_namespace (
203 WAPI_HANDLE_MUTEX, utf8_name,
204 (gpointer *)&mutex_handle, NULL);
205 if(handle==_WAPI_HANDLE_INVALID) {
206 /* The name has already been used for a different
210 SetLastError (ERROR_INVALID_HANDLE);
212 } else if (handle!=NULL) {
214 _wapi_handle_ref (handle);
218 /* Otherwise fall through to create the mutex. */
221 handle=_wapi_handle_new (WAPI_HANDLE_MUTEX);
222 if(handle==_WAPI_HANDLE_INVALID) {
223 g_warning (G_GNUC_PRETTY_FUNCTION
224 ": error creating mutex handle");
225 if(utf8_name!=NULL) {
231 pthread_cleanup_push ((void(*)(void *))_wapi_handle_unlock_handle,
233 thr_ret = _wapi_handle_lock_handle (handle);
234 g_assert (thr_ret == 0);
236 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_MUTEX,
237 (gpointer *)&mutex_handle, NULL);
239 g_warning (G_GNUC_PRETTY_FUNCTION
240 ": error looking up mutex handle %p", handle);
241 if(utf8_name!=NULL) {
249 if(utf8_name!=NULL) {
250 mutex_handle->sharedns.name=_wapi_handle_scratch_store (
251 utf8_name, strlen (utf8_name));
257 _wapi_handle_set_signal_state (handle, TRUE, FALSE);
261 g_message (G_GNUC_PRETTY_FUNCTION ": returning mutex handle %p",
265 if(utf8_name!=NULL) {
270 thr_ret = _wapi_handle_unlock_handle (handle);
271 g_assert (thr_ret == 0);
272 pthread_cleanup_pop (0);
275 thr_ret = mono_mutex_unlock (&named_mutex_mutex);
276 g_assert (thr_ret == 0);
277 pthread_cleanup_pop (0);
284 * @handle: The mutex handle.
286 * Releases ownership if the mutex handle @handle.
288 * Return value: %TRUE on success, %FALSE otherwise. This function
289 * fails if the calling thread does not own the mutex @handle.
291 gboolean ReleaseMutex(gpointer handle)
293 struct _WapiHandle_mutex *mutex_handle;
295 pthread_t tid=pthread_self();
298 gboolean ret = FALSE;
300 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_MUTEX,
301 (gpointer *)&mutex_handle, NULL);
303 g_warning (G_GNUC_PRETTY_FUNCTION
304 ": error looking up mutex handle %p", handle);
308 pthread_cleanup_push ((void(*)(void *))_wapi_handle_unlock_handle,
310 thr_ret = _wapi_handle_lock_handle (handle);
311 g_assert (thr_ret == 0);
314 g_message(G_GNUC_PRETTY_FUNCTION ": Releasing mutex handle %p",
318 if(mutex_handle->tid!=tid || mutex_handle->pid!=pid) {
320 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);
327 /* OK, we own this mutex */
328 mutex_handle->recursion--;
330 if(mutex_handle->recursion==0) {
332 g_message(G_GNUC_PRETTY_FUNCTION ": Unlocking mutex handle %p",
338 _wapi_handle_set_signal_state (handle, TRUE, FALSE);
342 thr_ret = _wapi_handle_unlock_handle (handle);
343 g_assert (thr_ret == 0);
344 pthread_cleanup_pop (0);