3 * Runtime support for managed Semaphore on Unix
6 * Ludovic Henry (luhenry@microsoft.com)
8 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
11 #include "w32semaphore.h"
14 #include "w32handle-namespace.h"
15 #include "mono/utils/mono-logger-internals.h"
16 #include "mono/metadata/w32handle.h"
23 } MonoW32HandleSemaphore
;
25 struct MonoW32HandleNamedSemaphore
{
26 MonoW32HandleSemaphore s
;
27 MonoW32HandleNamespace sharedns
;
30 static void sem_handle_signal (MonoW32Handle
*handle_data
)
32 MonoW32HandleSemaphore
*sem_handle
;
34 sem_handle
= (MonoW32HandleSemaphore
*) handle_data
->specific
;
36 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_IO_LAYER_SEMAPHORE
, "%s: signalling %s handle %p",
37 __func__
, mono_w32handle_get_typename (handle_data
->type
), handle_data
);
39 /* No idea why max is signed, but thats the spec :-( */
40 if (sem_handle
->val
+ 1 > (guint32
)sem_handle
->max
) {
41 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_IO_LAYER_SEMAPHORE
, "%s: %s handle %p val %d count %d max %d, max value would be exceeded",
42 __func__
, mono_w32handle_get_typename (handle_data
->type
), handle_data
, sem_handle
->val
, 1, sem_handle
->max
);
44 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_IO_LAYER_SEMAPHORE
, "%s: %s handle %p val %d count %d max %d",
45 __func__
, mono_w32handle_get_typename (handle_data
->type
), handle_data
, sem_handle
->val
, 1, sem_handle
->max
);
48 mono_w32handle_set_signal_state (handle_data
, TRUE
, TRUE
);
52 static gboolean
sem_handle_own (MonoW32Handle
*handle_data
, gboolean
*abandoned
)
54 MonoW32HandleSemaphore
*sem_handle
;
58 sem_handle
= (MonoW32HandleSemaphore
*) handle_data
->specific
;
60 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_IO_LAYER_SEMAPHORE
, "%s: owning %s handle %p",
61 __func__
, mono_w32handle_get_typename (handle_data
->type
), handle_data
);
65 if (sem_handle
->val
== 0)
66 mono_w32handle_set_signal_state (handle_data
, FALSE
, FALSE
);
71 static void sema_details (MonoW32Handle
*handle_data
)
73 MonoW32HandleSemaphore
*sem
= (MonoW32HandleSemaphore
*)handle_data
->specific
;
74 g_print ("val: %5u, max: %5d", sem
->val
, sem
->max
);
77 static void namedsema_details (MonoW32Handle
*handle_data
)
79 MonoW32HandleNamedSemaphore
*namedsem
= (MonoW32HandleNamedSemaphore
*)handle_data
->specific
;
80 g_print ("val: %5u, max: %5d, name: \"%s\"", namedsem
->s
.val
, namedsem
->s
.max
, namedsem
->sharedns
.name
);
83 static const gchar
* sema_typename (void)
88 static gsize
sema_typesize (void)
90 return sizeof (MonoW32HandleSemaphore
);
93 static const gchar
* namedsema_typename (void)
98 static gsize
namedsema_typesize (void)
100 return sizeof (MonoW32HandleNamedSemaphore
);
104 mono_w32semaphore_init (void)
106 static MonoW32HandleOps sem_ops
= {
108 sem_handle_signal
, /* signal */
109 sem_handle_own
, /* own */
111 NULL
, /* special_wait */
113 sema_details
, /* details */
114 sema_typename
, /* typename */
115 sema_typesize
, /* typesize */
118 static MonoW32HandleOps namedsem_ops
= {
120 sem_handle_signal
, /* signal */
121 sem_handle_own
, /* own */
123 NULL
, /* special_wait */
125 namedsema_details
, /* details */
126 namedsema_typename
, /* typename */
127 namedsema_typesize
, /* typesize */
130 mono_w32handle_register_ops (MONO_W32TYPE_SEM
, &sem_ops
);
131 mono_w32handle_register_ops (MONO_W32TYPE_NAMEDSEM
, &namedsem_ops
);
133 mono_w32handle_register_capabilities (MONO_W32TYPE_SEM
,
134 (MonoW32HandleCapability
)(MONO_W32HANDLE_CAP_WAIT
| MONO_W32HANDLE_CAP_SIGNAL
));
135 mono_w32handle_register_capabilities (MONO_W32TYPE_NAMEDSEM
,
136 (MonoW32HandleCapability
)(MONO_W32HANDLE_CAP_WAIT
| MONO_W32HANDLE_CAP_SIGNAL
));
140 sem_handle_create (MonoW32HandleSemaphore
*sem_handle
, MonoW32Type type
, gint32 initial
, gint32 max
)
142 MonoW32Handle
*handle_data
;
145 sem_handle
->val
= initial
;
146 sem_handle
->max
= max
;
148 handle
= mono_w32handle_new (type
, sem_handle
);
149 if (handle
== INVALID_HANDLE_VALUE
) {
150 g_warning ("%s: error creating %s handle",
151 __func__
, mono_w32handle_get_typename (type
));
152 mono_w32error_set_last (ERROR_GEN_FAILURE
);
156 if (!mono_w32handle_lookup_and_ref (handle
, &handle_data
))
157 g_error ("%s: unkown handle %p", __func__
, handle
);
159 if (handle_data
->type
!= type
)
160 g_error ("%s: unknown semaphore handle %p", __func__
, handle
);
162 mono_w32handle_lock (handle_data
);
165 mono_w32handle_set_signal_state (handle_data
, TRUE
, FALSE
);
167 mono_w32handle_unlock (handle_data
);
169 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_IO_LAYER_SEMAPHORE
, "%s: created %s handle %p",
170 __func__
, mono_w32handle_get_typename (type
), handle
);
172 mono_w32handle_unref (handle_data
);
178 sem_create (gint32 initial
, gint32 max
)
180 MonoW32HandleSemaphore sem_handle
;
181 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_IO_LAYER_SEMAPHORE
, "%s: creating %s handle, initial %d max %d",
182 __func__
, mono_w32handle_get_typename (MONO_W32TYPE_SEM
), initial
, max
);
183 return sem_handle_create (&sem_handle
, MONO_W32TYPE_SEM
, initial
, max
);
187 namedsem_create (gint32 initial
, gint32 max
, const gunichar2
*name
)
192 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_IO_LAYER_SEMAPHORE
, "%s: creating %s handle, initial %d max %d name \"%s\"",
193 __func__
, mono_w32handle_get_typename (MONO_W32TYPE_NAMEDSEM
), initial
, max
, (const char*)name
);
195 /* w32 seems to guarantee that opening named objects can't race each other */
196 mono_w32handle_namespace_lock ();
199 utf8_name
= g_utf16_to_utf8 (name
, -1, NULL
, &utf8_len
, NULL
);
201 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_IO_LAYER_SEMAPHORE
, "%s: Creating named sem name [%s] initial %d max %d", __func__
, utf8_name
, initial
, max
);
203 handle
= mono_w32handle_namespace_search_handle (MONO_W32TYPE_NAMEDSEM
, utf8_name
);
204 if (handle
== INVALID_HANDLE_VALUE
) {
205 /* The name has already been used for a different object. */
207 mono_w32error_set_last (ERROR_INVALID_HANDLE
);
209 /* Not an error, but this is how the caller is informed that the semaphore wasn't freshly created */
210 mono_w32error_set_last (ERROR_ALREADY_EXISTS
);
212 /* mono_w32handle_namespace_search_handle already adds a ref to the handle */
214 /* A new named semaphore */
215 MonoW32HandleNamedSemaphore namedsem_handle
;
217 size_t len
= utf8_len
< MAX_PATH
? utf8_len
: MAX_PATH
;
218 memcpy (&namedsem_handle
.sharedns
.name
[0], utf8_name
, len
);
219 namedsem_handle
.sharedns
.name
[len
] = '\0';
221 handle
= sem_handle_create ((MonoW32HandleSemaphore
*) &namedsem_handle
, MONO_W32TYPE_NAMEDSEM
, initial
, max
);
226 mono_w32handle_namespace_unlock ();
232 ves_icall_System_Threading_Semaphore_CreateSemaphore_internal (gint32 initialCount
, gint32 maximumCount
, MonoString
*name
, gint32
*error
)
236 if (maximumCount
<= 0) {
237 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_IO_LAYER_SEMAPHORE
, "%s: maximumCount <= 0", __func__
);
239 *error
= ERROR_INVALID_PARAMETER
;
243 if (initialCount
> maximumCount
|| initialCount
< 0) {
244 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_IO_LAYER_SEMAPHORE
, "%s: initialCount > maximumCount or < 0", __func__
);
246 *error
= ERROR_INVALID_PARAMETER
;
250 /* Need to blow away any old errors here, because code tests
251 * for ERROR_ALREADY_EXISTS on success (!) to see if a
252 * semaphore was freshly created
254 mono_w32error_set_last (ERROR_SUCCESS
);
257 sem
= sem_create (initialCount
, maximumCount
);
259 sem
= namedsem_create (initialCount
, maximumCount
, mono_string_chars (name
));
261 *error
= mono_w32error_get_last ();
267 ves_icall_System_Threading_Semaphore_ReleaseSemaphore_internal (gpointer handle
, gint32 releaseCount
, gint32
*prevcount
)
269 MonoW32Handle
*handle_data
;
270 MonoW32HandleSemaphore
*sem_handle
;
273 if (!mono_w32handle_lookup_and_ref (handle
, &handle_data
)) {
274 g_warning ("%s: unkown handle %p", __func__
, handle
);
275 mono_w32error_set_last (ERROR_INVALID_HANDLE
);
279 if (handle_data
->type
!= MONO_W32TYPE_SEM
&& handle_data
->type
!= MONO_W32TYPE_NAMEDSEM
) {
280 g_warning ("%s: unknown sem handle %p", __func__
, handle
);
281 mono_w32error_set_last (ERROR_INVALID_HANDLE
);
282 mono_w32handle_unref (handle_data
);
286 sem_handle
= (MonoW32HandleSemaphore
*) handle_data
->specific
;
288 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_IO_LAYER_SEMAPHORE
, "%s: releasing %s handle %p",
289 __func__
, mono_w32handle_get_typename (handle_data
->type
), handle
);
291 mono_w32handle_lock (handle_data
);
293 /* Do this before checking for count overflow, because overflowing
294 * max is a listed technique for finding the current value */
296 *prevcount
= sem_handle
->val
;
298 /* No idea why max is signed, but thats the spec :-( */
299 if (sem_handle
->val
+ releaseCount
> (guint32
)sem_handle
->max
) {
300 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_IO_LAYER_SEMAPHORE
, "%s: %s handle %p val %d count %d max %d, max value would be exceeded",
301 __func__
, mono_w32handle_get_typename (handle_data
->type
), handle
, sem_handle
->val
, releaseCount
, sem_handle
->max
);
305 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_IO_LAYER_SEMAPHORE
, "%s: %s handle %p val %d count %d max %d",
306 __func__
, mono_w32handle_get_typename (handle_data
->type
), handle
, sem_handle
->val
, releaseCount
, sem_handle
->max
);
308 sem_handle
->val
+= releaseCount
;
309 mono_w32handle_set_signal_state (handle_data
, TRUE
, TRUE
);
314 mono_w32handle_unlock (handle_data
);
315 mono_w32handle_unref (handle_data
);
321 ves_icall_System_Threading_Semaphore_OpenSemaphore_internal (MonoString
*name
, gint32 rights
, gint32
*error
)
326 *error
= ERROR_SUCCESS
;
328 /* w32 seems to guarantee that opening named objects can't race each other */
329 mono_w32handle_namespace_lock ();
331 utf8_name
= g_utf16_to_utf8 (mono_string_chars (name
), -1, NULL
, NULL
, NULL
);
333 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_IO_LAYER_SEMAPHORE
, "%s: Opening named sem [%s]", __func__
, utf8_name
);
335 handle
= mono_w32handle_namespace_search_handle (MONO_W32TYPE_NAMEDSEM
, utf8_name
);
336 if (handle
== INVALID_HANDLE_VALUE
) {
337 /* The name has already been used for a different object. */
338 *error
= ERROR_INVALID_HANDLE
;
340 } else if (!handle
) {
341 /* This name doesn't exist */
342 *error
= ERROR_FILE_NOT_FOUND
;
346 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_IO_LAYER_SEMAPHORE
, "%s: returning named sem handle %p", __func__
, handle
);
351 mono_w32handle_namespace_unlock ();
356 MonoW32HandleNamespace
*
357 mono_w32semaphore_get_namespace (MonoW32HandleNamedSemaphore
*semaphore
)
359 return &semaphore
->sharedns
;