summaryrefslogtreecommitdiff
path: root/create.c
blob: e8fd1c192e0535d0907fc37fd5fc2095a122a6f3 (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
117
118
119
120
121
122
123
124
/*
 * create.c
 *
 * Description:
 * This translation unit implements routines associated with spawning a new
 * thread.
 */

#include <windows.h>
#include <process.h>
#include <string.h>

#include "pthread.h"
#include "implement.h"

unsigned
_pthread_start_call(void * thisarg)
{
  /* 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 * this = thisarg;
  _pthread_call_t * call;
  unsigned (*func)(void *);
  void * arg;
  unsigned ret;
  int from;

  if (this->detached == PTHREAD_CREATE_DETACHED)
    {
      (void) CloseHandle(this->thread);
    }

  func = this->call.routine;
  arg = this->call.arg;

  /* FIXME: Should we be using sigsetjmp() here instead. */
  from = setjmp(this->call.env);

  if (from == 0)
    {
      ret = (*func)(arg);

      _pthread_vacuum();
    }
  else
    {
      /* func() called pthread_exit() which called longjmp(). */
      _pthread_vacuum();

      /* Never returns. */
      _endthreadex(0);
    }

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

  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;
	  attr_copy->canceltype = attr->canceltype;
	  attr_copy->detached = attr->detached;
	  attr_copy->priority = attr->priority;
	  memcpy(attr_copy.sigmask, attr.sigmask, sizeof(sigset_t)); 
	}

      /* Start running, not suspended. */
      flags = 0;

      handle = (HANDLE) _beginthreadex(security,
				       attr_copy->stacksize,
				       _pthread_start_call,
				       (void *) this,
				       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
    {
      /* Undo everything. */
      _pthread_delete_thread_entry(this);
    }

  return ret;
}