[mono-threads] Factor common platform create thread code (#3484)
authorLudovic Henry <ludovic@xamarin.com>
Thu, 1 Sep 2016 19:22:51 +0000 (21:22 +0200)
committerGitHub <noreply@github.com>
Thu, 1 Sep 2016 19:22:51 +0000 (21:22 +0200)
mono/utils/mono-threads-posix.c
mono/utils/mono-threads-windows.c
mono/utils/mono-threads.c
mono/utils/mono-threads.h

index 4d1afeba132a1dd3702810ff5531d8d43e95753c..1a6b06fe0452fca72d97e2eb9bff4ffd3d22698d 100644 (file)
@@ -107,71 +107,18 @@ mono_threads_platform_register (MonoThreadInfo *info)
        info->handle = thread_handle_create ();
 }
 
-typedef struct {
-       void *(*start_routine)(void*);
-       void *arg;
-       int flags;
-       gint32 priority;
-       MonoCoopSem registered;
-       HANDLE handle;
-} StartInfo;
-
-static void*
-inner_start_thread (void *arg)
-{
-       StartInfo *start_info = (StartInfo *) arg;
-       void *t_arg = start_info->arg;
-       int res;
-       void *(*start_func)(void*) = start_info->start_routine;
-       guint32 flags = start_info->flags;
-       void *result;
-       MonoThreadInfo *info;
-
-       info = mono_thread_info_attach (&result);
-       info->runtime_thread = TRUE;
-
-       start_info->handle = info->handle;
-
-       mono_threads_platform_set_priority (info, start_info->priority);
-
-       if (flags & CREATE_SUSPENDED) {
-               info->create_suspended = TRUE;
-               mono_coop_sem_init (&info->create_suspended_sem, 0);
-       }
-
-       /* start_info is not valid after this */
-       mono_coop_sem_post (&(start_info->registered));
-       start_info = NULL;
-
-       if (flags & CREATE_SUSPENDED) {
-               res = mono_coop_sem_wait (&info->create_suspended_sem, MONO_SEM_FLAGS_NONE);
-               g_assert (res != -1);
-
-               mono_coop_sem_destroy (&info->create_suspended_sem);
-       }
-
-       /* Run the actual main function of the thread */
-       result = start_func (t_arg);
-
-       mono_threads_platform_exit (GPOINTER_TO_UINT (result));
-       g_assert_not_reached ();
-}
-
-HANDLE
-mono_threads_platform_create_thread (MonoThreadStart start_routine, gpointer arg, MonoThreadParm *tp, MonoNativeThreadId *out_tid)
+int
+mono_threads_platform_create_thread (MonoThreadStart thread_fn, gpointer thread_data, gsize stack_size, MonoNativeThreadId *out_tid)
 {
        pthread_attr_t attr;
-       int res;
        pthread_t thread;
-       StartInfo start_info;
-       guint32 stack_size;
-       int policy;
-       struct sched_param sp;
+       gint res;
 
        res = pthread_attr_init (&attr);
        g_assert (!res);
 
-       if (tp->stack_size == 0) {
+#ifdef HAVE_PTHREAD_ATTR_SETSTACKSIZE
+       if (stack_size == 0) {
 #if HAVE_VALGRIND_MEMCHECK_H
                if (RUNNING_ON_VALGRIND)
                        stack_size = 1 << 20;
@@ -180,52 +127,26 @@ mono_threads_platform_create_thread (MonoThreadStart start_routine, gpointer arg
 #else
                stack_size = (SIZEOF_VOID_P / 4) * 1024 * 1024;
 #endif
-       } else
-               stack_size = tp->stack_size;
+       }
 
 #ifdef PTHREAD_STACK_MIN
        if (stack_size < PTHREAD_STACK_MIN)
                stack_size = PTHREAD_STACK_MIN;
 #endif
 
-#ifdef HAVE_PTHREAD_ATTR_SETSTACKSIZE
        res = pthread_attr_setstacksize (&attr, stack_size);
        g_assert (!res);
-#endif
-
-       /*
-        * For policies that respect priorities set the prirority for the new thread
-        */ 
-       pthread_getschedparam(pthread_self(), &policy, &sp);
-       if ((policy == SCHED_FIFO) || (policy == SCHED_RR)) {
-               sp.sched_priority = win32_priority_to_posix_priority (tp->priority, policy);
-               res = pthread_attr_setschedparam (&attr, &sp);
-       }
-
-       memset (&start_info, 0, sizeof (StartInfo));
-       start_info.start_routine = (void *(*)(void *)) start_routine;
-       start_info.arg = arg;
-       start_info.flags = tp->creation_flags;
-       start_info.priority = tp->priority;
-       mono_coop_sem_init (&(start_info.registered), 0);
+#endif /* HAVE_PTHREAD_ATTR_SETSTACKSIZE */
 
        /* Actually start the thread */
-       res = mono_gc_pthread_create (&thread, &attr, inner_start_thread, &start_info);
-       if (res) {
-               mono_coop_sem_destroy (&(start_info.registered));
-               return NULL;
-       }
-
-       /* Wait until the thread register itself in various places */
-       res = mono_coop_sem_wait (&start_info.registered, MONO_SEM_FLAGS_NONE);
-       g_assert (res != -1);
-
-       mono_coop_sem_destroy (&(start_info.registered));
+       res = mono_gc_pthread_create (&thread, &attr, (gpointer (*)(gpointer)) thread_fn, thread_data);
+       if (res)
+               return -1;
 
        if (out_tid)
                *out_tid = thread;
 
-       return start_info.handle;
+       return 0;
 }
 
 gboolean
index ca6159b07f52e277b41d35a7b756a37201f81c87..bb8d300a58b59306e44268214dd1ed46a932a1ef 100644 (file)
@@ -148,84 +148,24 @@ mono_threads_platform_register (MonoThreadInfo *info)
        info->handle = thread_handle;
 }
 
