[threads] Fix another sleep compilation error on win32
[mono.git] / mono / utils / mono-threads.c
index c0bfbec293daabd03924a2664d9cda4d5a230024..1c1a1842eb2f9e5a965431547e4220a50eb3ec16 100644 (file)
 
 #include <config.h>
 
+/* enable pthread extensions */
+#ifdef TARGET_MACH
+#define _DARWIN_C_SOURCE
+#endif
+
 #include <mono/utils/mono-compiler.h>
 #include <mono/utils/mono-semaphore.h>
 #include <mono/utils/mono-threads.h>
@@ -19,6 +24,7 @@
 #include <mono/utils/mono-mmap.h>
 #include <mono/utils/atomic.h>
 #include <mono/utils/mono-time.h>
+#include <mono/utils/mono-lazy-init.h>
 
 
 #include <errno.h>
@@ -163,7 +169,15 @@ dump_threads (void)
        MOSTLY_ASYNC_SAFE_PRINTF ("\t0x?08\t- blocking with pending suspend (GOOD)\n");
 
        FOREACH_THREAD_SAFE (info) {
+#ifdef TARGET_MACH
+               char thread_name [256] = { 0 };
+               pthread_getname_np (mono_thread_info_get_tid (info), thread_name, 255);
+
+               MOSTLY_ASYNC_SAFE_PRINTF ("--thread %p id %p [%p] (%s) state %x  %s\n", info, (void *) mono_thread_info_get_tid (info), (void*)(size_t)info->native_handle, thread_name, info->thread_state, info == cur ? "GC INITIATOR" : "" );
+#else
                MOSTLY_ASYNC_SAFE_PRINTF ("--thread %p id %p [%p] state %x  %s\n", info, (void *) mono_thread_info_get_tid (info), (void*)(size_t)info->native_handle, info->thread_state, info == cur ? "GC INITIATOR" : "" );
+#endif
+
        } END_FOREACH_THREAD_SAFE
 }
 
@@ -313,6 +327,8 @@ register_thread (MonoThreadInfo *info, gpointer baseptr)
        info->stack_start_limit = staddr;
        info->stack_end = staddr + stsize;
 
+       info->stackdata = g_byte_array_new ();
+
        mono_threads_platform_register (info);
 
        /*
@@ -374,6 +390,8 @@ unregister_thread (void *arg)
 
        mono_thread_info_suspend_unlock ();
 
+       g_byte_array_free (info->stackdata, /*free_segment=*/TRUE);
+
        /*now it's safe to free the thread info.*/
        mono_thread_hazardous_free_or_queue (info, free_thread_info, TRUE, FALSE);
        mono_thread_small_id_free (small_id);
@@ -589,6 +607,7 @@ mono_threads_init (MonoThreadInfoCallbacks *callbacks, size_t info_size)
        mono_lls_init (&thread_list, NULL);
        mono_thread_smr_init ();
        mono_threads_init_platform ();
+       mono_threads_init_abort_syscall ();
 
 #if defined(__MACH__)
        mono_mach_init (thread_info_key);
@@ -1000,7 +1019,7 @@ mono_thread_info_abort_socket_syscall_for_close (MonoNativeThreadId tid)
        if (!info)
                return;
 
