[mutex] Make mono_os_mutex_* functions return more meaningful value
[mono.git] / mono / io-layer / mutexes.c
1 /*
2  * mutexes.c:  Mutex handles
3  *
4  * Author:
5  *      Dick Porter (dick@ximian.com)
6  *
7  * (C) 2002-2006 Ximian, Inc.
8  */
9
10 #include <config.h>
11 #include <glib.h>
12 #include <pthread.h>
13 #include <string.h>
14 #include <unistd.h>
15
16 #include <mono/io-layer/wapi.h>
17 #include <mono/io-layer/wapi-private.h>
18 #include <mono/io-layer/mutex-private.h>
19 #include <mono/io-layer/io-trace.h>
20 #include <mono/utils/mono-once.h>
21 #include <mono/utils/mono-logger-internals.h>
22 #include <mono/utils/w32handle.h>
23
24 static void mutex_signal(gpointer handle);
25 static gboolean mutex_own (gpointer handle);
26 static gboolean mutex_is_owned (gpointer handle);
27 static void mutex_prewait (gpointer handle);
28 static void mutex_details (gpointer data);
29 static const gchar* mutex_typename (void);
30 static gsize mutex_typesize (void);
31
32 static void namedmutex_signal (gpointer handle);
33 static gboolean namedmutex_own (gpointer handle);
34 static gboolean namedmutex_is_owned (gpointer handle);
35 static void namedmutex_prewait (gpointer handle);
36 static void namedmutex_details (gpointer data);
37 static const gchar* namedmutex_typename (void);
38 static gsize namedmutex_typesize (void);
39
40 static MonoW32HandleOps _wapi_mutex_ops = {
41         NULL,                   /* close */
42         mutex_signal,           /* signal */
43         mutex_own,              /* own */
44         mutex_is_owned,         /* is_owned */
45         NULL,                   /* special_wait */
46         mutex_prewait,                  /* prewait */
47         mutex_details,  /* details */
48         mutex_typename, /* typename */
49         mutex_typesize, /* typesize */
50 };
51
52 static MonoW32HandleOps _wapi_namedmutex_ops = {
53         NULL,                   /* close */
54         namedmutex_signal,      /* signal */
55         namedmutex_own,         /* own */
56         namedmutex_is_owned,    /* is_owned */
57         NULL,                   /* special_wait */
58         namedmutex_prewait,     /* prewait */
59         namedmutex_details,     /* details */
60         namedmutex_typename,    /* typename */
61         namedmutex_typesize,    /* typesize */
62 };
63
64 void
65 _wapi_mutex_init (void)
66 {
67         mono_w32handle_register_ops (MONO_W32HANDLE_MUTEX,      &_wapi_mutex_ops);
68         mono_w32handle_register_ops (MONO_W32HANDLE_NAMEDMUTEX, &_wapi_namedmutex_ops);
69
70         mono_w32handle_register_capabilities (MONO_W32HANDLE_MUTEX,
71                 (MonoW32HandleCapability)(MONO_W32HANDLE_CAP_WAIT | MONO_W32HANDLE_CAP_SIGNAL | MONO_W32HANDLE_CAP_OWN));
72         mono_w32handle_register_capabilities (MONO_W32HANDLE_NAMEDMUTEX,
73                 (MonoW32HandleCapability)(MONO_W32HANDLE_CAP_WAIT | MONO_W32HANDLE_CAP_SIGNAL | MONO_W32HANDLE_CAP_OWN));
74 }
75
76 static const char* mutex_handle_type_to_string (MonoW32HandleType type)
77 {
78         switch (type) {
79         case MONO_W32HANDLE_MUTEX: return "mutex";
80         case MONO_W32HANDLE_NAMEDMUTEX: return "named mutex";
81         default:
82                 g_assert_not_reached ();
83         }
84 }
85
86 static gboolean
87 mutex_handle_own (gpointer handle, MonoW32HandleType type)
88 {
89         struct _WapiHandle_mutex *mutex_handle;
90
91         if (!mono_w32handle_lookup (handle, type, (gpointer *)&mutex_handle)) {
92                 g_warning ("%s: error looking up %s handle %p", __func__, mutex_handle_type_to_string (type), handle);
93                 return FALSE;
94         }
95
96         MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: owning %s handle %p, tid %p, recursion %u",
97                 __func__, mutex_handle_type_to_string (type), handle, (gpointer) mutex_handle->tid, mutex_handle->recursion);
98
99         _wapi_thread_own_mutex (handle);
100
101         mutex_handle->tid = pthread_self ();
102         mutex_handle->recursion++;
103
104         mono_w32handle_set_signal_state (handle, FALSE, FALSE);
105
106         return TRUE;
107 }
108
109 static gboolean
110 mutex_handle_is_owned (gpointer handle, MonoW32HandleType type)
111 {
112         struct _WapiHandle_mutex *mutex_handle;
113
114         if (!mono_w32handle_lookup (handle, type, (gpointer *)&mutex_handle)) {
115                 g_warning ("%s: error looking up %s handle %p", __func__, mutex_handle_type_to_string (type), handle);
116                 return FALSE;
117         }
118
119         MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: testing ownership %s handle %p",
120                 __func__, mutex_handle_type_to_string (type), handle);
121
122         if (mutex_handle->recursion > 0 && pthread_equal (mutex_handle->tid, pthread_self ())) {
123                 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: %s handle %p owned by %p",
124                         __func__, mutex_handle_type_to_string (type), handle, (gpointer) pthread_self ());
125                 return TRUE;
126         } else {
127                 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: %s handle %p not owned by %p, but locked %d times by %p",
128                         __func__, mutex_handle_type_to_string (type), handle, (gpointer) pthread_self (), mutex_handle->recursion, (gpointer) mutex_handle->tid);
129                 return FALSE;
130         }
131 }
132
133 static void mutex_signal(gpointer handle)
134 {
135         ReleaseMutex(handle);
136 }
137
138 static gboolean mutex_own (gpointer handle)
139 {
140         return mutex_handle_own (handle, MONO_W32HANDLE_MUTEX);
141 }
142
143 static gboolean mutex_is_owned (gpointer handle)
144 {
145         
146         return mutex_handle_is_owned (handle, MONO_W32HANDLE_MUTEX);
147 }
148
149 static void namedmutex_signal (gpointer handle)
150 {
151         ReleaseMutex(handle);
152 }
153
154 /* NB, always called with the shared handle lock held */
155 static gboolean namedmutex_own (gpointer handle)
156 {
157         return mutex_handle_own (handle, MONO_W32HANDLE_NAMEDMUTEX);
158 }
159
160 static gboolean namedmutex_is_owned (gpointer handle)
161 {
162         return mutex_handle_is_owned (handle, MONO_W32HANDLE_NAMEDMUTEX);
163 }
164
165 static void mutex_handle_prewait (gpointer handle, MonoW32HandleType type)
166 {
167         /* If the mutex is not currently owned, do nothing and let the
168          * usual wait carry on.  If it is owned, check that the owner
169          * is still alive; if it isn't we override the previous owner
170          * and assume that process exited abnormally and failed to
171          * clean up.
172          */
173         struct _WapiHandle_mutex *mutex_handle;
174
175         if (!mono_w32handle_lookup (handle, type, (gpointer *)&mutex_handle)) {
176                 g_warning ("%s: error looking up %s handle %p",
177                         __func__, mutex_handle_type_to_string (type), handle);
178                 return;
179         }
180
181         MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: pre-waiting %s handle %p, owned? %s",
182                 __func__, mutex_handle_type_to_string (type), handle, mutex_handle->recursion != 0 ? "true" : "false");
183 }
184
185 /* The shared state is not locked when prewait methods are called */
186 static void mutex_prewait (gpointer handle)
187 {
188         mutex_handle_prewait (handle, MONO_W32HANDLE_MUTEX);
189 }
190
191 /* The shared state is not locked when prewait methods are called */
192 static void namedmutex_prewait (gpointer handle)
193 {
194         mutex_handle_prewait (handle, MONO_W32HANDLE_NAMEDMUTEX);
195 }
196
197 static void mutex_details (gpointer data)
198 {
199         struct _WapiHandle_mutex *mut = (struct _WapiHandle_mutex *)data;
200         
201 #ifdef PTHREAD_POINTER_ID
202         g_print ("own: %5p, count: %5u", mut->tid, mut->recursion);
203 #else
204         g_print ("own: %5ld, count: %5u", mut->tid, mut->recursion);
205 #endif
206 }
207
208 static void namedmutex_details (gpointer data)
209 {
210         struct _WapiHandle_namedmutex *namedmut = (struct _WapiHandle_namedmutex *)data;
211         
212 #ifdef PTHREAD_POINTER_ID
213         g_print ("own: %5p, count: %5u, name: \"%s\"",
214                 namedmut->m.tid, namedmut->m.recursion, namedmut->sharedns.name);
215 #else
216         g_print ("own: %5ld, count: %5u, name: \"%s\"",
217                 namedmut->m.tid, namedmut->m.recursion, namedmut->sharedns.name);
218 #endif
219 }
220
221 static const gchar* mutex_typename (void)
222 {
223         return "Mutex";
224 }
225
226 static gsize mutex_typesize (void)
227 {
228         return sizeof (struct _WapiHandle_mutex);
229 }
230
231 static const gchar* namedmutex_typename (void)
232 {
233         return "N.Mutex";
234 }
235
236 static gsize namedmutex_typesize (void)
237 {
238         return sizeof (struct _WapiHandle_namedmutex);
239 }
240
241 /* When a thread exits, any mutexes it still holds need to be signalled. */
242 void _wapi_mutex_abandon (gpointer handle, pid_t pid, pthread_t tid)
243 {
244         MonoW32HandleType type;
245         struct _WapiHandle_mutex *mutex_handle;
246         int thr_ret;
247
248         switch (type = mono_w32handle_get_type (handle)) {
249         case MONO_W32HANDLE_MUTEX:
250         case MONO_W32HANDLE_NAMEDMUTEX:
251                 break;
252         default:
253                 g_assert_not_reached ();
254         }
255
256         if (!mono_w32handle_lookup (handle, type, (gpointer *)&mutex_handle)) {
257                 g_warning ("%s: error looking up %s handle %p",
258                         __func__, mutex_handle_type_to_string (type), handle);
259                 return;
260         }
261
262         MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: abandon %s handle %p",
263                 __func__, mutex_handle_type_to_string (type), handle);
264
265         thr_ret = mono_w32handle_lock_handle (handle);
266         g_assert (thr_ret == 0);
267
268         if (pthread_equal (mutex_handle->tid, tid)) {
269                 mutex_handle->recursion = 0;
270                 mutex_handle->tid = 0;
271
272                 mono_w32handle_set_signal_state (handle, TRUE, FALSE);
273
274                 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: abandoned %s handle %p",
275                         __func__, mutex_handle_type_to_string (type), handle);
276         }
277
278         thr_ret = mono_w32handle_unlock_handle (handle);
279         g_assert (thr_ret == 0);
280 }
281
282 static gpointer mutex_handle_create (struct _WapiHandle_mutex *mutex_handle, MonoW32HandleType type, gboolean owned)
283 {
284         gpointer handle;
285         int thr_ret;
286
287         mutex_handle->tid = 0;
288         mutex_handle->recursion = 0;
289
290         handle = mono_w32handle_new (type, mutex_handle);
291         if (handle == INVALID_HANDLE_VALUE) {
292                 g_warning ("%s: error creating %s handle",
293                         __func__, mutex_handle_type_to_string (type));
294                 SetLastError (ERROR_GEN_FAILURE);
295                 return NULL;
296         }
297
298         thr_ret = mono_w32handle_lock_handle (handle);
299         g_assert (thr_ret == 0);
300
301         if (owned)
302                 mutex_handle_own (handle, type);
303         else
304                 mono_w32handle_set_signal_state (handle, TRUE, FALSE);
305
306         thr_ret = mono_w32handle_unlock_handle (handle);
307         g_assert (thr_ret == 0);
308
309         MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: created %s handle %p",
310                 __func__, mutex_handle_type_to_string (type), handle);
311
312         return handle;
313 }
314
315 static gpointer mutex_create (gboolean owned)
316 {
317         struct _WapiHandle_mutex mutex_handle;
318         MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: creating %s handle",
319                 __func__, mutex_handle_type_to_string (MONO_W32HANDLE_MUTEX));
320         return mutex_handle_create (&mutex_handle, MONO_W32HANDLE_MUTEX, owned);
321 }
322
323 static gpointer namedmutex_create (gboolean owned, const gunichar2 *name)
324 {
325         gpointer handle;
326         gchar *utf8_name;
327         int thr_ret;
328
329         MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: creating %s handle",
330                 __func__, mutex_handle_type_to_string (MONO_W32HANDLE_NAMEDMUTEX));
331
332         /* w32 seems to guarantee that opening named objects can't race each other */
333         thr_ret = _wapi_namespace_lock ();
334         g_assert (thr_ret == 0);
335
336         utf8_name = g_utf16_to_utf8 (name, -1, NULL, NULL, NULL);
337
338         handle = _wapi_search_handle_namespace (MONO_W32HANDLE_NAMEDMUTEX, utf8_name);
339         if (handle == INVALID_HANDLE_VALUE) {
340                 /* The name has already been used for a different object. */
341                 handle = NULL;
342                 SetLastError (ERROR_INVALID_HANDLE);
343         } else if (handle) {
344                 /* Not an error, but this is how the caller is informed that the mutex wasn't freshly created */
345                 SetLastError (ERROR_ALREADY_EXISTS);
346
347                 /* this is used as creating a new handle */
348                 mono_w32handle_ref (handle);
349         } else {
350                 /* A new named mutex */
351                 struct _WapiHandle_namedmutex namedmutex_handle;
352
353                 strncpy (&namedmutex_handle.sharedns.name [0], utf8_name, MAX_PATH);
354                 namedmutex_handle.sharedns.name [MAX_PATH] = '\0';
355
356                 handle = mutex_handle_create ((struct _WapiHandle_mutex*) &namedmutex_handle, MONO_W32HANDLE_NAMEDMUTEX, owned);
357         }
358
359         g_free (utf8_name);
360
361         thr_ret = _wapi_namespace_unlock (NULL);
362         g_assert (thr_ret == 0);
363
364         return handle;
365 }
366
367 /**
368  * CreateMutex:
369  * @security: Ignored for now.
370  * @owned: If %TRUE, the mutex is created with the calling thread
371  * already owning the mutex.
372  * @name:Pointer to a string specifying the name of this mutex, or
373  * %NULL.
374  *
375  * Creates a new mutex handle.  A mutex is signalled when no thread
376  * owns it.  A thread acquires ownership of the mutex by waiting for
377  * it with WaitForSingleObject() or WaitForMultipleObjects().  A
378  * thread relinquishes ownership with ReleaseMutex().
379  *
380  * A thread that owns a mutex can specify the same mutex in repeated
381  * wait function calls without blocking.  The thread must call
382  * ReleaseMutex() an equal number of times to release the mutex.
383  *
384  * Return value: A new handle, or %NULL on error.
385  */
386 gpointer CreateMutex(WapiSecurityAttributes *security G_GNUC_UNUSED, gboolean owned, const gunichar2 *name)
387 {
388         /* Need to blow away any old errors here, because code tests
389          * for ERROR_ALREADY_EXISTS on success (!) to see if a mutex
390          * was freshly created */
391         SetLastError (ERROR_SUCCESS);
392
393         return name ? namedmutex_create (owned, name) : mutex_create (owned);
394 }
395
396 /**
397  * ReleaseMutex:
398  * @handle: The mutex handle.
399  *
400  * Releases ownership if the mutex handle @handle.
401  *
402  * Return value: %TRUE on success, %FALSE otherwise.  This function
403  * fails if the calling thread does not own the mutex @handle.
404  */
405 gboolean ReleaseMutex(gpointer handle)
406 {
407         MonoW32HandleType type;
408         struct _WapiHandle_mutex *mutex_handle;
409         pthread_t tid;
410         int thr_ret;
411         gboolean ret;
412
413         if (handle == NULL) {
414                 SetLastError (ERROR_INVALID_HANDLE);
415                 return FALSE;
416         }
417
418         switch (type = mono_w32handle_get_type (handle)) {
419         case MONO_W32HANDLE_MUTEX:
420         case MONO_W32HANDLE_NAMEDMUTEX:
421                 break;
422         default:
423                 SetLastError (ERROR_INVALID_HANDLE);
424                 return FALSE;
425         }
426
427         if (!mono_w32handle_lookup (handle, type, (gpointer *)&mutex_handle)) {
428                 g_warning ("%s: error looking up %s handle %p",
429                         __func__, mutex_handle_type_to_string (type), handle);
430                 return FALSE;
431         }
432
433         MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: releasing %s handle %p",
434                 __func__, mutex_handle_type_to_string (type), handle);
435
436         thr_ret = mono_w32handle_lock_handle (handle);
437         g_assert (thr_ret == 0);
438
439         tid = pthread_self ();
440
441         if (!pthread_equal (mutex_handle->tid, tid)) {
442                 ret = FALSE;
443
444                 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: we don't own %s handle %p (owned by %ld, me %ld)",
445                         __func__, mutex_handle_type_to_string (type), handle, mutex_handle->tid, tid);
446         } else {
447                 ret = TRUE;
448
449                 /* OK, we own this mutex */
450                 mutex_handle->recursion--;
451
452                 if (mutex_handle->recursion == 0) {
453                         _wapi_thread_disown_mutex (handle);
454
455                         MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: unlocking %s handle %p",
456                                 __func__, mutex_handle_type_to_string (type), handle);
457
458                         mutex_handle->tid = 0;
459                         mono_w32handle_set_signal_state (handle, TRUE, FALSE);
460                 }
461         }
462
463         thr_ret = mono_w32handle_unlock_handle (handle);
464         g_assert (thr_ret == 0);
465
466         return ret;
467 }
468
469 gpointer OpenMutex (guint32 access G_GNUC_UNUSED, gboolean inherit G_GNUC_UNUSED, const gunichar2 *name)
470 {
471         gpointer handle;
472         gchar *utf8_name;
473         int thr_ret;
474
475         /* w32 seems to guarantee that opening named objects can't
476          * race each other
477          */
478         thr_ret = _wapi_namespace_lock ();
479         g_assert (thr_ret == 0);
480
481         utf8_name = g_utf16_to_utf8 (name, -1, NULL, NULL, NULL);
482         
483         MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Opening named mutex [%s]", __func__, utf8_name);
484         
485         handle = _wapi_search_handle_namespace (MONO_W32HANDLE_NAMEDMUTEX,
486                                                 utf8_name);
487         if (handle == INVALID_HANDLE_VALUE) {
488                 /* The name has already been used for a different
489                  * object.
490                  */
491                 SetLastError (ERROR_INVALID_HANDLE);
492                 goto cleanup;
493         } else if (!handle) {
494                 /* This name doesn't exist */
495                 SetLastError (ERROR_FILE_NOT_FOUND);    /* yes, really */
496                 goto cleanup;
497         }
498
499         MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: returning named mutex handle %p", __func__, handle);
500
501 cleanup:
502         g_free (utf8_name);
503
504         _wapi_namespace_unlock (NULL);
505         
506         return handle;
507 }