+ os_invalidate(corpse->os_address, THREAD_STRUCT_SIZE);
+#endif
+}
+
+# else
+
+/* THREAD POST MORTEM CLEANUP
+ *
+ * Memory allocated for the thread stacks cannot be reclaimed while
+ * the thread is still alive, so we need a mechanism for post mortem
+ * cleanups. FIXME: We actually have three, for historical reasons as
+ * the saying goes. Do we really need three? Nikodemus guesses that
+ * not anymore, now that we properly call pthread_attr_destroy before
+ * freeing the stack. */
+
+static struct thread_post_mortem *
+plan_thread_post_mortem(struct thread *corpse)
+{
+ if (corpse) {
+ struct thread_post_mortem *post_mortem = malloc(sizeof(struct thread_post_mortem));
+ gc_assert(post_mortem);
+ post_mortem->os_thread = corpse->os_thread;
+ post_mortem->os_attr = corpse->os_attr;
+ post_mortem->os_address = corpse->os_address;
+#ifdef DELAY_THREAD_POST_MORTEM
+ post_mortem->next = NULL;
+#endif
+ return post_mortem;
+ } else {
+ /* FIXME: When does this happen? */
+ return NULL;
+ }
+}
+
+static void
+perform_thread_post_mortem(struct thread_post_mortem *post_mortem)
+{
+#ifdef CREATE_POST_MORTEM_THREAD
+ pthread_detach(pthread_self());
+#endif
+ if (post_mortem) {
+ gc_assert(!pthread_join(post_mortem->os_thread, NULL));
+ gc_assert(!pthread_attr_destroy(post_mortem->os_attr));
+ free(post_mortem->os_attr);
+ os_invalidate(post_mortem->os_address, THREAD_STRUCT_SIZE);
+ free(post_mortem);
+ }
+}
+
+static void
+schedule_thread_post_mortem(struct thread *corpse)
+{
+ struct thread_post_mortem *post_mortem = NULL;
+ if (corpse) {
+ post_mortem = plan_thread_post_mortem(corpse);
+
+#ifdef DELAY_THREAD_POST_MORTEM
+ pthread_mutex_lock(&thread_post_mortem_lock);
+ /* First stick the new post mortem to the end of the queue. */
+ if (pending_thread_post_mortem) {
+ struct thread_post_mortem *next = pending_thread_post_mortem;
+ while (next->next) {
+ next = next->next;
+ }
+ next->next = post_mortem;
+ } else {
+ pending_thread_post_mortem = post_mortem;
+ }
+ /* Then, if there are enough things in the queue, clean up one
+ * from the head -- or increment the count, and null out the
+ * post_mortem we have. */
+ if (pending_thread_post_mortem_count > DELAY_THREAD_POST_MORTEM) {
+ post_mortem = pending_thread_post_mortem;
+ pending_thread_post_mortem = post_mortem->next;
+ } else {
+ pending_thread_post_mortem_count++;
+ post_mortem = NULL;
+ }
+ pthread_mutex_unlock(&thread_post_mortem_lock);
+ /* Finally run, the cleanup, if any. */
+ perform_thread_post_mortem(post_mortem);
+#elif defined(CREATE_POST_MORTEM_THREAD)
+ gc_assert(!pthread_create(&thread, NULL, perform_thread_post_mortem, post_mortem));
+#else
+ post_mortem = (struct thread_post_mortem *)
+ swap_lispobjs((lispobj *)(void *)&pending_thread_post_mortem,
+ (lispobj)post_mortem);
+ perform_thread_post_mortem(post_mortem);
+#endif
+ }
+}
+
+# endif /* !IMMEDIATE_POST_MORTEM */
+
+/* Note: scribble must be stack-allocated */
+static void
+init_new_thread(struct thread *th, init_thread_data *scribble, int guardp)
+{
+ int lock_ret;
+
+ pthread_setspecific(lisp_thread, (void *)1);
+ if(arch_os_thread_init(th)==0) {
+ /* FIXME: handle error */
+ lose("arch_os_thread_init failed\n");
+ }
+
+ th->os_thread=thread_self();
+ if (guardp)
+ 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)scribble;
+#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
+ gc_state_lock();
+ gc_state_wait(GC_NONE);
+ gc_state_unlock();
+ push_gcing_safety(&scribble->safety);
+#endif
+}
+
+static void
+undo_init_new_thread(struct thread *th, init_thread_data *scribble)
+{
+ int lock_ret;
+
+ /* 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
+ block_blockable_signals(0, 0);
+ gc_alloc_update_page_tables(BOXED_PAGE_FLAG, &th->alloc_region);
+#if defined(LISP_FEATURE_SB_SAFEPOINT_STRICTLY) && !defined(LISP_FEATURE_WIN32)
+ gc_alloc_update_page_tables(BOXED_PAGE_FLAG, &th->sprof_alloc_region);
+#endif
+ pop_gcing_safety(&scribble->safety);
+ 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);
+#else
+ /* 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);
+#if defined(LISP_FEATURE_SB_SAFEPOINT_STRICTLY) && !defined(LISP_FEATURE_WIN32)
+ gc_alloc_update_page_tables(BOXED_PAGE_FLAG, &th->sprof_alloc_region);
+#endif
+ unlink_thread(th);
+ pthread_mutex_unlock(&all_threads_lock);
+ gc_assert(lock_ret == 0);