/* * create.c * * Description: * This translation unit implements routines associated with spawning a new * thread. */ #include #include #include "pthread.h" #include "implement.h" int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void * (*start_routine) (void *), void * arg) { /* Call Win32 CreateThread. Map attributes as correctly as possible. The passed in attr structure will be modified by this routine to reflect any default values used. This is POSIX semantics. */ HANDLE handle = NULL; unsigned flags; unsigned stack; void * security = NULL; /* FIXME: This needs to be moved into process space. Perhaps into a structure that contains all per thread info that is Win32 thread specific but not visible from the pthreads API, and accessible through HANDLE (or pthread_t). */ SECURITY_ATTRIBUTES security_attr; DWORD threadID; int t; int ret = 0; /* Success unless otherwise set */ char * privmem; pthread_attr_t * attr_copy; _pthread_cleanup_stack_t * cleanup_stack; /* Use and modify attr_copy. Only after we've succeeded in creating the new thread can we modify any passed-in structures. We use one malloc() to get all of our heap space and then allocate it further. */ if (NULL == (privmem = (char) malloc(sizeof(pthread_attr_t) + sizeof(_pthread_cleanup_stack_t) + sizeof(DWORD)))) { return EAGAIN; } attr_copy = (pthread_attr_t *) privmem; /* Force the next to a DWORD boundary. This is all compile time arithmetic. */ cleanup_stack = (_pthread_cleanup_stack_t *) &privmem[((sizeof(pthread_attr_t) / sizeof(DWORD)) + 1) * sizeof(DWORD)]; (void) memcpy(attr_copy, attr); /* CRITICAL SECTION */ pthread_mutex_lock(&_pthread_count_mutex); if (_pthread_threads_count < PTHREAD_THREADS_MAX) { switch (attr) { case NULL: /* Use POSIX default attributes */ stack = attr_copy->stacksize = PTHREAD_STACK_MIN; break; default: /* Map attributes */ if (attr_copy.stacksize != NULL) stack = (DWORD) attr_copy->stacksize; else stack = attr_copy->stacksize = PTHREAD_STACK_MIN; break; } flags = 1; /* Start suspended and resume at the last moment */ handle = (HANDLE) _beginthreadex(security, stack, (unsigned (_stdcall *)(void *)) start_routine, arg, flags, &threadID); if (handle != NULL) { /* We have a new thread */ _pthread_threads_count++; /* The hash table works as follows: hash into the table, if the slot is occupied then start single stepping from there until we find an available slot. There is at least one slot available at this point. */ t = _PTHREAD_HASH_INDEX(handle); while ((_pthread_threads_table[t])->thread != NULL) { t++; if (t == PTHREAD_THREADS_MAX) t = 0; /* Wrap around to the first slot */ } if ((_pthread_threads_table[t])->thread != NULL) { /* INTERNAL ERROR */ } else { (_pthread_threads_table[t])->thread = handle; (_pthread_threads_table[t])->attr = attr_copy; (_pthread_threads_table[t])->cleanupstack = cleanup_stack; } } else { ret = EAGAIN; } } else { ret = EAGAIN; } /* Let others in as soon as possible. */ pthread_mutex_unlock(&_pthread_count_mutex); /* END CRITICAL SECTION */ if (ret == 0) { *thread = (pthread_t) handle; (void) memcpy(attr, attr_copy); /* POSIX threads are always running after creation. Start the thread only after passed-in structures have been modified to avoid race conditions. */ ResumeThread(handle); } else { free(privmem); } return ret; }