[io-layer] Remove pseudo global handle
authorLudovic Henry <ludovic@xamarin.com>
Thu, 30 Jun 2016 17:50:20 +0000 (19:50 +0200)
committerLudovic Henry <ludovic@xamarin.com>
Tue, 12 Jul 2016 12:53:23 +0000 (14:53 +0200)
mono/io-layer/handles.c

index 023dd8cbc5934b68b8d9c47a91d9f647f4b9eb20..201b4db6e841113a0f07ccd01fee4e90dff5df16 100644 (file)
@@ -87,11 +87,8 @@ guint32 _wapi_fd_reserve;
  * Threads which wait for multiple handles wait on this one handle, and when a handle
  * is signalled, this handle is signalled too.
  */
-static gpointer _wapi_global_signal_handle;
-
-/* Point to the mutex/cond inside _wapi_global_signal_handle */
-static mono_mutex_t *_wapi_global_signal_mutex;
-static mono_cond_t *_wapi_global_signal_cond;
+static mono_mutex_t _wapi_global_signal_mutex;
+static mono_cond_t _wapi_global_signal_cond;
 
 static void _wapi_handle_unref_full (gpointer handle, gboolean ignore_private_busy_handles);
 
@@ -147,7 +144,7 @@ _wapi_handle_set_signal_state (gpointer handle, gboolean state, gboolean broadca
                /* The condition the global signal cond is waiting on is the signalling of
                 * _any_ handle. So lock it before setting the signalled state.
                 */
-               thr_ret = mono_os_mutex_lock (_wapi_global_signal_mutex);
+               thr_ret = mono_os_mutex_lock (&_wapi_global_signal_mutex);
                if (thr_ret != 0)
                        g_warning ("Bad call to mono_os_mutex_lock result %d for global signal mutex", thr_ret);
                g_assert (thr_ret == 0);
@@ -172,12 +169,12 @@ _wapi_handle_set_signal_state (gpointer handle, gboolean state, gboolean broadca
                /* Tell everyone blocking on multiple handles that something
                 * was signalled
                 */                     
-               thr_ret = mono_os_cond_broadcast (_wapi_global_signal_cond);
+               thr_ret = mono_os_cond_broadcast (&_wapi_global_signal_cond);
                if (thr_ret != 0)
                        g_warning ("Bad call to mono_os_cond_broadcast result %d for handle %p", thr_ret, handle);
                g_assert (thr_ret == 0);
                        
-               thr_ret = mono_os_mutex_unlock (_wapi_global_signal_mutex);
+               thr_ret = mono_os_mutex_unlock (&_wapi_global_signal_mutex);
                if (thr_ret != 0)
                        g_warning ("Bad call to mono_os_mutex_unlock result %d for global signal mutex", thr_ret);
                g_assert (thr_ret == 0);
@@ -205,7 +202,7 @@ _wapi_handle_lock_signal_mutex (void)
        g_message ("%s: lock global signal mutex", __func__);
 #endif
 
-       return(mono_os_mutex_lock (_wapi_global_signal_mutex));
+       return(mono_os_mutex_lock (&_wapi_global_signal_mutex));
 }
 
 int
@@ -215,7 +212,7 @@ _wapi_handle_unlock_signal_mutex (void)
        g_message ("%s: unlock global signal mutex", __func__);
 #endif
 
-       return(mono_os_mutex_unlock (_wapi_global_signal_mutex));
+       return(mono_os_mutex_unlock (&_wapi_global_signal_mutex));
 }
 
 int
@@ -315,10 +312,8 @@ _wapi_handle_init (void)
 
        mono_os_mutex_init (&scan_mutex);
 
-       _wapi_global_signal_handle = _wapi_handle_new (WAPI_HANDLE_EVENT, NULL);
-
-       _wapi_global_signal_cond = &_WAPI_PRIVATE_HANDLES (GPOINTER_TO_UINT (_wapi_global_signal_handle))->signal_cond;
-       _wapi_global_signal_mutex = &_WAPI_PRIVATE_HANDLES (GPOINTER_TO_UINT (_wapi_global_signal_handle))->signal_mutex;
+       mono_os_cond_init (&_wapi_global_signal_cond);
+       mono_os_mutex_init (&_wapi_global_signal_mutex);
 }
 
 void
@@ -1107,6 +1102,80 @@ void _wapi_handle_unlock_handles (guint32 numhandles, gpointer *handles)
        }
 }
 