-       if (mono_thread_info_run_state (info) > STATE_RUNNING) {
+       if (mono_thread_info_run_state (info) == STATE_DETACHED) {
                mono_hazard_pointer_clear (hp, 1);
                return;
        }
@@ -1087,6 +1106,135 @@ mono_thread_info_yield (void)
 {
        return mono_threads_core_yield ();
 }
+static mono_lazy_init_t sleep_init = MONO_LAZY_INIT_STATUS_NOT_INITIALIZED;
+static mono_mutex_t sleep_mutex;
+static mono_cond_t sleep_cond;
+
+static void
+sleep_initialize (void)
+{
+       mono_mutex_init (&sleep_mutex);
+       mono_cond_init (&sleep_cond, NULL);
+}
+
+static void
+sleep_interrupt (gpointer data)
+{
+       mono_mutex_lock (&sleep_mutex);
+       mono_cond_broadcast (&sleep_cond);
+       mono_mutex_unlock (&sleep_mutex);
+}
+
+static inline guint32
+sleep_interruptable (guint32 ms, gboolean *alerted)
+{
+       guint32 start, now, end;
+
+       g_assert (INFINITE == G_MAXUINT32);
+
+       g_assert (alerted);
+       *alerted = FALSE;
+
+       start = mono_msec_ticks ();
+
+       if (start < G_MAXUINT32 - ms) {
+               end = start + ms;
+       } else {
+               /* start + ms would overflow guint32 */
+               end = G_MAXUINT32;
+       }
+
+       mono_lazy_initialize (&sleep_init, sleep_initialize);
+
+       mono_mutex_lock (&sleep_mutex);
+
+       for (now = mono_msec_ticks (); ms == INFINITE || now - start < ms; now = mono_msec_ticks ()) {
+               mono_thread_info_install_interrupt (sleep_interrupt, NULL, alerted);
+               if (*alerted) {
+                       mono_mutex_unlock (&sleep_mutex);
+                       return WAIT_IO_COMPLETION;
+               }
+
+               if (ms < INFINITE)
+                       mono_cond_timedwait_ms (&sleep_cond, &sleep_mutex, end - now);
+               else
+                       mono_cond_wait (&sleep_cond, &sleep_mutex);
+
+               mono_thread_info_uninstall_interrupt (alerted);
+               if (*alerted) {
+                       mono_mutex_unlock (&sleep_mutex);
+                       return WAIT_IO_COMPLETION;
+               }
+       }
+
+       mono_mutex_unlock (&sleep_mutex);
+
+       return 0;
+}
+
+gint
+mono_thread_info_sleep (guint32 ms, gboolean *alerted)
+{
+       if (ms == 0) {
+               MonoThreadInfo *info;
+
+               mono_thread_info_yield ();
+
+               info = mono_thread_info_current ();
+               if (info && mono_thread_info_is_interrupt_state (info))
+                       return WAIT_IO_COMPLETION;
+
+               return 0;
+       }
+
+       if (alerted)
+               return sleep_interruptable (ms, alerted);
+
+       if (ms == INFINITE) {
+               do {
+#ifdef HOST_WIN32
+                       Sleep (G_MAXUINT32);
+#else
+                       sleep (G_MAXUINT32);
+#endif
+               } while (1);
+       } else {
+               int ret;
+#if defined (__linux__) && !defined(PLATFORM_ANDROID)
+               struct timespec start, target;
+
+               /* Use clock_nanosleep () to prevent time drifting problems when nanosleep () is interrupted by signals */
+               ret = clock_gettime (CLOCK_MONOTONIC, &start);
+               g_assert (ret == 0);
+
+               target = start;
+               target.tv_sec += ms / 1000;
+               target.tv_nsec += (ms % 1000) * 1000000;
+               if (target.tv_nsec > 999999999) {
+                       target.tv_nsec -= 999999999;
+                       target.tv_sec ++;
+               }
+
+               do {
+                       ret = clock_nanosleep (CLOCK_MONOTONIC, TIMER_ABSTIME, &target, NULL);
+               } while (ret != 0);
+#elif HOST_WIN32
+               Sleep (ms);
+#else
+               struct timespec req, rem;
+
+               req.tv_sec = ms / 1000;
+               req.tv_nsec = (ms % 1000) * 1000000;
+
+               do {
+                       memset (&rem, 0, sizeof (rem));
+                       ret = nanosleep (&req, &rem);
+               } while (ret != 0);
+#endif /* __linux__ */
+       }
+
+       return 0;
+}
 
 gpointer
 mono_thread_info_tls_get (THREAD_INFO_TYPE *info, MonoTlsKey key)