2 * semaphores.c: Semaphore handles
5 * Dick Porter (dick@ximian.com)
7 * (C) 2002 Ximian, Inc.
13 #ifdef HAVE_SEMAPHORE_H
14 #include <semaphore.h>
20 #include <mono/io-layer/wapi.h>
21 #include <mono/io-layer/wapi-private.h>
22 #include <mono/io-layer/misc-private.h>
23 #include <mono/io-layer/handles-private.h>
24 #include <mono/io-layer/mono-mutex.h>
25 #include <mono/io-layer/semaphore-private.h>
29 static void sema_close_shared (gpointer handle);
30 static void sema_signal(gpointer handle);
31 static void sema_own (gpointer handle);
33 struct _WapiHandleOps _wapi_sem_ops = {
34 sema_close_shared, /* close_shared */
35 NULL, /* close_private */
36 sema_signal, /* signal */
41 static mono_once_t sem_ops_once=MONO_ONCE_INIT;
43 static void sem_ops_init (void)
45 _wapi_handle_register_capabilities (WAPI_HANDLE_SEM,
46 WAPI_HANDLE_CAP_WAIT |
47 WAPI_HANDLE_CAP_SIGNAL);
50 static void sema_close_shared (gpointer handle G_GNUC_UNUSED)
52 /* Not really much to do here */
54 g_message(G_GNUC_PRETTY_FUNCTION ": closing sem handle %p", handle);
58 static void sema_signal(gpointer handle)
60 ReleaseSemaphore(handle, 1, NULL);
63 static void sema_own (gpointer handle)
65 struct _WapiHandle_sem *sem_handle;
68 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_SEM,
69 (gpointer *)&sem_handle, NULL);
71 g_warning (G_GNUC_PRETTY_FUNCTION
72 ": error looking up sem handle %p", handle);
77 g_message(G_GNUC_PRETTY_FUNCTION ": owning sem handle %p", handle);
83 g_message (G_GNUC_PRETTY_FUNCTION ": sem %p val now %d", handle,
87 if(sem_handle->val==0) {
88 _wapi_handle_set_signal_state (handle, FALSE, FALSE);
95 * @security: Ignored for now.
96 * @initial: The initial count for the semaphore. The value must be
97 * greater than or equal to zero, and less than or equal to @max.
98 * @max: The maximum count for this semaphore. The value must be
100 * @name: Pointer to a string specifying the name of this semaphore,
101 * or %NULL. Currently ignored.
103 * Creates a new semaphore handle. A semaphore is signalled when its
104 * count is greater than zero, and unsignalled otherwise. The count
105 * is decreased by one whenever a wait function releases a thread that
106 * was waiting for the semaphore. The count is increased by calling
107 * ReleaseSemaphore().
109 * Return value: a new handle, or NULL
111 gpointer CreateSemaphore(WapiSecurityAttributes *security G_GNUC_UNUSED, gint32 initial, gint32 max, const gunichar2 *name G_GNUC_UNUSED)
113 struct _WapiHandle_sem *sem_handle;
119 mono_once (&sem_ops_once, sem_ops_init);
123 g_message(G_GNUC_PRETTY_FUNCTION ": max <= 0");
129 if(initial>max || initial<0) {
131 g_message(G_GNUC_PRETTY_FUNCTION ": initial>max or < 0");
137 handle=_wapi_handle_new (WAPI_HANDLE_SEM);
138 if(handle==_WAPI_HANDLE_INVALID) {
139 g_warning (G_GNUC_PRETTY_FUNCTION
140 ": error creating semaphore handle");
144 pthread_cleanup_push ((void(*)(void *))_wapi_handle_unlock_handle,
146 thr_ret = _wapi_handle_lock_handle (handle);
147 g_assert (thr_ret == 0);
149 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_SEM,
150 (gpointer *)&sem_handle, NULL);
152 g_warning (G_GNUC_PRETTY_FUNCTION
153 ": error lookup up semaphore handle %p", handle);
158 sem_handle->val=initial;
162 _wapi_handle_set_signal_state (handle, TRUE, FALSE);
166 g_message(G_GNUC_PRETTY_FUNCTION
167 ": Created semaphore handle %p initial %d max %d", handle,
172 thr_ret = _wapi_handle_unlock_handle (handle);
173 g_assert (thr_ret == 0);
174 pthread_cleanup_pop (0);
181 * @handle: The semaphore handle to release.
182 * @count: The amount by which the semaphore's count should be
184 * @prevcount: Pointer to a location to store the previous count of
185 * the semaphore, or %NULL.
187 * Increases the count of semaphore @handle by @count.
189 * Return value: %TRUE on success, %FALSE otherwise.
191 gboolean ReleaseSemaphore(gpointer handle, gint32 count, gint32 *prevcount)
193 struct _WapiHandle_sem *sem_handle;
198 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_SEM,
199 (gpointer *)&sem_handle, NULL);
201 g_warning (G_GNUC_PRETTY_FUNCTION
202 ": error looking up sem handle %p", handle);
206 pthread_cleanup_push ((void(*)(void *))_wapi_handle_unlock_handle,
208 thr_ret = _wapi_handle_lock_handle (handle);
209 g_assert (thr_ret == 0);
212 g_message(G_GNUC_PRETTY_FUNCTION ": sem %p val %d count %d",
213 handle, sem_handle->val, count);
216 /* Do this before checking for count overflow, because overflowing max
217 * is a listed technique for finding the current value
219 if(prevcount!=NULL) {
220 *prevcount=sem_handle->val;
223 /* No idea why max is signed, but thats the spec :-( */
224 if(sem_handle->val+count > (guint32)sem_handle->max) {
226 g_message(G_GNUC_PRETTY_FUNCTION ": sem %p max value would be exceeded: max %d current %d count %d",
227 handle, sem_handle->max, sem_handle->val, count);
233 sem_handle->val+=count;
234 _wapi_handle_set_signal_state (handle, TRUE, TRUE);
239 g_message(G_GNUC_PRETTY_FUNCTION ": sem %p val now %d", handle,
244 thr_ret = _wapi_handle_unlock_handle (handle);
245 g_assert (thr_ret == 0);
246 pthread_cleanup_pop (0);