summaryrefslogtreecommitdiff
path: root/create.c
diff options
context:
space:
mode:
Diffstat (limited to 'create.c')
-rw-r--r--create.c142
1 files changed, 110 insertions, 32 deletions
diff --git a/create.c b/create.c
index 7a374bb..6897a9f 100644
--- a/create.c
+++ b/create.c
@@ -6,23 +6,24 @@
* thread.
*/
+#include <windows.h>
+#include <process.h>
#include "pthread.h"
#include "implement.h"
-/* FIXME: There must be a Win32 routine to get this value. */
-DWORD pthread_threads_count = 0;
-
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;
- DWORD flags = 0; /* Always 0 for POSIX threads */
- DWORD stack = PTHREAD_STACK_MIN;
- LPSECURITY_ATTRIBUTES security = NULL;
+ 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
@@ -32,34 +33,111 @@ pthread_create(pthread_t *thread, const pthread_attr_t *attr,
*/
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.
- if (pthread_threads_count >= PTHREAD_THREADS_MAX)
+ 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 */
- switch (attr)
- {
- case NULL:
- /* Use POSIX default attributes */
- break;
- default:
- /* Map attributes */
- if (attr->stacksize != NULL)
- stack = (DWORD) attr->stacksize;
- break;
+ 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;
+ }
- /* FIXME: I don't have error return values to work with so
- I'm assuming this always succeeds (obviously not).
- */
- handle = CreateThread(security,
- stack,
- start_routine,
- arg,
- flags,
- &threadID);
-
- *thread = (pthread_t) handle;
- pthread_threads_count++;
- return 0;
-}
+ /* 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;
+}