os-event-unix.c 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235
  1. /**
  2. * \file
  3. * MonoOSEvent on Unix
  4. *
  5. * Author:
  6. * Ludovic Henry (luhenry@microsoft.com)
  7. *
  8. * Licensed under the MIT license. See LICENSE file in the project root for full license information.
  9. */
  10. #include "os-event.h"
  11. #include "atomic.h"
  12. #include "mono-lazy-init.h"
  13. #include "mono-threads.h"
  14. #include "mono-time.h"
  15. static mono_lazy_init_t status = MONO_LAZY_INIT_STATUS_NOT_INITIALIZED;
  16. static mono_mutex_t signal_mutex;
  17. static void
  18. initialize (void)
  19. {
  20. mono_os_mutex_init (&signal_mutex);
  21. }
  22. void
  23. mono_os_event_init (MonoOSEvent *event, gboolean initial)
  24. {
  25. g_assert (event);
  26. mono_lazy_initialize (&status, initialize);
  27. event->conds = g_ptr_array_new ();
  28. event->signalled = initial;
  29. }
  30. void
  31. mono_os_event_destroy (MonoOSEvent *event)
  32. {
  33. g_assert (mono_lazy_is_initialized (&status));
  34. g_assert (event);
  35. if (event->conds->len > 0)
  36. g_error ("%s: cannot destroy osevent, there are still %d threads waiting on it", __func__, event->conds->len);
  37. g_ptr_array_free (event->conds, TRUE);
  38. }
  39. static gboolean
  40. mono_os_event_is_signalled (MonoOSEvent *event)
  41. {
  42. return event->signalled;
  43. }
  44. void
  45. mono_os_event_set (MonoOSEvent *event)
  46. {
  47. gsize i;
  48. g_assert (mono_lazy_is_initialized (&status));
  49. g_assert (event);
  50. mono_os_mutex_lock (&signal_mutex);
  51. event->signalled = TRUE;
  52. for (i = 0; i < event->conds->len; ++i)
  53. mono_os_cond_signal ((mono_cond_t*) event->conds->pdata [i]);
  54. mono_os_mutex_unlock (&signal_mutex);
  55. }
  56. void
  57. mono_os_event_reset (MonoOSEvent *event)
  58. {
  59. g_assert (mono_lazy_is_initialized (&status));
  60. g_assert (event);
  61. mono_os_mutex_lock (&signal_mutex);
  62. event->signalled = FALSE;
  63. mono_os_mutex_unlock (&signal_mutex);
  64. }
  65. MonoOSEventWaitRet
  66. mono_os_event_wait_one (MonoOSEvent *event, guint32 timeout, gboolean alertable)
  67. {
  68. return mono_os_event_wait_multiple (&event, 1, TRUE, timeout, alertable);
  69. }
  70. typedef struct {
  71. guint32 ref;
  72. MonoOSEvent event;
  73. } OSEventWaitData;
  74. static void
  75. signal_and_unref (gpointer user_data)
  76. {
  77. OSEventWaitData *data;
  78. data = (OSEventWaitData*) user_data;
  79. mono_os_event_set (&data->event);
  80. if (mono_atomic_dec_i32 ((gint32*) &data->ref) == 0) {
  81. mono_os_event_destroy (&data->event);
  82. g_free (data);
  83. }
  84. }
  85. MonoOSEventWaitRet
  86. mono_os_event_wait_multiple (MonoOSEvent **events, gsize nevents, gboolean waitall, guint32 timeout, gboolean alertable)
  87. {
  88. MonoOSEventWaitRet ret;
  89. mono_cond_t signal_cond;
  90. OSEventWaitData *data = NULL;
  91. gboolean alerted;
  92. gint64 start = 0;
  93. gint i;
  94. g_assert (mono_lazy_is_initialized (&status));
  95. g_assert (events);
  96. g_assert (nevents > 0);
  97. g_assert (nevents <= MONO_OS_EVENT_WAIT_MAXIMUM_OBJECTS);
  98. for (i = 0; i < nevents; ++i)
  99. g_assert (events [i]);
  100. if (alertable) {
  101. data = g_new0 (OSEventWaitData, 1);
  102. data->ref = 2;
  103. mono_os_event_init (&data->event, FALSE);
  104. alerted = FALSE;
  105. mono_thread_info_install_interrupt (signal_and_unref, data, &alerted);
  106. if (alerted) {
  107. mono_os_event_destroy (&data->event);
  108. g_free (data);
  109. return MONO_OS_EVENT_WAIT_RET_ALERTED;
  110. }
  111. }
  112. if (timeout != MONO_INFINITE_WAIT)
  113. start = mono_msec_ticks ();
  114. mono_os_cond_init (&signal_cond);
  115. mono_os_mutex_lock (&signal_mutex);
  116. for (i = 0; i < nevents; ++i)
  117. g_ptr_array_add (events [i]->conds, &signal_cond);
  118. if (alertable)
  119. g_ptr_array_add (data->event.conds, &signal_cond);
  120. for (;;) {
  121. gint count, lowest;
  122. gboolean signalled;
  123. count = 0;
  124. lowest = -1;
  125. for (i = 0; i < nevents; ++i) {
  126. if (mono_os_event_is_signalled (events [i])) {
  127. count += 1;
  128. if (lowest == -1)
  129. lowest = i;
  130. }
  131. }
  132. if (alertable && mono_os_event_is_signalled (&data->event))
  133. signalled = TRUE;
  134. else if (waitall)
  135. signalled = (count == nevents);
  136. else /* waitany */
  137. signalled = (count > 0);
  138. if (signalled) {
  139. ret = (MonoOSEventWaitRet)(MONO_OS_EVENT_WAIT_RET_SUCCESS_0 + lowest);
  140. goto done;
  141. }
  142. if (timeout == MONO_INFINITE_WAIT) {
  143. mono_os_cond_wait (&signal_cond, &signal_mutex);
  144. } else {
  145. gint64 elapsed;
  146. gint res;
  147. elapsed = mono_msec_ticks () - start;
  148. if (elapsed >= timeout) {
  149. ret = MONO_OS_EVENT_WAIT_RET_TIMEOUT;
  150. goto done;
  151. }
  152. res = mono_os_cond_timedwait (&signal_cond, &signal_mutex, timeout - elapsed);
  153. if (res != 0) {
  154. ret = MONO_OS_EVENT_WAIT_RET_TIMEOUT;
  155. goto done;
  156. }
  157. }
  158. }
  159. done:
  160. for (i = 0; i < nevents; ++i)
  161. g_ptr_array_remove (events [i]->conds, &signal_cond);
  162. if (alertable)
  163. g_ptr_array_remove (data->event.conds, &signal_cond);
  164. mono_os_mutex_unlock (&signal_mutex);
  165. mono_os_cond_destroy (&signal_cond);
  166. if (alertable) {
  167. mono_thread_info_uninstall_interrupt (&alerted);
  168. if (alerted) {
  169. if (mono_atomic_dec_i32 ((gint32*) &data->ref) == 0) {
  170. mono_os_event_destroy (&data->event);
  171. g_free (data);
  172. }
  173. return MONO_OS_EVENT_WAIT_RET_ALERTED;
  174. }
  175. mono_os_event_destroy (&data->event);
  176. g_free (data);
  177. }
  178. return ret;
  179. }