Ignoring case for MachineName in EventLogTest
[mono.git] / mono / io-layer / semaphores.c
1 /*
2  * semaphores.c:  Semaphore handles
3  *
4  * Author:
5  *      Dick Porter (dick@ximian.com)
6  *
7  * (C) 2002 Ximian, Inc.
8  */
9
10 #include <config.h>
11 #include <glib.h>
12 #include <pthread.h>
13 #ifdef HAVE_SEMAPHORE_H
14 #include <semaphore.h>
15 #endif
16 #include <errno.h>
17 #include <string.h>
18 #include <sys/time.h>
19
20 #include <mono/io-layer/wapi.h>
21 #include <mono/io-layer/wapi-private.h>
22 #include <mono/io-layer/semaphore-private.h>
23 #include <mono/io-layer/io-trace.h>
24 #include <mono/utils/mono-once.h>
25 #include <mono/utils/mono-logger-internals.h>
26 #include <mono/utils/w32handle.h>
27
28 static void sema_signal(gpointer handle);
29 static gboolean sema_own (gpointer handle);
30 static void sema_details (gpointer data);
31 static const gchar* sema_typename (void);
32 static gsize sema_typesize (void);
33
34 static void namedsema_signal (gpointer handle);
35 static gboolean namedsema_own (gpointer handle);
36 static void namedsema_details (gpointer data);
37 static const gchar* namedsema_typename (void);
38 static gsize namedsema_typesize (void);
39
40 static MonoW32HandleOps _wapi_sem_ops = {
41         NULL,                   /* close */
42         sema_signal,            /* signal */
43         sema_own,               /* own */
44         NULL,                   /* is_owned */
45         NULL,                   /* special_wait */
46         NULL,                   /* prewait */
47         sema_details,   /* details */
48         sema_typename,  /* typename */
49         sema_typesize,  /* typesize */
50 };
51
52 static MonoW32HandleOps _wapi_namedsem_ops = {
53         NULL,                   /* close */
54         namedsema_signal,       /* signal */
55         namedsema_own,          /* own */
56         NULL,                   /* is_owned */
57         NULL,                   /* special_wait */
58         NULL,                   /* prewait */
59         namedsema_details,      /* details */
60         namedsema_typename,     /* typename */
61         namedsema_typesize,     /* typesize */
62 };
63
64 void
65 _wapi_semaphore_init (void)
66 {
67         mono_w32handle_register_ops (MONO_W32HANDLE_SEM,      &_wapi_sem_ops);
68         mono_w32handle_register_ops (MONO_W32HANDLE_NAMEDSEM, &_wapi_namedsem_ops);
69
70         mono_w32handle_register_capabilities (MONO_W32HANDLE_SEM,
71                 (MonoW32HandleCapability)(MONO_W32HANDLE_CAP_WAIT | MONO_W32HANDLE_CAP_SIGNAL));
72         mono_w32handle_register_capabilities (MONO_W32HANDLE_NAMEDSEM,
73                 (MonoW32HandleCapability)(MONO_W32HANDLE_CAP_WAIT | MONO_W32HANDLE_CAP_SIGNAL));
74 }
75
76 static const char* sem_handle_type_to_string (MonoW32HandleType type)
77 {
78         switch (type) {
79         case MONO_W32HANDLE_SEM: return "sem";
80         case MONO_W32HANDLE_NAMEDSEM: return "named sem";
81         default:
82                 g_assert_not_reached ();
83         }
84 }
85
86 static gboolean sem_handle_own (gpointer handle, MonoW32HandleType type)
87 {
88         struct _WapiHandle_sem *sem_handle;
89
90         if (!mono_w32handle_lookup (handle, type, (gpointer *)&sem_handle)) {
91                 g_warning ("%s: error looking up %s handle %p",
92                         __func__, sem_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",
97                 __func__, sem_handle_type_to_string (type), handle);
98
99         sem_handle->val--;
100
101         if (sem_handle->val == 0)
102                 mono_w32handle_set_signal_state (handle, FALSE, FALSE);
103
104         return TRUE;
105 }
106
107 static void sema_signal(gpointer handle)
108 {
109         ReleaseSemaphore(handle, 1, NULL);
110 }
111
112 static gboolean sema_own (gpointer handle)
113 {
114         return sem_handle_own (handle, MONO_W32HANDLE_SEM);
115 }
116
117 static void namedsema_signal (gpointer handle)
118 {
119         ReleaseSemaphore (handle, 1, NULL);
120 }
121
122 /* NB, always called with the shared handle lock held */
123 static gboolean namedsema_own (gpointer handle)
124 {
125         return sem_handle_own (handle, MONO_W32HANDLE_NAMEDSEM);
126 }
127
128 static void sema_details (gpointer data)
129 {
130         struct _WapiHandle_sem *sem = (struct _WapiHandle_sem *)data;
131         g_print ("val: %5u, max: %5d", sem->val, sem->max);
132 }
133
134 static void namedsema_details (gpointer data)
135 {
136         struct _WapiHandle_namedsem *namedsem = (struct _WapiHandle_namedsem *)data;
137         g_print ("val: %5u, max: %5d, name: \"%s\"", namedsem->s.val, namedsem->s.max, namedsem->sharedns.name);
138 }
139
140 static const gchar* sema_typename (void)
141 {
142         return "Semaphore";
143 }
144
145 static gsize sema_typesize (void)
146 {
147         return sizeof (struct _WapiHandle_sem);
148 }
149
150 static const gchar* namedsema_typename (void)
151 {
152         return "N.Semaphore";
153 }
154
155 static gsize namedsema_typesize (void)
156 {
157         return sizeof (struct _WapiHandle_namedsem);
158 }
159
160 static gpointer sem_handle_create (struct _WapiHandle_sem *sem_handle, MonoW32HandleType type, gint32 initial, gint32 max)
161 {
162         gpointer handle;
163         int thr_ret;
164
165         sem_handle->val = initial;
166         sem_handle->max = max;
167
168         handle = mono_w32handle_new (type, sem_handle);
169         if (handle == INVALID_HANDLE_VALUE) {
170                 g_warning ("%s: error creating %s handle",
171                         __func__, sem_handle_type_to_string (type));
172                 SetLastError (ERROR_GEN_FAILURE);
173                 return NULL;
174         }
175
176         thr_ret = mono_w32handle_lock_handle (handle);
177         g_assert (thr_ret == 0);
178
179         if (initial != 0)
180                 mono_w32handle_set_signal_state (handle, TRUE, FALSE);
181
182         thr_ret = mono_w32handle_unlock_handle (handle);
183         g_assert (thr_ret == 0);
184
185         MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: created %s handle %p",
186                 __func__, sem_handle_type_to_string (type), handle);
187
188         return handle;
189 }
190
191 static gpointer sem_create (gint32 initial, gint32 max)
192 {
193         struct _WapiHandle_sem sem_handle;
194         MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: creating %s handle, initial %d max %d",
195                 __func__, sem_handle_type_to_string (MONO_W32HANDLE_SEM), initial, max);
196         return sem_handle_create (&sem_handle, MONO_W32HANDLE_SEM, initial, max);
197 }
198
199 static gpointer namedsem_create (gint32 initial, gint32 max, const gunichar2 *name)
200 {
201         gpointer handle;
202         gchar *utf8_name;
203         int thr_ret;
204
205         MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: creating %s handle, initial %d max %d name \"%s\"",
206                 __func__, sem_handle_type_to_string (MONO_W32HANDLE_NAMEDSEM), initial, max, name);
207
208         /* w32 seems to guarantee that opening named objects can't race each other */
209         thr_ret = _wapi_namespace_lock ();
210         g_assert (thr_ret == 0);
211
212         utf8_name = g_utf16_to_utf8 (name, -1, NULL, NULL, NULL);
213
214         MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Creating named sem name [%s] initial %d max %d", __func__, utf8_name, initial, max);
215
216         handle = _wapi_search_handle_namespace (MONO_W32HANDLE_NAMEDSEM, utf8_name);
217         if (handle == INVALID_HANDLE_VALUE) {
218                 /* The name has already been used for a different object. */
219                 handle = NULL;
220                 SetLastError (ERROR_INVALID_HANDLE);
221         } else if (handle) {
222                 /* Not an error, but this is how the caller is informed that the semaphore wasn't freshly created */
223                 SetLastError (ERROR_ALREADY_EXISTS);
224
225                 /* this is used as creating a new handle */
226                 mono_w32handle_ref (handle);
227         } else {
228                 /* A new named semaphore */
229                 struct _WapiHandle_namedsem namedsem_handle;
230
231                 strncpy (&namedsem_handle.sharedns.name [0], utf8_name, MAX_PATH);
232                 namedsem_handle.sharedns.name [MAX_PATH] = '\0';
233
234                 handle = sem_handle_create ((struct _WapiHandle_sem*) &namedsem_handle, MONO_W32HANDLE_NAMEDSEM, initial, max);
235         }
236
237         g_free (utf8_name);
238
239         thr_ret = _wapi_namespace_unlock (NULL);
240         g_assert (thr_ret == 0);
241
242         return handle;
243 }
244
245
246 /**
247  * CreateSemaphore:
248  * @security: Ignored for now.
249  * @initial: The initial count for the semaphore.  The value must be
250  * greater than or equal to zero, and less than or equal to @max.
251  * @max: The maximum count for this semaphore.  The value must be
252  * greater than zero.
253  * @name: Pointer to a string specifying the name of this semaphore,
254  * or %NULL.  Currently ignored.
255  *
256  * Creates a new semaphore handle.  A semaphore is signalled when its
257  * count is greater than zero, and unsignalled otherwise.  The count
258  * is decreased by one whenever a wait function releases a thread that
259  * was waiting for the semaphore.  The count is increased by calling
260  * ReleaseSemaphore().
261  *
262  * Return value: a new handle, or NULL
263  */
264 gpointer CreateSemaphore(WapiSecurityAttributes *security G_GNUC_UNUSED, gint32 initial, gint32 max, const gunichar2 *name)
265 {
266         if (max <= 0) {
267                 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: max <= 0", __func__);
268
269                 SetLastError (ERROR_INVALID_PARAMETER);
270                 return(NULL);
271         }
272         
273         if (initial > max || initial < 0) {
274                 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: initial>max or < 0", __func__);
275
276                 SetLastError (ERROR_INVALID_PARAMETER);
277                 return(NULL);
278         }
279
280         /* Need to blow away any old errors here, because code tests
281          * for ERROR_ALREADY_EXISTS on success (!) to see if a
282          * semaphore was freshly created
283          */
284         SetLastError (ERROR_SUCCESS);
285
286         return name ? namedsem_create (initial, max, name) : sem_create (initial, max);
287 }
288
289 /**
290  * ReleaseSemaphore:
291  * @handle: The semaphore handle to release.
292  * @count: The amount by which the semaphore's count should be
293  * increased.
294  * @prevcount: Pointer to a location to store the previous count of
295  * the semaphore, or %NULL.
296  *
297  * Increases the count of semaphore @handle by @count.
298  *
299  * Return value: %TRUE on success, %FALSE otherwise.
300  */
301 gboolean ReleaseSemaphore(gpointer handle, gint32 count, gint32 *prevcount)
302 {
303         MonoW32HandleType type;
304         struct _WapiHandle_sem *sem_handle;
305         int thr_ret;
306         gboolean ret;
307
308         if (!handle) {
309                 SetLastError (ERROR_INVALID_HANDLE);
310                 return FALSE;
311         }
312
313         switch (type = mono_w32handle_get_type (handle)) {
314         case MONO_W32HANDLE_SEM:
315         case MONO_W32HANDLE_NAMEDSEM:
316                 break;
317         default:
318                 SetLastError (ERROR_INVALID_HANDLE);
319                 return FALSE;
320         }
321
322         if (!mono_w32handle_lookup (handle, type, (gpointer *)&sem_handle)) {
323                 g_warning ("%s: error looking up sem handle %p", __func__, handle);
324                 return FALSE;
325         }
326
327         MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: releasing %s handle %p",
328                 __func__, sem_handle_type_to_string (type), handle);
329
330         thr_ret = mono_w32handle_lock_handle (handle);
331         g_assert (thr_ret == 0);
332
333         /* Do this before checking for count overflow, because overflowing
334          * max is a listed technique for finding the current value */
335         if (prevcount)
336                 *prevcount = sem_handle->val;
337
338         /* No idea why max is signed, but thats the spec :-( */
339         if (sem_handle->val + count > (guint32)sem_handle->max) {
340                 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: %s handle %p val %d count %d max %d, max value would be exceeded",
341                         __func__, sem_handle_type_to_string (type), handle, sem_handle->val, count, sem_handle->max, count);
342
343                 ret = FALSE;
344         } else {
345                 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: %s handle %p val %d count %d max %d",
346                         __func__, sem_handle_type_to_string (type), handle, sem_handle->val, count, sem_handle->max, count);
347
348                 sem_handle->val += count;
349                 mono_w32handle_set_signal_state (handle, TRUE, TRUE);
350
351                 ret = TRUE;
352         }
353
354         thr_ret = mono_w32handle_unlock_handle (handle);
355         g_assert (thr_ret == 0);
356
357         return ret;
358 }
359
360 gpointer OpenSemaphore (guint32 access G_GNUC_UNUSED, gboolean inherit G_GNUC_UNUSED,
361                         const gunichar2 *name)
362 {
363         gpointer handle;
364         gchar *utf8_name;
365         int thr_ret;
366
367         /* w32 seems to guarantee that opening named objects can't
368          * race each other
369          */
370         thr_ret = _wapi_namespace_lock ();
371         g_assert (thr_ret == 0);
372         
373         utf8_name = g_utf16_to_utf8 (name, -1, NULL, NULL, NULL);
374         
375         MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Opening named sem [%s]", __func__, utf8_name);
376
377         handle = _wapi_search_handle_namespace (MONO_W32HANDLE_NAMEDSEM,
378                                                 utf8_name);
379         if (handle == INVALID_HANDLE_VALUE) {
380                 /* The name has already been used for a different
381                  * object.
382                  */
383                 SetLastError (ERROR_INVALID_HANDLE);
384                 goto cleanup;
385         } else if (!handle) {
386                 /* This name doesn't exist */
387                 SetLastError (ERROR_FILE_NOT_FOUND);    /* yes, really */
388                 goto cleanup;
389         }
390
391         MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: returning named sem handle %p", __func__, handle);
392
393 cleanup:
394         g_free (utf8_name);
395         
396         _wapi_namespace_unlock (NULL);
397         
398         return handle;
399 }