+
+#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
+
+ memset (&start_info, 0, sizeof (StartInfo));
+ start_info.start_routine = (gpointer)start_routine;
+ start_info.arg = arg;
+ start_info.flags = creation_flags;
+ MONO_SEM_INIT (&(start_info.registered), 0);
+
+ /* Actually start the thread */
+ res = mono_threads_get_callbacks ()->mono_gc_pthread_create (&thread, &attr, inner_start_thread, &start_info);
+ if (res) {
+ MONO_SEM_DESTROY (&(start_info.registered));
+ return NULL;
+ }
+
+ /* Wait until the thread register itself in various places */
+ while (MONO_SEM_WAIT (&(start_info.registered)) != 0) {
+ /*if (EINTR != errno) ABORT("sem_wait failed"); */
+ }
+ MONO_SEM_DESTROY (&(start_info.registered));
+
+ if (out_tid)
+ *out_tid = thread;
+
+ return start_info.handle;
+}
+
+/*
+ * mono_threads_core_resume_created:
+ *
+ * Resume a newly created thread created using CREATE_SUSPENDED.
+ */
+void
+mono_threads_core_resume_created (MonoThreadInfo *info, MonoNativeThreadId tid)
+{
+ MONO_SEM_POST (&info->create_suspended_sem);
+}
+
+gboolean
+mono_threads_core_yield (void)
+{
+ return sched_yield () == 0;
+}
+
+void
+mono_threads_core_exit (int exit_code)
+{
+ MonoThreadInfo *current = mono_thread_info_current ();
+
+#if defined(__native_client__)
+ nacl_shutdown_gc_thread();
+#endif
+
+ wapi_thread_handle_set_exited (current->handle, exit_code);
+
+ g_assert (mono_threads_get_callbacks ()->thread_exit);
+ mono_threads_get_callbacks ()->thread_exit (NULL);
+}
+
+void
+mono_threads_core_unregister (MonoThreadInfo *info)
+{
+ if (info->handle) {
+ wapi_thread_handle_set_exited (info->handle, 0);
+ info->handle = NULL;
+ }
+}
+
+HANDLE
+mono_threads_core_open_handle (void)
+{
+ MonoThreadInfo *info;
+
+ info = mono_thread_info_current ();
+ g_assert (info);
+
+ if (!info->handle)
+ info->handle = wapi_create_thread_handle ();
+ else
+ wapi_ref_thread_handle (info->handle);
+ return info->handle;
+}
+
+int
+mono_threads_get_max_stack_size (void)
+{
+ struct rlimit lim;
+
+ /* If getrlimit fails, we don't enforce any limits. */
+ if (getrlimit (RLIMIT_STACK, &lim))
+ return INT_MAX;
+ /* rlim_t is an unsigned long long on 64bits OSX but we want an int response. */
+ if (lim.rlim_max > (rlim_t)INT_MAX)
+ return INT_MAX;
+ return (int)lim.rlim_max;
+}
+
+HANDLE
+mono_threads_core_open_thread_handle (HANDLE handle, MonoNativeThreadId tid)
+{
+ wapi_ref_thread_handle (handle);
+
+ return handle;
+}
+
+gpointer
+mono_threads_core_prepare_interrupt (HANDLE thread_handle)
+{
+ return wapi_prepare_interrupt_thread (thread_handle);
+}
+
+void
+mono_threads_core_finish_interrupt (gpointer wait_handle)
+{
+ wapi_finish_interrupt_thread (wait_handle);
+}
+
+void
+mono_threads_core_self_interrupt (void)
+{
+ wapi_self_interrupt ();
+}
+
+void
+mono_threads_core_clear_interruption (void)
+{
+ wapi_clear_interruption ();