-typedef struct {
-       LPTHREAD_START_ROUTINE start_routine;
-       void *arg;
-       gint32 priority;
-       MonoCoopSem registered;
-       gboolean suspend;
-       HANDLE handle;
-} ThreadStartInfo;
-
-static DWORD WINAPI
-inner_start_thread (LPVOID arg)
+int
+mono_threads_platform_create_thread (MonoThreadStart thread_fn, gpointer thread_data, gsize stack_size, MonoNativeThreadId *out_tid)
 {
-       ThreadStartInfo *start_info = arg;
-       void *t_arg = start_info->arg;
-       LPTHREAD_START_ROUTINE start_func = start_info->start_routine;
-       DWORD result;
-       gboolean suspend = start_info->suspend;
-       MonoThreadInfo *info;
-       int res;
-
-       info = mono_thread_info_attach (&result);
-       info->runtime_thread = TRUE;
-
-       start_info->handle = info->handle;
-
-       mono_threads_platform_set_priority(info, start_info->priority);
-
-       if (suspend) {
-               info->create_suspended = TRUE;
-               mono_coop_sem_init (&info->create_suspended_sem, 0);
-       }
-
-       mono_coop_sem_post (&(start_info->registered));
-
-       if (suspend) {
-               res = mono_coop_sem_wait (&info->create_suspended_sem, MONO_SEM_FLAGS_NONE);
-               g_assert (res != -1);
-
-               mono_coop_sem_destroy (&info->create_suspended_sem);
-       }
-
-       result = start_func (t_arg);
+       HANDLE result;
+       DWORD thread_id;
 
-       mono_thread_info_detach ();
+       result = CreateThread (NULL, stack_size, (LPTHREAD_START_ROUTINE) thread_fn, thread_data, 0, &thread_id);
+       if (!result)
+               return -1;
 
-       return result;
-}
+       /* A new handle is open when attaching
+        * the thread, so we don't need this one */
+       CloseHandle (result);
 
-HANDLE
-mono_threads_platform_create_thread (MonoThreadStart start_routine, gpointer arg, MonoThreadParm *tp, MonoNativeThreadId *out_tid)
-{
-       ThreadStartInfo start_info;
-       HANDLE result;
-       DWORD thread_id;
-       guint32 creation_flags = tp->creation_flags;
-       int res;
-
-       memset (&start_info, 0, sizeof (start_info));
-       mono_coop_sem_init (&(start_info.registered), 0);
-       start_info.arg = arg;
-       start_info.start_routine = start_routine;
-       start_info.suspend = creation_flags & CREATE_SUSPENDED;
-       start_info.priority = tp->priority;
-       creation_flags &= ~CREATE_SUSPENDED;
-
-       result = CreateThread (NULL, tp->stack_size, inner_start_thread, &start_info, creation_flags, &thread_id);
-       if (result) {
-               res = mono_coop_sem_wait (&(start_info.registered), MONO_SEM_FLAGS_NONE);
-               g_assert (res != -1);
-
-               /* A new handle has been opened when attaching
-                * the thread, so we don't need this one */
-               CloseHandle (result);
-       }
        if (out_tid)
                *out_tid = thread_id;
-       mono_coop_sem_destroy (&(start_info.registered));
-       return start_info.handle;
+
+       return 0;
 }
 
 
index 53a14e38440effbc912513977065b4231edcb4b1..0611e739d3772bbedc9b1e606c2bac84585a696c 100644 (file)
@@ -1138,6 +1138,75 @@ mono_thread_info_is_async_context (void)
                return FALSE;
 }
 
