/* * create.c * * Description: * This translation unit implements routines associated with spawning a new * thread. */ #include #include #include #include "pthread.h" #include "implement.h" unsigned _pthread_start_call(void * us_arg) { /* We're now in a running thread. Any local variables here are on this threads private stack so we're safe to leave data in them until we leave. */ _pthread_threads_thread__t * us; _pthread_call_t * call; unsigned (*func)(void *); void * arg; unsigned ret; int from; us = (_pthread_threads_thread__t *) us_arg; /* FIXME: For now, if priority setting fails then at least ensure that our records reflect true reality. */ if (SetThreadPriority((HANDLE) us->thread, us->attr.priority) == FALSE) { us->attr.priority = GetThreadPriority((HANDLE) us->thread); } func = us->call.routine; arg = us->call.arg; /* FIXME: Should we be using sigsetjmp() here instead. */ from = setjmp(us->call.env); if (from == 0) { /* Normal return from setjmp(). */ ret = (*func)(arg); _pthread_vacuum(); /* Remove the thread entry on exit only if pthread_detach() was called and there are no waiting joins. */ /* CRITICAL SECTION */ pthread_mutex_lock(&_pthread_count_mutex); if (us->detach == TRUE && us->join_count == 0) { _pthread_delete_thread_entry(us); } pthread_mutex_lock(&_pthread_count_mutex); /* END CRITICAL SECTION */ } else { /* longjmp() teleported us here. func() called pthread_exit() which called longjmp(). */ _pthread_vacuum(); /* Remove the thread entry on exit only if pthread_detach() was called and there are no waiting joins. */ /* CRITICAL SECTION */ pthread_mutex_lock(&_pthread_count_mutex); if (us->detach == TRUE && us->join_count == 0) { _pthread_delete_thread_entry(us); } pthread_mutex_lock(&_pthread_count_mutex); /* END CRITICAL SECTION */ ret = 0; } /* From Win32's point of view we always return naturally from our start routine and so it should clean up it's own thread residue. */ return ret; } int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void * (*start_routine) (void *), void * arg) { HANDLE handle = NULL; unsigned flags; void * security = NULL; DWORD threadID; pthread_attr_t * attr_copy; _pthread_threads_thread_t * us; /* Success unless otherwise set. */ int ret = 0; if (_pthread_new_thread_entry((pthread_t) handle, us) == 0) { attr_copy = &(us->attr); /* Map given attributes otherwise just use default values. */ if (attr != NULL) { if (attr_copy->stacksize == 0) { attr_copy->stacksize = PTHREAD_STACK_MIN; } attr_copy->detachedstate = attr->detachedstate; attr_copy->priority = attr->priority; #if HAVE_SIGSET_T memcpy(&(attr_copy->sigmask), &(attr->sigmask), sizeof(sigset_t)); #endif /* HAVE_SIGSET_T */ } /* Start running, not suspended. */ flags = 0; handle = (HANDLE) _beginthreadex(security, attr_copy->stacksize, _pthread_start_call, (void *) us, flags, &threadID); if (handle == NULL) { ret = EAGAIN; } } else { ret = EAGAIN; } if (ret == 0) { /* Let the caller know the thread handle. */ *thread = (pthread_t) handle; } else { /* Remove the failed thread entry. */ _pthread_delete_thread_entry(us); } return ret; }