summaryrefslogtreecommitdiff
path: root/create.c
blob: 3814a230d428918e30322502e3c29e62ca044a12 (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
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
/*
 * 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"

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.

     To save time we use one malloc() to get all of our heap space and
     then allocate it further.
   */

  if (NULL == 
      (privmem = (char) malloc(RND_SIZEOF(pthread_attr_t) +
			       RND_SIZEOF(_pthread_cleanup_stack_t)))) {
    return EAGAIN;
  }

  attr_copy = (pthread_attr_t *) privmem;

  /* Force cleanup_stack to start at a DWORD boundary within privmem.
   */
  cleanup_stack = 
    (_pthread_cleanup_stack_t *) &privmem[RND_SIZEOF(pthread_attr_t)];

  (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 to avoid
		  race conditions, ie. where a thread may enquire it's
		  attributes before we finish storing them away.
		*/

    handle = (HANDLE) _beginthreadex(security,
				   stack,
				   (unsigned (_stdcall *)(void *)) start_routine,
				   arg,
				   flags,
				   &threadID);

    if (handle != NULL) {
      _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.
       */
      t = _PTHREAD_HASH_INDEX(handle);
      while ((_pthread_threads_table[t])->thread != NULL) {
	t++;

	if (t == PTHREAD_THREADS_MAX)
	  t = 0; /* Wrap to the top of the table. */
      }

      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.
     */
    ResumeThread(handle);
  } else {
    free(privmem);
  }

  return ret;
}