+static int
+_wapi_handle_timedwait_signal_naked (mono_cond_t *cond, mono_mutex_t *mutex, guint32 timeout, gboolean poll, gboolean *alerted)
+{
+       int res;
+
+       if (!poll) {
+               res = mono_os_cond_timedwait (cond, mutex, timeout);
+       } else {
+               /* This is needed when waiting for process handles */
+               if (!alerted) {
+                       /*
+                        * pthread_cond_(timed)wait() can return 0 even if the condition was not
+                        * signalled.  This happens at least on Darwin.  We surface this, i.e., we
+                        * get spurious wake-ups.
+                        *
+                        * http://pubs.opengroup.org/onlinepubs/007908775/xsh/pthread_cond_wait.html
+                        */
+                       res = mono_os_cond_timedwait (cond, mutex, timeout);
+               } else {
+                       if (timeout < 100) {
+                               /* Real timeout is less than 100ms time */
+                               res = mono_os_cond_timedwait (cond, mutex, timeout);
+                       } else {
+                               res = mono_os_cond_timedwait (cond, mutex, 100);
+
+                               /* Mask the fake timeout, this will cause
+                                * another poll if the cond was not really signaled
+                                */
+                               if (res == ETIMEDOUT)
+                                       res = 0;
+                       }
+               }
+       }
+
+       return res;
+}
+
+static void
+signal_global (gpointer unused)
+{
+       /* If we reach here, then interrupt token is set to the flag value, which
+        * means that the target thread is either
+        * - before the first CAS in timedwait, which means it won't enter the wait.
+        * - it is after the first CAS, so it is already waiting, or it will enter
+        *    the wait, and it will be interrupted by the broadcast. */
+       mono_os_mutex_lock (&_wapi_global_signal_mutex);
+       mono_os_cond_broadcast (&_wapi_global_signal_cond);
+       mono_os_mutex_unlock (&_wapi_global_signal_mutex);
+}
+
+int
+_wapi_handle_timedwait_signal (guint32 timeout, gboolean poll, gboolean *alerted)
+{
+       int res;
+
+       MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: waiting for global", __func__);
+
+       if (alerted)
+               *alerted = FALSE;
+
+       if (alerted) {
+               mono_thread_info_install_interrupt (signal_global, NULL, alerted);
+               if (*alerted)
+                       return 0;
+       }
+
+       res = _wapi_handle_timedwait_signal_naked (&_wapi_global_signal_cond, &_wapi_global_signal_mutex, timeout, poll, alerted);
+
+       if (alerted)
+               mono_thread_info_uninstall_interrupt (alerted);
+
+       return res;
+}
+
 static void
 signal_handle_and_unref (gpointer handle)
 {
@@ -1135,20 +1204,12 @@ signal_handle_and_unref (gpointer handle)
        _wapi_handle_unref (handle);
 }
 
-int
-_wapi_handle_timedwait_signal (guint32 timeout, gboolean poll, gboolean *alerted)
-{
-       return _wapi_handle_timedwait_signal_handle (_wapi_global_signal_handle, timeout, poll, alerted);
-}
-
 int
 _wapi_handle_timedwait_signal_handle (gpointer handle, guint32 timeout, gboolean poll, gboolean *alerted)
 {
        guint32 idx;
        WapiHandleBase *handle_data;
        int res;
-       mono_cond_t *cond;
-       mono_mutex_t *mutex;
 
        MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: waiting for %p (type %s)", __func__, handle,
                   _wapi_handle_ops_typename (_wapi_handle_type (handle)));
@@ -1166,37 +1227,7 @@ _wapi_handle_timedwait_signal_handle (gpointer handle, guint32 timeout, gboolean
                _wapi_handle_ref (handle);
        }
 
-       cond = &handle_data->signal_cond;
-       mutex = &handle_data->signal_mutex;
-
-       if (!poll) {
-               res = mono_os_cond_timedwait (cond, mutex, timeout);
-       } else {
-               /* This is needed when waiting for process handles */
-               if (!alerted) {
-                       /*
-                        * pthread_cond_(timed)wait() can return 0 even if the condition was not
-                        * signalled.  This happens at least on Darwin.  We surface this, i.e., we
-                        * get spurious wake-ups.
-                        *
-                        * http://pubs.opengroup.org/onlinepubs/007908775/xsh/pthread_cond_wait.html
-                        */
-                       res = mono_os_cond_timedwait (cond, mutex, timeout);
-               } else {
-                       if (timeout < 100) {
-                               /* Real timeout is less than 100ms time */
-                               res = mono_os_cond_timedwait (cond, mutex, timeout);
-                       } else {
-                               res = mono_os_cond_timedwait (cond, mutex, 100);
-
-                               /* Mask the fake timeout, this will cause
-                                * another poll if the cond was not really signaled
-                                */
-                               if (res == ETIMEDOUT)
-                                       res = 0;
-                       }
-               }
-       }
+       res = _wapi_handle_timedwait_signal_naked (&handle_data->signal_cond, &handle_data->signal_mutex, timeout, poll, alerted);
 
        if (alerted) {
                mono_thread_info_uninstall_interrupt (alerted);