[io-layer] Move WapiHandleType and WapiHandleOps to handles-private.h
[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/handles-private.h>
19 #include <mono/io-layer/mutex-private.h>
20 #include <mono/io-layer/io-trace.h>
21 #include <mono/utils/mono-once.h>
22 #include <mono/utils/mono-logger-internals.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 WapiHandleOps _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 WapiHandleOps _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 static mono_once_t mutex_ops_once=MONO_ONCE_INIT;
65
66 static void mutex_ops_init (void)
67 {
68         _wapi_handle_register_capabilities (WAPI_HANDLE_MUTEX,
69                 (WapiHandleCapability)(WAPI_HANDLE_CAP_WAIT | WAPI_HANDLE_CAP_SIGNAL | WAPI_HANDLE_CAP_OWN));
70         _wapi_handle_register_capabilities (WAPI_HANDLE_NAMEDMUTEX,
71                 (WapiHandleCapability)(WAPI_HANDLE_CAP_WAIT | WAPI_HANDLE_CAP_SIGNAL | WAPI_HANDLE_CAP_OWN));
72 }
73
74 static const char* mutex_handle_type_to_string (WapiHandleType type)
75 {
76         switch (type) {
77         case WAPI_HANDLE_MUTEX: return "mutex";
78         case WAPI_HANDLE_NAMEDMUTEX: return "named mutex";
79         default:
80                 g_assert_not_reached ();
81         }
82 }
83
84 static gboolean
85 mutex_handle_own (gpointer handle, WapiHandleType type)
86 {
87         struct _WapiHandle_mutex *mutex_handle;
88
89         if (!_wapi_lookup_handle (handle, type, (gpointer *)&mutex_handle)) {
90                 g_warning ("%s: error looking up %s handle %p", __func__, mutex_handle_type_to_string (type), handle);
91                 return FALSE;
92         }
93
94         MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: owning %s handle %p, tid %p, recursion %u",
95                 __func__, mutex_handle_type_to_string (type), handle, (gpointer) mutex_handle->tid, mutex_handle->recursion);
96
97         _wapi_thread_own_mutex (handle);
98
99         mutex_handle->tid = pthread_self ();
100         mutex_handle->recursion++;
101
102         _wapi_handle_set_signal_state (handle, FALSE, FALSE);
103
104         return TRUE;
105 }
106
107 static gboolean
108 mutex_handle_is_owned (gpointer handle, WapiHandleType type)
109 {
110         struct _WapiHandle_mutex *mutex_handle;
111
112         if (!_wapi_lookup_handle (handle, type, (gpointer *)&mutex_handle)) {
113                 g_warning ("%s: error looking up %s handle %p", __func__, mutex_handle_type_to_string (type), handle);
114                 return FALSE;
115         }
116
117         MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: testing ownership %s handle %p",
118                 __func__, mutex_handle_type_to_string (type), handle);
119
120         if (mutex_handle->recursion > 0 && pthread_equal (mutex_handle->tid, pthread_self ())) {
121                 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: %s handle %p owned by %p",
122                         __func__, mutex_handle_type_to_string (type), handle, (gpointer) pthread_self ());
123                 return TRUE;
124         } else {
125                 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: %s handle %p not owned by %p, but locked %d times by %p",
126                         __func__, mutex_handle_type_to_string (type), handle, (gpointer) pthread_self (), mutex_handle->recursion, (gpointer) mutex_handle->tid);
127                 return FALSE;
128         }
129 }
130
131 static void mutex_signal(gpointer handle)
132 {
133         ReleaseMutex(handle);
134 }
135
136 static gboolean mutex_own (gpointer handle)
137 {
138         return mutex_handle_own (handle, WAPI_HANDLE_MUTEX);
139 }
140
141 static gboolean mutex_is_owned (gpointer handle)
142 {
143         
144         return mutex_handle_is_owned (handle, WAPI_HANDLE_MUTEX);
145 }
146
147 static void namedmutex_signal (gpointer handle)
148 {
149         ReleaseMutex(handle);
150 }
151
152 /* NB, always called with the shared handle lock held */
153 static gboolean namedmutex_own (gpointer handle)
154 {
155         return mutex_handle_own (handle, WAPI_HANDLE_NAMEDMUTEX);
156 }
157
158 static gboolean namedmutex_is_owned (gpointer handle)
159 {
160         return mutex_handle_is_owned (handle, WAPI_HANDLE_NAMEDMUTEX);
161 }
162
163 static void mutex_handle_prewait (gpointer handle, WapiHandleType type)
164 {
165         /* If the mutex is not currently owned, do nothing and let the
166          * usual wait carry on.  If it is owned, check that the owner
167          * is still alive; if it isn't we override the previous owner
168          * and assume that process exited abnormally and failed to
169          * clean up.
170          */
171         struct _WapiHandle_mutex *mutex_handle;
172
173         if (!_wapi_lookup_handle (handle, type, (gpointer *)&mutex_handle)) {
174                 g_warning ("%s: error looking up %s handle %p",
175                         __func__, mutex_handle_type_to_string (type), handle);
176                 return;
177         }
178
179         MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: pre-waiting %s handle %p, owned? %s",
180                 __func__, mutex_handle_type_to_string (type), handle, mutex_handle->recursion != 0 ? "true" : "false");
181 }
182
183 /* The shared state is not locked when prewait methods are called */
184 static void mutex_prewait (gpointer handle)
185 {
186         mutex_handle_prewait (handle, WAPI_HANDLE_MUTEX);
187 }
188
189 /* The shared state is not locked when prewait methods are called */
190 static void namedmutex_prewait (gpointer handle)
191 {
192         mutex_handle_prewait (handle, WAPI_HANDLE_NAMEDMUTEX);
193 }
194
195 static void mutex_details (gpointer data)
196 {
197         struct _WapiHandle_mutex *mut = (struct _WapiHandle_mutex *)data;
198         
199 #ifdef PTHREAD_POINTER_ID
200         g_print ("own: %5p, count: %5u", mut->tid, mut->recursion);
201 #else
202         g_print ("own: %5ld, count: %5u", mut->tid, mut->recursion);
203 #endif
204 }
205
206 static void namedmutex_details (gpointer data)
207 {
208         struct _WapiHandle_namedmutex *namedmut = (struct _WapiHandle_namedmutex *)data;
209         
210 #ifdef PTHREAD_POINTER_ID
211         g_print ("own: %5p, count: %5u, name: \"%s\"",
212                 namedmut->m.tid, namedmut->m.recursion, namedmut->sharedns.name);
213 #else
214         g_print ("own: %5ld, count: %5u, name: \"%s\"",
215                 namedmut->m.tid, namedmut->m.recursion, namedmut->sharedns.name);
216 #endif
217 }
218
219 static const gchar* mutex_typename (void)
220 {
221         return "Mutex";
222 }
223
224 static gsize mutex_typesize (void)
225 {
226         return sizeof (struct _WapiHandle_mutex);
227 }
228
229 static const gchar* namedmutex_typename (void)
230 {
231         return "N.Mutex";
232 }
233
234 static gsize namedmutex_typesize (void)
235 {
236         return sizeof (struct _WapiHandle_namedmutex);
237 }
238
239 /* When a thread exits, any mutexes it still holds need to be signalled. */
240 void _wapi_mutex_abandon (gpointer handle, pid_t pid, pthread_t tid)
241 {
242         WapiHandleType type;
243         struct _WapiHandle_mutex *mutex_handle;
244         int thr_ret;
245
246         switch (type = _wapi_handle_type (handle)) {
247         case WAPI_HANDLE_MUTEX:
248         case WAPI_HANDLE_NAMEDMUTEX:
249                 break;
250         default:
251                 g_assert_not_reached ();
252         }
253
254         if (!_wapi_lookup_handle (handle, type, (gpointer *)&mutex_handle)) {
255                 g_warning ("%s: error looking up %s handle %p",
256                         __func__, mutex_handle_type_to_string (type), handle);
257                 return;
258         }
259
260         MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: abandon %s handle %p",
261                 __func__, mutex_handle_type_to_string (type), handle);
262
263         thr_ret = _wapi_handle_lock_handle (handle);
264         g_assert (thr_ret == 0);
265
266         if (pthread_equal (mutex_handle->tid, tid)) {
267                 mutex_handle->recursion = 0;
268                 mutex_handle->tid = 0;
269
270                 _wapi_handle_set_signal_state (handle, TRUE, FALSE);
271
272                 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: abandoned %s handle %p",
273                         __func__, mutex_handle_type_to_string (type), handle);
274         }
275
276         thr_ret = _wapi_handle_unlock_handle (handle);
277         g_assert (thr_ret == 0);
278 }
279
280 static gpointer mutex_handle_create (struct _WapiHandle_mutex *mutex_handle, WapiHandleType type, gboolean owned)
281 {
282         gpointer handle;
283         int thr_ret;
284
285         mutex_handle->tid = 0;
286         mutex_handle->recursion = 0;
287
288         handle = _wapi_handle_new (type, mutex_handle);
289         if (handle == _WAPI_HANDLE_INVALID) {
290                 g_warning ("%s: error creating %s handle",
291                         __func__, mutex_handle_type_to_string (type));
292                 SetLastError (ERROR_GEN_FAILURE);
293                 return NULL;
294         }
295
296         thr_ret = _wapi_handle_lock_handle (handle);
297         g_assert (thr_ret == 0);
298
299         if (owned)
300                 mutex_handle_own (handle, type);
301         else
302                 _wapi_handle_set_signal_state (handle, TRUE, FALSE);
303
304         thr_ret = _wapi_handle_unlock_handle (handle);
305         g_assert (thr_ret == 0);
306
307         MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: created %s handle %p",
308                 __func__, mutex_handle_type_to_string (type), handle);
309
310         return handle;
311 }
312
313 static gpointer mutex_create (gboolean owned)
314 {
315         struct _WapiHandle_mutex mutex_handle;
316         MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: creating %s handle",
317                 __func__, mutex_handle_type_to_string (WAPI_HANDLE_MUTEX));
318         return mutex_handle_create (&mutex_handle, WAPI_HANDLE_MUTEX, owned);
319 }
320
321 static gpointer namedmutex_create (gboolean owned, const gunichar2 *name)
322 {
323         gpointer handle;
324         gchar *utf8_name;
325         int thr_ret;
326
327         MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: creating %s handle",
328                 __func__, mutex_handle_type_to_string (WAPI_HANDLE_NAMEDMUTEX));
329
330         /* w32 seems to guarantee that opening named objects can't race each other */
331         thr_ret = _wapi_namespace_lock ();
332         g_assert (thr_ret == 0);
333
334         utf8_name = g_utf16_to_utf8 (name, -1, NULL, NULL, NULL);
335
336         handle = _wapi_search_handle_namespace (WAPI_HANDLE_NAMEDMUTEX, utf8_name);
337         if (handle == _WAPI_HANDLE_INVALID) {
338                 /* The name has already been used for a different object. */
339                 handle = NULL;
340                 SetLastError (ERROR_INVALID_HANDLE);
341         } else if (handle) {
342                 /* Not an error, but this is how the caller is informed that the mutex wasn't freshly created */
343                 SetLastError (ERROR_ALREADY_EXISTS);
344
345                 /* this is used as creating a new handle */
346                 _wapi_handle_ref (handle);
347         } else {
348                 /* A new named mutex */
349                 struct _WapiHandle_namedmutex namedmutex_handle;
350
351                 strncpy (&namedmutex_handle.sharedns.name [0], utf8_name, MAX_PATH);
352                 namedmutex_handle.sharedns.name [MAX_PATH] = '\0';
353
354                 handle = mutex_handle_create ((struct _WapiHandle_mutex*) &namedmutex_handle, WAPI_HANDLE_NAMEDMUTEX, owned);
355         }
356
357         g_free (utf8_name);
358
359         thr_ret = _wapi_namespace_unlock (NULL);
360         g_assert (thr_ret == 0);
361
362         return handle;
363 }
364
365 /**
366  * CreateMutex:
367  * @security: Ignored for now.
368  * @owned: If %TRUE, the mutex is created with the calling thread
369  * already owning the mutex.
370  * @name:Pointer to a string specifying the name of this mutex, or
371  * %NULL.
372  *
373  * Creates a new mutex handle.  A mutex is signalled when no thread
374  * owns it.  A thread acquires ownership of the mutex by waiting for
375  * it with WaitForSingleObject() or WaitForMultipleObjects().  A
376  * thread relinquishes ownership with ReleaseMutex().
377  *
378  * A thread that owns a mutex can specify the same mutex in repeated
379  * wait function calls without blocking.  The thread must call
380  * ReleaseMutex() an equal number of times to release the mutex.
381  *
382  * Return value: A new handle, or %NULL on error.
383  */
384 gpointer CreateMutex(WapiSecurityAttributes *security G_GNUC_UNUSED, gboolean owned, const gunichar2 *name)
385 {
386         mono_once (&mutex_ops_once, mutex_ops_init);
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         WapiHandleType 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 = _wapi_handle_type (handle)) {
419         case WAPI_HANDLE_MUTEX:
420         case WAPI_HANDLE_NAMEDMUTEX:
421                 break;
422         default:
423                 SetLastError (ERROR_INVALID_HANDLE);
424                 return FALSE;
425         }
426
427         if (!_wapi_lookup_handle (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 = _wapi_handle_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                         _wapi_handle_set_signal_state (handle, TRUE, FALSE);
460                 }
461         }
462
463         thr_ret = _wapi_handle_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         mono_once (&mutex_ops_once, mutex_ops_init);
476
477         /* w32 seems to guarantee that opening named objects can't
478          * race each other
479          */
480         thr_ret = _wapi_namespace_lock ();
481         g_assert (thr_ret == 0);
482
483         utf8_name = g_utf16_to_utf8 (name, -1, NULL, NULL, NULL);
484         
485         MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Opening named mutex [%s]", __func__, utf8_name);
486         
487         handle = _wapi_search_handle_namespace (WAPI_HANDLE_NAMEDMUTEX,
488                                                 utf8_name);
489         if (handle == _WAPI_HANDLE_INVALID) {
490                 /* The name has already been used for a different
491                  * object.
492                  */
493                 SetLastError (ERROR_INVALID_HANDLE);
494                 goto cleanup;
495         } else if (!handle) {
496                 /* This name doesn't exist */
497                 SetLastError (ERROR_FILE_NOT_FOUND);    /* yes, really */
498                 goto cleanup;
499         }
500
501         MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: returning named mutex handle %p", __func__, handle);
502
503 cleanup:
504         g_free (utf8_name);
505
506         _wapi_namespace_unlock (NULL);
507         
508         return handle;
509 }