9 #include "mono/io-layer/wapi.h"
10 #include "wapi-private.h"
11 #include "wait-private.h"
12 #include "misc-private.h"
13 #include "handles-private.h"
15 #include "mono-mutex.h"
19 /* emulate sem_t, so that we can prod the internal state more easily */
20 struct _WapiHandle_sem
27 /* This mutex controls access to _all_ semaphores and should not be
28 * locked for long periods.
30 * This global mutex and cond is really for wait_multiple, so we dont
31 * have to try and lock multiple handle mutexes and conditions.
33 static mono_mutex_t sem_mutex=MONO_MUTEX_INITIALIZER;
34 static pthread_cond_t sem_cond=PTHREAD_COND_INITIALIZER;
36 static void sema_close(WapiHandle *handle);
37 static gboolean sema_wait(WapiHandle *handle, WapiHandle *signal, guint32 ms);
38 static guint32 sema_wait_multiple(gpointer data);
39 static void sema_signal(WapiHandle *handle);
41 static struct _WapiHandleOps sem_ops = {
42 sema_close, /* close */
43 NULL, /* getfiletype */
48 NULL, /* setendoffile */
49 NULL, /* getfilesize */
50 NULL, /* getfiletime */
51 NULL, /* setfiletime */
53 sema_wait_multiple, /* wait_multiple */
54 sema_signal, /* signal */
57 static void sema_close(WapiHandle *handle G_GNUC_UNUSED)
59 /* Not really much to do here */
61 g_message(G_GNUC_PRETTY_FUNCTION ": closing sem handle %p", handle);
65 static gboolean sema_wait(WapiHandle *handle, WapiHandle *signal, guint32 ms)
67 struct _WapiHandle_sem *sem_handle=(struct _WapiHandle_sem *)handle;
71 mono_mutex_lock(&sem_mutex);
74 g_message(G_GNUC_PRETTY_FUNCTION ": Sem %p val %d ms %d", handle,
78 /* Signal this handle after we have obtained the semaphore
83 g_message(G_GNUC_PRETTY_FUNCTION ": signalling %p", signal);
85 signal->ops->signal(signal);
88 /* Shortcut when ms==0 */
92 g_message(G_GNUC_PRETTY_FUNCTION ": Polling");
94 if(sem_handle->val>0) {
102 /* Check state first */
103 if(sem_handle->val>0) {
110 g_message(G_GNUC_PRETTY_FUNCTION ": wait for %p INFINITE",
114 ret=mono_cond_wait(&sem_cond, &sem_mutex);
116 /* See if we were signalled (it might have been
119 if(sem_handle->val>0) {
121 g_message(G_GNUC_PRETTY_FUNCTION
122 ": sem %p has been signalled",
128 g_message(G_GNUC_PRETTY_FUNCTION
129 ": sem %p not signalled",
132 goto try_again_infinite;
136 struct timespec timeout;
139 g_message(G_GNUC_PRETTY_FUNCTION ": wait for %p for %d ms",
143 _wapi_calc_timeout(&timeout, ms);
146 ret=mono_cond_timedwait(&sem_cond, &sem_mutex, &timeout);
148 /* See if we were signalled (it might have been
151 if(sem_handle->val>0) {
153 g_message(G_GNUC_PRETTY_FUNCTION
154 ": sem %p has been signalled",
160 g_message(G_GNUC_PRETTY_FUNCTION
161 ": sem %p not signalled",
164 goto try_again_timed;
167 /* ret might be ETIMEDOUT for timeout, or
177 g_message(G_GNUC_PRETTY_FUNCTION
178 ": Waited TRUE, sem %p val now %d", sem_handle,
184 g_message(G_GNUC_PRETTY_FUNCTION ": Waited FALSE, sem %p",
189 mono_mutex_unlock(&sem_mutex);
193 static guint32 sema_wait_multiple(gpointer data G_GNUC_UNUSED)
195 WaitQueueItem *item=(WaitQueueItem *)data;
196 guint32 numhandles, count;
197 struct timespec timeout;
201 numhandles=item->handles[WAPI_HANDLE_SEM]->len;
204 g_message(G_GNUC_PRETTY_FUNCTION
205 ": waiting on %d sem handles for %d ms", numhandles,
209 mono_mutex_lock(&sem_mutex);
211 /* First, check if any of the handles are already signalled.
212 * If waitall is specified we only return if all handles have
215 for(count=0, i=0; i<numhandles; i++) {
216 struct _WapiHandle_sem *sem_handle;
218 sem_handle=g_ptr_array_index(item->handles[WAPI_HANDLE_SEM],
220 if(sem_handle->val>0) {
226 g_message(G_GNUC_PRETTY_FUNCTION
227 ": Preliminary check found %d handles signalled", count);
230 if((item->waitall==TRUE && count==numhandles) ||
231 (item->waitall==FALSE && count>0)) {
235 /* OK, we need to wait for some */
236 if(item->timeout!=INFINITE) {
237 _wapi_calc_timeout(&timeout, item->timeout);
240 /* We can restart from here without resetting the timeout,
241 * because it is calculated from absolute time, not an offset.
244 if(item->timeout==INFINITE) {
245 ret=mono_cond_wait(&sem_cond, &sem_mutex);
247 ret=mono_cond_timedwait(&sem_cond, &sem_mutex, &timeout);
252 g_message(G_GNUC_PRETTY_FUNCTION ": Wait timed out");
259 g_message(G_GNUC_PRETTY_FUNCTION ": Sem posted, checking status");
262 /* A semaphore was posted, so see if it was one we are
265 for(count=0, i=0; i<numhandles; i++) {
266 struct _WapiHandle_sem *sem_handle;
268 sem_handle=g_ptr_array_index(item->handles[WAPI_HANDLE_SEM],
270 if(sem_handle->val>0) {
276 g_message(G_GNUC_PRETTY_FUNCTION
277 ": Check after sem post found %d handles signalled", count);
280 if((item->waitall==TRUE && count==numhandles) ||
281 (item->waitall==FALSE && count>0)) {
285 /* Either we have waitall set with more handles to wait for, or
286 * the sem that was posted wasn't interesting to us
289 g_message(G_GNUC_PRETTY_FUNCTION ": Waiting a bit longer");
295 item->waited[WAPI_HANDLE_SEM]=TRUE;
296 item->waitcount[WAPI_HANDLE_SEM]=count;
298 if((item->waitall==TRUE && count==numhandles) ||
299 (item->waitall==FALSE && count>0)) {
300 /* Decrease all waited semaphores */
301 for(i=0; i<numhandles; i++) {
302 struct _WapiHandle_sem *sem_handle;
305 sem_handle=g_ptr_array_index(
306 item->handles[WAPI_HANDLE_SEM], i);
308 idx=g_array_index(item->waitindex[WAPI_HANDLE_SEM],
310 _wapi_handle_set_lowest(item, idx);
312 if(sem_handle->val>0) {
318 mono_mutex_unlock(&sem_mutex);
323 static void sema_signal(WapiHandle *handle)
325 ReleaseSemaphore(handle, 1, NULL);
330 * @security: Ignored for now.
331 * @initial: The initial count for the semaphore. The value must be
332 * greater than or equal to zero, and less than or equal to @max.
333 * @max: The maximum count for this semaphore. The value must be
335 * @name: Pointer to a string specifying the name of this semaphore,
336 * or %NULL. Currently ignored.
338 * Creates a new semaphore handle. A semaphore is signalled when its
339 * count is greater than zero, and unsignalled otherwise. The count
340 * is decreased by one whenever a wait function releases a thread that
341 * was waiting for the semaphore. The count is increased by calling
342 * ReleaseSemaphore().
344 * Return value: a new handle, or NULL
346 WapiHandle *CreateSemaphore(WapiSecurityAttributes *security G_GNUC_UNUSED, gint32 initial, gint32 max, const guchar *name G_GNUC_UNUSED)
348 struct _WapiHandle_sem *sem_handle;
353 g_message(G_GNUC_PRETTY_FUNCTION ": max <= 0");
359 if(initial>max || initial<0) {
361 g_message(G_GNUC_PRETTY_FUNCTION ": initial>max or < 0");
367 sem_handle=(struct _WapiHandle_sem *)g_new0(struct _WapiHandle_sem, 1);
368 handle=(WapiHandle *)sem_handle;
369 _WAPI_HANDLE_INIT(handle, WAPI_HANDLE_SEM, sem_ops);
371 sem_handle->val=initial;
375 g_message(G_GNUC_PRETTY_FUNCTION ": Created semaphore handle %p",
384 * @handle: The semaphore handle to release.
385 * @count: The amount by which the semaphore's count should be
387 * @prevcount: Pointer to a location to store the previous count of
388 * the semaphore, or %NULL.
390 * Increases the count of semaphore @handle by @count.
392 * Return value: %TRUE on success, %FALSE otherwise.
394 gboolean ReleaseSemaphore(WapiHandle *handle, gint32 count, gint32 *prevcount)
396 struct _WapiHandle_sem *sem_handle=(struct _WapiHandle_sem *)handle;
400 mono_mutex_lock(&sem_mutex);
403 g_message(G_GNUC_PRETTY_FUNCTION ": sem %p val %d count %d",
404 sem_handle, sem_handle->val, count);
407 /* Do this before checking for count overflow, because overflowing max
408 * is a listed technique for finding the current value
410 if(prevcount!=NULL) {
411 *prevcount=sem_handle->val;
414 /* No idea why max is signed, but thats the spec :-( */
415 if(sem_handle->val+count > (guint32)sem_handle->max) {
417 g_message(G_GNUC_PRETTY_FUNCTION ": sem %p max value would be exceeded: max %d current %d count %d",
418 handle, sem_handle->max, sem_handle->val, count);
424 sem_handle->val+=count;
425 pthread_cond_broadcast(&sem_cond);
429 g_message(G_GNUC_PRETTY_FUNCTION ": sem %p val now %d", sem_handle,
434 mono_mutex_unlock(&sem_mutex);