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; }
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; }
TEST(pthread, __pthread_clone) { uintptr_t fake_child_stack[16]; errno = 0; ASSERT_EQ(-1, __pthread_clone(NULL, &fake_child_stack[0], CLONE_THREAD, NULL)); ASSERT_EQ(EINVAL, errno); }