int gtthread_create(gtthread_t *thread, gtthread_attr_t const * attr, void *(*start_routine)(void *), void * arg) { //allocate memory for the thread and initialize to 0 gtthread_t* gt_thread = calloc(sizeof(*gt_thread),1); if(gt_thread==NULL){ return -1; } //check the thread attribute object if(attr==NULL){ *attr = default_gtthread_attr; } //create or retrieve a new stack for the thread if NULL size_t stack_size = attr->stack_size; uint8_t stack_base = attr->stack_base; if(stack_base==NULL){ stack_base = malloc(stack_size); if(stack_base==NULL){ //check for unsuccessful malloc return -1; } } stack_base = stack_base + stack_size; int flags = CLONE_FILES | CLONE_FS | CLONE_VM | CLONE_SIGHAND | CLONE_THREAD | CLONE_SYSVSEM | CLONE_DETACHED; int tid = __pthread_clone((int(*)(void*))start_routine, stack_base, flags, arg); if(tid<0){ //check for unsuccessful clone return -1; } int init_errno = _init_thread(thread, tid, (pthread_attr_t*) attr, stack_base, 1); return 0; }
void __libc_init_common(uintptr_t *elfdata) { int argc = *elfdata; char** argv = (char**)(elfdata + 1); char** envp = argv + argc + 1; pthread_attr_t thread_attr; static pthread_internal_t thread; static void* tls_area[BIONIC_TLS_SLOTS]; /* setup pthread runtime and maint thread descriptor */ unsigned stacktop = (__get_sp() & ~(PAGE_SIZE - 1)) + PAGE_SIZE; unsigned stacksize = 128 * 1024; unsigned stackbottom = stacktop - stacksize; pthread_attr_init(&thread_attr); pthread_attr_setstack(&thread_attr, (void*)stackbottom, stacksize); _init_thread(&thread, gettid(), &thread_attr, (void*)stackbottom); __init_tls(tls_area, &thread); /* clear errno - requires TLS area */ errno = 0; /* set program name */ __progname = argv[0] ? argv[0] : "<unknown>"; /* setup environment pointer */ environ = envp; /* setup system properties - requires environment */ __system_properties_init(); }
/* Init TLS for the initial thread. Called by the linker _before_ libc is mapped * in memory. Beware: all writes to libc globals from this function will * apply to linker-private copies and will not be visible from libc later on. * * Note: this function creates a pthread_internal_t for the initial thread and * stores the pointer in TLS, but does not add it to pthread's gThreadList. This * has to be done later from libc itself (see __libc_init_common). * * This function also stores the elf_data argument in a specific TLS slot to be later * picked up by the libc constructor. */ void __libc_init_tls(unsigned** elf_data) { unsigned stack_top = (__get_sp() & ~(PAGE_SIZE - 1)) + PAGE_SIZE; unsigned stack_size = 128 * 1024; unsigned stack_bottom = stack_top - stack_size; pthread_attr_t thread_attr; pthread_attr_init(&thread_attr); pthread_attr_setstack(&thread_attr, (void*) stack_bottom, stack_size); static pthread_internal_t thread; _init_thread(&thread, gettid(), &thread_attr, (void*) stack_bottom, false); static void* tls_area[BIONIC_TLS_SLOTS]; __init_tls(tls_area, &thread); tls_area[TLS_SLOT_BIONIC_PREINIT] = elf_data; }
/* Init TLS for the initial thread. Called by the linker _before_ libc is mapped * in memory. Beware: all writes to libc globals from this function will * apply to linker-private copies and will not be visible from libc later on. * * Note: this function creates a pthread_internal_t for the initial thread and * stores the pointer in TLS, but does not add it to pthread's gThreadList. This * has to be done later from libc itself (see __libc_init_common). * * This function also stores a pointer to the kernel argument block in a TLS slot to be * picked up by the libc constructor. */ void __libc_init_tls(KernelArgumentBlock& args) { __libc_auxv = args.auxv; uintptr_t stack_top = (__get_sp() & ~(PAGE_SIZE - 1)) + PAGE_SIZE; size_t stack_size = get_main_thread_stack_size(); uintptr_t stack_bottom = stack_top - stack_size; static void* tls[BIONIC_TLS_SLOTS]; static pthread_internal_t thread; thread.tid = gettid(); thread.tls = tls; pthread_attr_init(&thread.attr); pthread_attr_setstack(&thread.attr, (void*) stack_bottom, stack_size); _init_thread(&thread, false); __init_tls(&thread); tls[TLS_SLOT_BIONIC_PREINIT] = &args; }
int pthread_create(pthread_t* thread_out, pthread_attr_t const* attr, void* (*start_routine)(void*), void* arg) { ErrnoRestorer errno_restorer; // Inform the rest of the C library that at least one thread // was created. This will enforce certain functions to acquire/release // locks (e.g. atexit()) to protect shared global structures. // This works because pthread_create() is not called by the C library // initialization routine that sets up the main thread's data structures. __isthreaded = 1; pthread_internal_t* thread = reinterpret_cast<pthread_internal_t*>(calloc(sizeof(*thread), 1)); if (thread == NULL) { __libc_format_log(ANDROID_LOG_WARN, "libc", "pthread_create failed: couldn't allocate thread"); return EAGAIN; } thread->allocated_on_heap = true; if (attr == NULL) { pthread_attr_init(&thread->attr); } else { thread->attr = *attr; attr = NULL; // Prevent misuse below. } // Make sure the stack size is PAGE_SIZE aligned. size_t stack_size = (thread->attr.stack_size + (PAGE_SIZE-1)) & ~(PAGE_SIZE-1); if (thread->attr.stack_base == NULL) { // The caller didn't provide a stack, so allocate one. thread->attr.stack_base = __create_thread_stack(stack_size, thread->attr.guard_size); if (thread->attr.stack_base == NULL) { free(thread); __libc_format_log(ANDROID_LOG_WARN, "libc", "pthread_create failed: couldn't allocate %zd-byte stack", stack_size); return EAGAIN; } } else { // The caller did provide a stack, so remember we're not supposed to free it. thread->attr.flags |= PTHREAD_ATTR_FLAG_USER_STACK; } // Make room for TLS. void** tls = (void**)((uint8_t*)(thread->attr.stack_base) + stack_size - BIONIC_TLS_SLOTS * sizeof(void*)); // Create a mutex for the thread in TLS_SLOT_SELF to wait on once it starts so we can keep // it from doing anything until after we notify the debugger about it // // This also provides the memory barrier we need to ensure that all // memory accesses previously performed by this thread are visible to // the new thread. pthread_mutex_t* start_mutex = (pthread_mutex_t*) &tls[TLS_SLOT_SELF]; pthread_mutex_init(start_mutex, NULL); ScopedPthreadMutexLocker start_locker(start_mutex); tls[TLS_SLOT_THREAD_ID] = thread; int flags = CLONE_FILES | CLONE_FS | CLONE_VM | CLONE_SIGHAND | CLONE_THREAD | CLONE_SYSVSEM; int tid = __pthread_clone(start_routine, tls, flags, arg); if (tid < 0) { int clone_errno = errno; if ((thread->attr.flags & PTHREAD_ATTR_FLAG_USER_STACK) == 0) { munmap(thread->attr.stack_base, stack_size); } free(thread); __libc_format_log(ANDROID_LOG_WARN, "libc", "pthread_create failed: clone failed: %s", strerror(errno)); return clone_errno; } thread->tid = tid; int init_errno = _init_thread(thread, true); if (init_errno != 0) { // Mark the thread detached and let its __thread_entry run to // completion. (It'll just exit immediately, cleaning up its resources.) thread->internal_flags |= kPthreadInitFailed; thread->attr.flags |= PTHREAD_ATTR_FLAG_DETACHED; return init_errno; } // Notify any debuggers about the new thread. { ScopedPthreadMutexLocker debugger_locker(&gDebuggerNotificationLock); _thread_created_hook(thread->tid); } // Publish the pthread_t and let the thread run. *thread_out = (pthread_t) thread; return 0; }