summaryrefslogtreecommitdiff
path: root/create.c
blob: 37ce88f236f2359b88deb587edc3653af44bf96e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
/*
 * create.c
 *
 * Description:
 * This translation unit implements routines associated with spawning a new
 * thread.
 */

#include <windows.h>
#include <process.h>
#include "pthread.h"
#include "implement.h"

unsigned
_pthread_start_call(void *this)
{
  /* 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. */
  unsigned (*func)(void *) = this->call.routine;
  void * arg = this->call.arg;
  unsigned ret;

  ret = (*func)(arg);

  /* If we get to here then we're returning naturally and haven't
     been cancelled. We need to cleanup and remove the thread
     from the threads table. */
  _pthread_vacuum();

  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;

  /* 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;
  /* Success unless otherwise set. */
  int ret = 0;
  pthread_attr_t * attr_copy;
  _pthread_threads_thread_t * this;

  /* CRITICAL SECTION */
  pthread_mutex_lock(&_pthread_count_mutex);

  if (_pthread_new_thread_entry((pthread_t) handle, &this) == 0)
    {
      attr_copy = &(this->attr);

      if (attr != NULL) 
	{
	  /* Map attributes */
	  if (attr_copy->stacksize == 0)
	    {
	      attr_copy->stacksize = PTHREAD_STACK_MIN;
	    }

	  attr_copy->cancelability = attr->cancelability;
	}

      /* Start suspended and resume at the last moment to avoid
	 race conditions, ie. where a thread may enquire it's
	 attributes before we finish storing them away. */
      flags = 1;

      handle = (HANDLE) _beginthreadex(security,
				       attr_copy->stacksize,
				       _pthread_start_call,
				       (void *) this,
				       flags,
				       &threadID);

      if (handle == NULL)
	{
	  ret = EAGAIN;
	}
    }
  else
    {
      ret = EAGAIN;
    }

  /* Let others in as soon as possible. */
  pthread_mutex_unlock(&_pthread_count_mutex);
  /* END CRITICAL SECTION */

  if (ret == 0)
    {
      /* Let the caller know the thread handle. */
      *thread = (pthread_t) handle;

      /* POSIX threads are always running after creation. */
      ResumeThread(handle);
    }
  else
    {
      /* Undo everything. */
      _pthread_delete_thread_entry(this);
    }

  return ret;
}