/* * This replaces __pthread_initialize_minimal() from libnacl and * __pthread_initialize() from libpthread. */ void __pthread_initialize(void) { struct nc_combined_tdb *tdb; /* * Allocate the area. If malloc fails here, we'll crash before it returns. */ size_t combined_size = __nacl_tls_combined_size(sizeof(*tdb)); void *combined_area = malloc(combined_size); /* * Initialize TLS proper (i.e., __thread variable initializers). */ void *tp = __nacl_tls_initialize_memory(combined_area, sizeof(*tdb)); tdb = get_irt_tdb(tp); __nc_initialize_unjoinable_thread(tdb); tdb->tdb.irt_thread_data = combined_area; /* * Now install it for later fetching. * This is what our private version of __nacl_read_tp will read. */ NACL_SYSCALL(second_tls_set)(tp); /* * Finally, do newlib per-thread initialization. */ __newlib_thread_init(); __nc_initialize_globals(); }
static void nc_thread_starter(void) { nc_thread_descriptor_t *tdb = nc_get_tdb(); __newlib_thread_init(); #if defined(NACL_IN_IRT) g_is_irt_internal_thread = 1; #endif void *retval = tdb->start_func(tdb->state); /* * Free handler list to prevent memory leak in case function returns * without calling pthread_cleanup_pop(), although doing that is unspecified * behaviour. */ while (NULL != __nc_cleanup_handlers) { pthread_cleanup_pop(0); } /* If the function returns, terminate the thread. */ pthread_exit(retval); /* NOTREACHED */ /* TODO(gregoryd) - add assert */ }
/* See tls.h. */ int __pthread_initialize_minimal(size_t tdb_size) { /* Use sbrk not malloc here since the library is not initialized yet. */ size_t combined_size = __nacl_tls_combined_size(tdb_size); /* Adapt size for sbrk. */ /* TODO(robertm): this is somewhat arbitrary - re-examine). */ combined_size = (combined_size + 15) & ~15; void *combined_area = sbrk(combined_size); /* (uses nacl_sysbrk) */ __nacl_tls_data_bss_initialize_from_template(combined_area); /* Patch the first word of the TDB to contain the "base" of the TLS area. */ void *tdb = __nacl_tls_tdb_start(combined_area); *(void**) tdb = tdb; /* Set %gs, r9, or equivalent platform-specific mechanism. Requires * a syscall since certain bitfields of these registers are trusted. */ NACL_SYSCALL(tls_init)(tdb, tdb_size); /* initialize newlib's thread-specific pointer. */ __newlib_thread_init(); return 0; }
/* * 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. */ }