void pthread_exit(void *retval) { /* Get all we need from the tdb before releasing it. */ nc_thread_descriptor_t *tdb = nc_get_tdb(); nc_thread_memory_block_t *stack_node = tdb->stack_node; int32_t *is_used = &stack_node->is_used; nc_basic_thread_data_t *basic_data = tdb->basic_data; int joinable = tdb->joinable; /* Call cleanup handlers. */ while (NULL != __nc_cleanup_handlers) { pthread_cleanup_pop(1); } /* Call the destruction functions for TSD. */ __nc_tsd_exit(); __newlib_thread_exit(); __nc_futex_thread_exit(); if (__nc_initial_thread_id != basic_data) { pthread_mutex_lock(&__nc_thread_management_lock); --__nc_running_threads_counter; pthread_mutex_unlock(&__nc_thread_management_lock); } else { /* This is the main thread - wait for other threads to complete. */ wait_for_threads(); exit(0); } pthread_mutex_lock(&__nc_thread_management_lock); basic_data->retval = retval; if (joinable) { /* If somebody is waiting for this thread, signal. */ basic_data->status = THREAD_TERMINATED; pthread_cond_signal(&basic_data->join_condvar); } /* * We can release TLS+TDB - thread id and its return value are still * kept in basic_data. */ nc_release_tls_node(tdb->tls_node, tdb); if (!joinable) { nc_release_basic_data_mu(basic_data); } /* Now add the stack to the list but keep it marked as used. */ nc_free_memory_block_mu(THREAD_STACK_MEMORY, stack_node); if (1 == __nc_running_threads_counter) { pthread_cond_signal(&__nc_last_thread_cond); } pthread_mutex_unlock(&__nc_thread_management_lock); irt_thread.thread_exit(is_used); nc_abort(); }
static void nacl_irt_thread_exit(int32_t *stack_flag) { struct nc_combined_tdb *tdb = get_irt_tdb(__nacl_read_tp()); __nc_tsd_exit(); /* * Sanity check: Check that this function was not called on a thread * created by the IRT's internal pthread_create(). For such * threads, irt_thread_data == NULL. */ assert(tdb->tdb.irt_thread_data != NULL); free(tdb->tdb.irt_thread_data); NACL_SYSCALL(thread_exit)(stack_flag); while (1) *(volatile int *) 0 = 0; /* Crash. */ }