+typedef struct {
+       gint32 ref;
+       MonoThreadStart start_routine;
+       gpointer start_routine_arg;
+       gboolean create_suspended;
+       gint32 priority;
+       MonoCoopSem registered;
+       MonoThreadInfo *info;
+} CreateThreadData;
+
+static gsize WINAPI
+inner_start_thread (gpointer data)
+{
+       CreateThreadData *thread_data;
+       MonoThreadInfo *info;
+       MonoThreadStart start_routine;
+       gpointer start_routine_arg;
+       guint32 start_routine_res;
+       gboolean create_suspended;
+       gint32 priority;
+       gsize dummy;
+       gint res;
+
+       thread_data = (CreateThreadData*) data;
+       g_assert (thread_data);
+
+       start_routine = thread_data->start_routine;
+       start_routine_arg = thread_data->start_routine_arg;
+
+       create_suspended = thread_data->create_suspended;
+       priority = thread_data->priority;
+
+       info = mono_thread_info_attach (&dummy);
+       info->runtime_thread = TRUE;
+
+       mono_threads_platform_set_priority (info, priority);
+
+       if (create_suspended) {
+               info->create_suspended = TRUE;
+               mono_coop_sem_init (&info->create_suspended_sem, 0);
+       }
+
+       thread_data->info = info;
+
+       mono_coop_sem_post (&thread_data->registered);
+
+       if (InterlockedDecrement (&thread_data->ref) == 0) {
+               mono_coop_sem_destroy (&thread_data->registered);
+               g_free (thread_data);
+       }
+
+       /* thread_data is not valid anymore */
+       thread_data = NULL;
+
+       if (create_suspended) {
+               res = mono_coop_sem_wait (&info->create_suspended_sem, MONO_SEM_FLAGS_NONE);
+               g_assert (res == 0);
+
+               mono_coop_sem_destroy (&info->create_suspended_sem);
+       }
+
+       /* Run the actual main function of the thread */
+       start_routine_res = start_routine (start_routine_arg);
+
+       mono_threads_platform_exit (start_routine_res);
+
+       g_assert_not_reached ();
+}
+
 /*
  * mono_threads_create_thread:
  *
@@ -1147,7 +1216,43 @@ mono_thread_info_is_async_context (void)
 HANDLE
 mono_threads_create_thread (MonoThreadStart start, gpointer arg, MonoThreadParm *tp, MonoNativeThreadId *out_tid)
 {
-       return mono_threads_platform_create_thread (start, arg, tp, out_tid);
+       CreateThreadData *thread_data;
+       MonoThreadInfo *info;
+       gint res;
+       gpointer ret;
+
+       thread_data = g_new0 (CreateThreadData, 1);
+       thread_data->ref = 2;
+       thread_data->start_routine = start;
+       thread_data->start_routine_arg = arg;
+       thread_data->create_suspended = tp->creation_flags & CREATE_SUSPENDED;
+       thread_data->priority = tp->priority;
+       mono_coop_sem_init (&thread_data->registered, 0);
+
+       res = mono_threads_platform_create_thread (inner_start_thread, (gpointer) thread_data, tp->stack_size, out_tid);
+       if (res != 0) {
+               /* ref is not going to be decremented in inner_start_thread */
+               InterlockedDecrement (&thread_data->ref);
+               ret = NULL;
+               goto done;
+       }
+
+       res = mono_coop_sem_wait (&thread_data->registered, MONO_SEM_FLAGS_NONE);
+       g_assert (res == 0);
+
+       info = thread_data->info;
+       g_assert (info);
+
+       ret = info->handle;
+       g_assert (ret);
+
+done:
+       if (InterlockedDecrement (&thread_data->ref) == 0) {
+               mono_coop_sem_destroy (&thread_data->registered);
+               g_free (thread_data);
+       }
+
+       return ret;
 }
 
 /*
index 778deb5b51c584fa6a80b7f99ffd1b806078eda7..93e4aa4ce0fc1108402909aafa22af59b37b2782 100644 (file)
@@ -538,7 +538,7 @@ gboolean mono_threads_suspend_needs_abort_syscall (void);
 
 void mono_threads_platform_register (THREAD_INFO_TYPE *info);
 void mono_threads_platform_unregister (THREAD_INFO_TYPE *info);
-HANDLE mono_threads_platform_create_thread (MonoThreadStart start, gpointer arg, MonoThreadParm *, MonoNativeThreadId *out_tid);
+int mono_threads_platform_create_thread (MonoThreadStart thread_fn, gpointer thread_data, gsize stack_size, MonoNativeThreadId *out_tid);
 void mono_threads_platform_get_stack_bounds (guint8 **staddr, size_t *stsize);
 gboolean mono_threads_platform_yield (void);
 void mono_threads_platform_exit (int exit_code);