44b1d652b102a97cdffd4353f49626e4f2337e59
[mono.git] / mono / io-layer / events.c
1 #include <config.h>
2 #include <glib.h>
3 #include <pthread.h>
4 #include <string.h>
5
6 #include "mono/io-layer/wapi.h"
7 #include "wapi-private.h"
8 #include "wait-private.h"
9 #include "handles-private.h"
10 #include "misc-private.h"
11
12 #define DEBUG
13
14 /* event_wait() uses the event-private condition to signal that the
15  * event has been set
16  *
17  * Hold mutex before setting the event, and before the final test
18  * Hold rwlock for reading while testing the event
19  * Hold rwlock for writing before resetting the event
20  */
21 struct _WapiHandle_event
22 {
23         WapiHandle handle;
24         pthread_mutex_t mutex;
25         pthread_cond_t cond;
26         pthread_rwlock_t rwlock;
27         gboolean manual;
28 };
29
30 /* event_wait_multiple() uses the global condition to signal that an
31  * event has been set
32  */
33 static pthread_mutex_t event_signal_mutex = PTHREAD_MUTEX_INITIALIZER;
34 static pthread_cond_t event_signal_cond = PTHREAD_COND_INITIALIZER;
35
36 static void event_close(WapiHandle *handle);
37 static gboolean event_wait(WapiHandle *handle, guint32 ms);
38 static guint32 event_wait_multiple(gpointer data);
39
40 static struct _WapiHandleOps event_ops = {
41         event_close,            /* close */
42         NULL,                   /* getfiletype */
43         NULL,                   /* readfile */
44         NULL,                   /* writefile */
45         NULL,                   /* seek */
46         NULL,                   /* setendoffile */
47         NULL,                   /* getfilesize */
48         event_wait,             /* wait */
49         event_wait_multiple,    /* wait_multiple */
50 };
51
52 static void event_close(WapiHandle *handle)
53 {
54         struct _WapiHandle_event *event_handle=(struct _WapiHandle_event *)handle;
55         
56 #ifdef DEBUG
57         g_message(G_GNUC_PRETTY_FUNCTION ": closing event handle %p",
58                   event_handle);
59 #endif
60 }
61
62 static gboolean event_wait(WapiHandle *handle, guint32 ms)
63 {
64         struct _WapiHandle_event *event_handle=(struct _WapiHandle_event *)handle;
65         struct timespec timeout;
66         int ret;
67
68 #ifdef DEBUG
69         g_message(G_GNUC_PRETTY_FUNCTION
70                   ": waiting on event handle %p for %d ms", handle, ms);
71 #endif
72
73         pthread_mutex_lock(&event_handle->mutex);
74         
75         /* First check if the handle is already signalled */
76         if(handle->signalled==TRUE) {
77                 /* If this is an auto-reset event, reset the state to
78                  * unsignalled
79                  */
80         
81 #ifdef DEBUG
82                 g_message(G_GNUC_PRETTY_FUNCTION
83                           ": event handle %p already signalled", handle);
84 #endif
85
86                 if(event_handle->manual==FALSE) {
87 #ifdef DEBUG
88                         g_message(G_GNUC_PRETTY_FUNCTION
89                                   ": resetting auto event handle %p", handle);
90 #endif
91                         handle->signalled=FALSE;
92                 }
93                 pthread_mutex_unlock(&event_handle->mutex);
94                 
95                 return(TRUE);
96         }
97
98         /* We'll have to wait for it then */
99         if(ms!=INFINITE) {
100                 _wapi_calc_timeout(&timeout, ms);
101         }
102         
103 again:
104         /* Acquire a read lock so that the signal status can't be
105          * reset without us noticing. (PulseEvent and ResetEvent will
106          * gain a write lock before changing the status to
107          * unsignalled, which will block while one or more threads
108          * hold a read lock.)
109          */
110         pthread_rwlock_rdlock(&event_handle->rwlock);
111                 
112 #ifdef DEBUG
113         g_message(G_GNUC_PRETTY_FUNCTION
114                   ": waiting for event handle %p to be signalled", handle);
115 #endif
116
117         if(ms==INFINITE) {
118                 ret=pthread_cond_wait(&event_handle->cond,
119                                       &event_handle->mutex);
120         } else {
121                 ret=pthread_cond_timedwait(&event_handle->cond,
122                                            &event_handle->mutex, &timeout);
123         }
124
125         if(ret==0) {
126                 /* Condition was signalled, so hopefully event is
127                  * signalled now.  (It might not be if its an
128                  * auto-reset event and someone else got in before
129                  * us.)
130                  */
131         
132 #ifdef DEBUG
133                 g_message(G_GNUC_PRETTY_FUNCTION ": event handle %p signalled",
134                           handle);
135 #endif
136                 if(handle->signalled==TRUE) {
137         
138 #ifdef DEBUG
139                         g_message(G_GNUC_PRETTY_FUNCTION
140                                   ": event handle %p still signalled", handle);
141 #endif
142                         /* If this is an auto-reset event, reset the
143                          * state to unsignalled
144                          */
145                         if(event_handle->manual==FALSE) {
146 #ifdef DEBUG
147                                 g_message(G_GNUC_PRETTY_FUNCTION
148                                           ": resetting auto event handle %p",
149                                           handle);
150 #endif
151                                 handle->signalled=FALSE;
152                         }
153                         pthread_rwlock_unlock(&event_handle->rwlock);
154                         pthread_mutex_unlock(&event_handle->mutex);
155                         
156                         return(TRUE);
157                 }
158         
159 #ifdef DEBUG
160                 g_message(G_GNUC_PRETTY_FUNCTION
161                           ": event handle %p no longer signalled", handle);
162 #endif
163
164                 /* Better luck next time */
165                 
166                 /* Drop the rwlock briefly so that another thread has
167                  * a chance to reset the event
168                  */
169                 pthread_rwlock_unlock(&event_handle->rwlock);
170                 goto again;
171         }
172
173         /* Timeout or other error */
174         
175 #ifdef DEBUG
176         g_message(G_GNUC_PRETTY_FUNCTION
177                   ": wait on event handle %p error: %s", handle,
178                   strerror(ret));
179 #endif
180         
181         pthread_rwlock_unlock(&event_handle->rwlock);
182         pthread_mutex_unlock(&event_handle->mutex);
183         
184         return(FALSE);
185 }
186
187 static gboolean event_count_signalled(GPtrArray *handles, guint32 numhandles,
188                                       gboolean waitall, guint32 *retcount)
189 {
190         guint32 count, i;
191         gboolean ret;
192         
193         /* Lock all the handles, with backoff */
194 again:
195         for(i=0; i<numhandles; i++) {
196                 struct _WapiHandle_event *event_handle;
197                 
198                 event_handle=g_ptr_array_index(handles, i);
199                 
200                 ret=pthread_mutex_trylock(&event_handle->mutex);
201                 if(ret!=0) {
202                         /* Bummer */
203                         while(i--) {
204                                 event_handle=g_ptr_array_index(handles, i);
205                                 pthread_mutex_unlock(&event_handle->mutex);
206                         }
207
208                         /* It's not possible for two threads calling
209                          * WaitForMultipleObjects to both be calling
210                          * this function simultaneously, because the
211                          * global event_signal_mutex is held.
212                          * Therefore any collision is with a single
213                          * lock from one of the functions that deal
214                          * with single event handles.  It's just about
215                          * theoretically possible for the other
216                          * threads to keep locking an event in a tight
217                          * loop but eventually we will get the lock.
218                          */
219                         sched_yield();
220                         
221                         goto again;
222                 }
223         }
224         
225 #ifdef DEBUG
226         g_message(G_GNUC_PRETTY_FUNCTION ": Locked all event handles");
227 #endif
228         
229         count=_wapi_handle_count_signalled(handles);
230         
231 #ifdef DEBUG
232         g_message(G_GNUC_PRETTY_FUNCTION ": %d event handles signalled",
233                   count);
234 #endif
235         
236         if((waitall==TRUE && count==numhandles) ||
237            (waitall==FALSE && count>0)) {
238                 /* done */
239                 ret=TRUE;
240         } else {
241                 ret=FALSE;
242         }
243         
244         for(i=0; i<numhandles; i++) {
245                 struct _WapiHandle_event *event_handle;
246                 
247                 event_handle=g_ptr_array_index(handles, i);
248                 
249                 pthread_mutex_unlock(&event_handle->mutex);
250         }
251         
252 #ifdef DEBUG
253         g_message(G_GNUC_PRETTY_FUNCTION ": Returning %d", ret);
254 #endif
255
256         *retcount=count;
257         return(ret);
258 }
259
260 static guint32 event_wait_multiple(gpointer data)
261 {
262         WaitQueueItem *item=(WaitQueueItem *)data;
263         struct timespec timeout;
264         guint32 iterations;
265         guint32 numhandles, count, i;
266         gboolean done;
267         int ret;
268
269         numhandles=item->handles[WAPI_HANDLE_EVENT]->len;
270         
271 #ifdef DEBUG
272         g_message(G_GNUC_PRETTY_FUNCTION
273                   ": waiting on %d event handles for %d ms", numhandles,
274                   item->timeout);
275 #endif
276
277         /* First, check if any of the handles are already
278          * signalled. If waitall is specified we only return if all
279          * handles have been signalled.
280          */
281         done=event_count_signalled(item->handles[WAPI_HANDLE_EVENT],
282                                    numhandles, item->waitall, &count);
283         
284 #ifdef DEBUG
285         g_message(G_GNUC_PRETTY_FUNCTION
286                   ": Preliminary check found %d handles signalled", count);
287 #endif
288
289         if(done==TRUE) {
290                 item->waited[WAPI_HANDLE_EVENT]=TRUE;
291                 item->waitcount[WAPI_HANDLE_EVENT]=count;
292                 
293                 return(count);
294         }
295         
296         /* We'll have to wait then */
297         
298         pthread_mutex_lock(&event_signal_mutex);
299         
300         iterations=0;
301         do {
302                 iterations++;
303                 
304 #ifdef DEBUG
305                 g_message(G_GNUC_PRETTY_FUNCTION ": Wait iteration %d",
306                           iterations);
307 #endif
308
309                 /* If the timeout isnt INFINITE but greater than 1s,
310                  * split the timeout into 1s chunks.
311                  *
312                  * This is so that ResetEvent() wont block forever if
313                  * another thread is waiting on multiple events, with
314                  * some already signalled, and ResetEvent() wants to
315                  * reset one of the signalled ones.  (1s is a bit of a
316                  * long wait too, this might need to be tuned.)
317                  */
318
319                 if((item->timeout!=INFINITE) &&
320                    (item->timeout < (iterations*1000))) {
321                         _wapi_calc_timeout(
322                                 &timeout, item->timeout-((iterations-1)*1000));
323                 } else {
324                         _wapi_calc_timeout(&timeout, 1000);
325                 }
326                 
327                 /* Acquire a read lock on all handles so that the
328                  * signal status can't be reset without us
329                  * noticing. (PulseEvent and ResetEvent will gain a
330                  * write lock before changing the status to
331                  * unsignalled, which will block while one or more
332                  * threads hold a read lock.)
333                  */
334                 for(i=0; i<numhandles; i++) {
335                         struct _WapiHandle_event *event_handle;
336                         
337                         event_handle=g_ptr_array_index(
338                                 item->handles[WAPI_HANDLE_EVENT], i);
339                         
340                         pthread_rwlock_rdlock(&event_handle->rwlock);
341                 }
342                 
343                 ret=pthread_cond_timedwait(&event_signal_cond,
344                                            &event_signal_mutex, &timeout);
345
346                 if(ret==0) {
347                         /* Condition was signalled, so hopefully an
348                          * event is signalled now.  (It might not be
349                          * if it was an auto-reset event and someone
350                          * else got in before us.)
351                          */
352                         done=event_count_signalled(
353                                 item->handles[WAPI_HANDLE_EVENT], numhandles,
354                                 item->waitall, &count);
355         
356 #ifdef DEBUG
357                         g_message(G_GNUC_PRETTY_FUNCTION
358                                   ": signal check found %d handles signalled",
359                                   count);
360 #endif
361                         
362                         if(done==TRUE) {
363 #ifdef DEBUG
364                                 g_message(G_GNUC_PRETTY_FUNCTION
365                                           ": Returning wait success");
366 #endif
367
368                                 for(i=0; i<numhandles; i++) {
369                                         struct _WapiHandle_event *event_handle;
370                                 
371                                         event_handle=g_ptr_array_index(item->handles[WAPI_HANDLE_EVENT], i);
372                         
373                                         pthread_rwlock_unlock(&event_handle->rwlock);
374                                 }
375
376                                 item->waited[WAPI_HANDLE_EVENT]=TRUE;
377                                 item->waitcount[WAPI_HANDLE_EVENT]=count;
378                                 
379                                 return(count);
380                         }
381                 } else {
382 #ifdef DEBUG
383                         g_message(G_GNUC_PRETTY_FUNCTION ": Wait error %s",
384                                   strerror(ret));
385 #endif
386                 }
387
388 #ifdef DEBUG
389                 g_message(G_GNUC_PRETTY_FUNCTION
390                           ": Still waiting for more event handles");
391 #endif
392                 /* Drop the rwlocks briefly so that another thread has
393                  * a chance to reset any of the events
394                  */
395                 for(i=0; i<numhandles; i++) {
396                         struct _WapiHandle_event *event_handle;
397                                 
398                         event_handle=g_ptr_array_index(
399                                 item->handles[WAPI_HANDLE_EVENT], i);
400                         
401                         pthread_rwlock_unlock(&event_handle->rwlock);
402                 }
403         } while((item->timeout==INFINITE) ||
404                 (item->timeout > (iterations * 1000)));
405
406         /* Timeout or other error */
407         
408         for(i=0; i<numhandles; i++) {
409                 struct _WapiHandle_event *event_handle;
410                 
411                 event_handle=g_ptr_array_index(
412                         item->handles[WAPI_HANDLE_EVENT], i);
413                 
414                 pthread_rwlock_unlock(&event_handle->rwlock);
415         }
416
417         pthread_mutex_unlock(&event_signal_mutex);
418
419 #ifdef DEBUG
420         g_message(G_GNUC_PRETTY_FUNCTION ": Returning wait failed");
421 #endif
422         
423         item->waited[WAPI_HANDLE_EVENT]=TRUE;
424         item->waitcount[WAPI_HANDLE_MUTEX]=0;
425         
426         return(0);
427 }
428
429 /**
430  * CreateEvent:
431  * @security: Ignored for now.
432  * @manual: Specifies whether the new event handle has manual or auto
433  * reset behaviour.
434  * @initial: Specifies whether the new event handle is initially
435  * signalled or not.
436  * @name:Pointer to a string specifying the name of this name, or
437  * %NULL.  Currently ignored.
438  *
439  * Creates a new event handle.
440  *
441  * An event handle is signalled with SetEvent().  If the new handle is
442  * a manual reset event handle, it remains signalled until it is reset
443  * with ResetEvent().  An auto reset event remains signalled until a
444  * single thread has waited for it, at which time the event handle is
445  * automatically reset to unsignalled.
446  *
447  * Return value: A new handle, or %NULL on error.
448  */
449 WapiHandle *CreateEvent(WapiSecurityAttributes *security G_GNUC_UNUSED, gboolean manual,
450                         gboolean initial, const guchar *name G_GNUC_UNUSED)
451 {
452         struct _WapiHandle_event *event_handle;
453         WapiHandle *handle;
454         
455         event_handle=(struct _WapiHandle_event *)g_new0(struct _WapiHandle_event, 1);
456         handle=(WapiHandle *)event_handle;
457         _WAPI_HANDLE_INIT(handle, WAPI_HANDLE_EVENT, event_ops);
458         
459         pthread_mutex_init(&event_handle->mutex, NULL);
460         pthread_cond_init(&event_handle->cond, NULL);
461         pthread_rwlock_init(&event_handle->rwlock, NULL);
462         event_handle->manual=manual;
463
464         if(initial==TRUE) {
465                 handle->signalled=TRUE;
466         }
467         
468 #ifdef DEBUG
469         g_message(G_GNUC_PRETTY_FUNCTION ": created new event handle %p",
470                   handle);
471 #endif
472
473         return(handle);
474 }
475
476 /**
477  * PulseEvent:
478  * @handle: The event handle.
479  *
480  * Sets the event handle @handle to the signalled state, and then
481  * resets it to unsignalled after informing any waiting threads.
482  *
483  * If @handle is a manual reset event, all waiting threads that can be
484  * released immediately are released.  @handle is then reset.  If
485  * @handle is an auto reset event, one waiting thread is released even
486  * if multiple threads are waiting.
487  *
488  * Return value: %TRUE on success, %FALSE otherwise.  (Currently only
489  * ever returns %TRUE).
490  */
491 gboolean PulseEvent(WapiHandle *handle)
492 {
493         struct _WapiHandle_event *event_handle=(struct _WapiHandle_event *)handle;
494         
495         pthread_mutex_lock(&event_handle->mutex);
496
497 #ifdef DEBUG
498         g_message(G_GNUC_PRETTY_FUNCTION ": Pulsing event handle %p", handle);
499 #endif
500
501         handle->signalled=TRUE;
502         
503         /* Tell everyone blocking on WaitForSingleObject */
504         if(event_handle->manual==TRUE) {
505                 pthread_cond_broadcast(&event_handle->cond);
506         } else {
507                 pthread_cond_signal(&event_handle->cond);
508         }
509         pthread_mutex_unlock(&event_handle->mutex);
510
511 #ifdef DEBUG
512         g_message(G_GNUC_PRETTY_FUNCTION
513                   ": Informed single waits for event handle %p", handle);
514 #endif
515         
516         /* Tell everyone blocking on WaitForMultipleObjects */
517         pthread_mutex_lock(&event_signal_mutex);
518         pthread_cond_broadcast(&event_signal_cond);
519         pthread_mutex_unlock(&event_signal_mutex);
520
521 #ifdef DEBUG
522         g_message(G_GNUC_PRETTY_FUNCTION
523                   ": Informed multiple waits for event handles");
524 #endif
525         
526         /* Reset the handle signal state */
527
528         /* This rwlock blocks until no other thread holds a read lock.
529          * This ensures that we can't reset the event until every
530          * waiting thread has had a chance to examine it
531          */
532         pthread_rwlock_wrlock(&event_handle->rwlock);
533
534 #ifdef DEBUG
535         g_message(G_GNUC_PRETTY_FUNCTION
536                   ": Obtained write lock on event handle %p", handle);
537 #endif
538
539         handle->signalled=FALSE;
540         pthread_rwlock_unlock(&event_handle->rwlock);
541
542         return(TRUE);
543 }
544
545 /**
546  * ResetEvent:
547  * @handle: The event handle.
548  *
549  * Resets the event handle @handle to the unsignalled state.
550  *
551  * Return value: %TRUE on success, %FALSE otherwise.  (Currently only
552  * ever returns %TRUE).
553  */
554 gboolean ResetEvent(WapiHandle *handle)
555 {
556         struct _WapiHandle_event *event_handle=(struct _WapiHandle_event *)handle;
557
558 #ifdef DEBUG
559         g_message(G_GNUC_PRETTY_FUNCTION ": Resetting event handle %p",
560                   handle);
561 #endif
562
563         /* Test for the current state, because another thread might be
564          * waiting forever on an unsignalled event with the read lock
565          * held.  Theres no point going for the write lock if we dont
566          * need it.
567          */
568         pthread_mutex_lock(&event_handle->mutex);
569         if(handle->signalled==FALSE) {
570
571 #ifdef DEBUG
572                 g_message(G_GNUC_PRETTY_FUNCTION
573                           ": No need to reset event handle %p", handle);
574 #endif
575
576                 pthread_mutex_unlock(&event_handle->mutex);
577                 return(TRUE);
578         }
579         pthread_mutex_unlock(&event_handle->mutex);
580         
581         pthread_rwlock_wrlock(&event_handle->rwlock);
582
583 #ifdef DEBUG
584         g_message(G_GNUC_PRETTY_FUNCTION
585                   ": Obtained write lock on event handle %p", handle);
586 #endif
587
588         handle->signalled=FALSE;
589         pthread_rwlock_unlock(&event_handle->rwlock);
590         
591         return(TRUE);
592 }
593
594 /**
595  * SetEvent:
596  * @handle: The event handle
597  *
598  * Sets the event handle @handle to the signalled state.
599  *
600  * If @handle is a manual reset event, it remains signalled until it
601  * is reset with ResetEvent().  An auto reset event remains signalled
602  * until a single thread has waited for it, at which time @handle is
603  * automatically reset to unsignalled.
604  *
605  * Return value: %TRUE on success, %FALSE otherwise.  (Currently only
606  * ever returns %TRUE).
607  */
608 gboolean SetEvent(WapiHandle *handle)
609 {
610         struct _WapiHandle_event *event_handle=(struct _WapiHandle_event *)handle;
611         
612         pthread_mutex_lock(&event_handle->mutex);
613
614 #ifdef DEBUG
615         g_message(G_GNUC_PRETTY_FUNCTION ": Setting event handle %p", handle);
616 #endif
617
618         handle->signalled=TRUE;
619         
620         /* Tell everyone blocking on WaitForSingleObject */
621         if(event_handle->manual==TRUE) {
622                 pthread_cond_broadcast(&event_handle->cond);
623         } else {
624                 pthread_cond_signal(&event_handle->cond);
625         }
626         pthread_mutex_unlock(&event_handle->mutex);
627
628 #ifdef DEBUG
629         g_message(G_GNUC_PRETTY_FUNCTION
630                   ": Informed single waits for event handle %p", handle);
631 #endif
632         
633         /* Tell everyone blocking on WaitForMultipleObjects */
634         pthread_mutex_lock(&event_signal_mutex);
635         pthread_cond_broadcast(&event_signal_cond);
636         pthread_mutex_unlock(&event_signal_mutex);
637
638 #ifdef DEBUG
639         g_message(G_GNUC_PRETTY_FUNCTION
640                   ": Informed multiple waits for event handles");
641 #endif
642         
643         return(TRUE);
644 }
645