static inline nc_thread_descriptor_t *nc_get_tdb(void) { /* * Fetch the thread-specific data pointer. This is usually just * a wrapper around __libnacl_irt_tls.tls_get() but we don't use * that here so that the IRT build can override the definition. */ return (void *) ((char *) __nacl_read_tp() + __nacl_tp_tdb_offset(TDB_SIZE)); }
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. */ }
/* * This is the real first entry point for new threads. */ static void irt_start_thread(void) { struct nc_combined_tdb *tdb = get_irt_tdb(__nacl_read_tp()); /* * Fetch the user's start routine. */ void (*user_start)(void) = (void (*)(void)) tdb->tdb.start_func; /* * Now do per-thread initialization for the IRT-private C library state. */ __newlib_thread_init(); /* * Finally, run the user code. */ (*user_start)(); /* * That should never return. Crash hard if it does. */ while (1) *(volatile int *) 0 = 0; /* Crash. */ }