+ th->os_thread=thread_self();
+ protect_control_stack_guard_page(1, NULL);
+ protect_binding_stack_guard_page(1, NULL);
+ protect_alien_stack_guard_page(1, NULL);
+ /* Since GC can only know about this thread from the all_threads
+ * list and we're just adding this thread to it, there is no
+ * danger of deadlocking even with SIG_STOP_FOR_GC blocked (which
+ * it is not). */
+#ifdef LISP_FEATURE_SB_SAFEPOINT
+ *th->csp_around_foreign_call = (lispobj)&function;
+ pthread_mutex_lock(thread_qrl(th));
+#endif
+ lock_ret = pthread_mutex_lock(&all_threads_lock);
+ gc_assert(lock_ret == 0);
+ link_thread(th);
+ lock_ret = pthread_mutex_unlock(&all_threads_lock);
+ gc_assert(lock_ret == 0);
+
+ /* Kludge: Changed the order of some steps between the safepoint/
+ * non-safepoint versions of this code. Can we unify this more?
+ */
+#ifdef LISP_FEATURE_SB_SAFEPOINT
+ WITH_GC_AT_SAFEPOINTS_ONLY() {
+ result = funcall0(function);
+ block_blockable_signals(0, 0);
+ gc_alloc_update_page_tables(BOXED_PAGE_FLAG, &th->alloc_region);
+ }
+ lock_ret = pthread_mutex_lock(&all_threads_lock);
+ gc_assert(lock_ret == 0);
+ unlink_thread(th);
+ lock_ret = pthread_mutex_unlock(&all_threads_lock);
+ gc_assert(lock_ret == 0);
+ pthread_mutex_unlock(thread_qrl(th));
+ set_thread_state(th,STATE_DEAD);
+#else
+ result = funcall0(function);
+
+ /* Block GC */
+ block_blockable_signals(0, 0);
+ set_thread_state(th, STATE_DEAD);
+
+ /* SIG_STOP_FOR_GC is blocked and GC might be waiting for this
+ * thread, but since we are already dead it won't wait long. */
+ lock_ret = pthread_mutex_lock(&all_threads_lock);
+ gc_assert(lock_ret == 0);
+
+ gc_alloc_update_page_tables(BOXED_PAGE_FLAG, &th->alloc_region);
+ unlink_thread(th);
+ pthread_mutex_unlock(&all_threads_lock);
+ gc_assert(lock_ret == 0);
+#endif
+
+ if(th->tls_cookie>=0) arch_os_thread_cleanup(th);
+ os_sem_destroy(th->state_sem);
+ os_sem_destroy(th->state_not_running_sem);
+ os_sem_destroy(th->state_not_stopped_sem);
+
+#if defined(LISP_FEATURE_WIN32)
+ free((os_vm_address_t)th->interrupt_data);
+#else
+ os_invalidate((os_vm_address_t)th->interrupt_data,
+ (sizeof (struct interrupt_data)));
+#endif
+
+#ifdef LISP_FEATURE_MACH_EXCEPTION_HANDLER
+ mach_lisp_thread_destroy(th);
+#endif
+
+#if defined(LISP_FEATURE_WIN32)
+ int i;
+ for (i = 0; i<
+ (int) (sizeof(th->private_events.events)/
+ sizeof(th->private_events.events[0])); ++i) {
+ CloseHandle(th->private_events.events[i]);
+ }
+ TlsSetValue(OUR_TLS_INDEX,NULL);
+#endif
+
+ schedule_thread_post_mortem(th);
+ FSHOW((stderr,"/exiting thread %lu\n", thread_self()));
+ return result;
+}
+
+#endif /* LISP_FEATURE_SB_THREAD */
+
+static void
+free_thread_struct(struct thread *th)
+{
+#if defined(LISP_FEATURE_WIN32)
+ if (th->interrupt_data) {
+ os_invalidate_free((os_vm_address_t) th->interrupt_data,
+ (sizeof (struct interrupt_data)));
+ }
+ os_invalidate_free((os_vm_address_t) th->os_address,
+ THREAD_STRUCT_SIZE);
+#else
+ if (th->interrupt_data)
+ os_invalidate((os_vm_address_t) th->interrupt_data,
+ (sizeof (struct interrupt_data)));
+ os_invalidate((os_vm_address_t) th->os_address,
+ THREAD_STRUCT_SIZE);
+#endif