summaryrefslogtreecommitdiff
path: root/sync.c
blob: 628e5bb601b88abcff022f440c9f6a036fa64c44 (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
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
/*
 * sync.c
 *
 * Description:
 * This translation unit implements functions related to thread
 * synchronisation.
 */

/*
 * Code contributed by John E. Bossom <JEB>.
 */

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

int
pthread_detach (pthread_t tid)
     /*
      * ------------------------------------------------------
      * DOCPUBLIC
      *      This function detaches the given thread.
      *
      * PARAMETERS
      *      thread
      *              an instance of a pthread_t
      *
      *
      * DESCRIPTION
      *      This function detaches the given thread. You may
      *      detach the main thread or to detach a joinable thread
      *      (You should have used pthread_attr_t to create the
      *      thread as detached!)
      *      NOTE:   detached threads cannot be joined nor canceled;
      *                      storage is freed immediately on termination.
      *
      * RESULTS
      *              0               successfully detached the thread,
      *              EINVAL          thread is not a joinable thread,
      *              ENOSPC          a required resource has been exhausted,
      *              ESRCH           no thread could be found for 'thread',
      *
      * ------------------------------------------------------
      */
{
  int result;

  if (tid == NULL ||
      tid->detachState == PTHREAD_CREATE_DETACHED)
    {

      result = EINVAL;

    }
  else
    {
      result = 0;
      tid->detachState = PTHREAD_CREATE_DETACHED;
    }

  return (result);

}				/* pthread_detach */

int
pthread_join (pthread_t thread, void **value_ptr)
     /*
      * ------------------------------------------------------
      * DOCPUBLIC
      *      This function waits for 'thread' to terminate and
      *      returns the thread's exit value if 'value_ptr' is not
      *      NULL. This also detaches the thread on successful
      *      completion.
      *
      * PARAMETERS
      *      sem
      *              pointer to an instance of sem_t
      *
      *
      * DESCRIPTION
      *      This function waits for 'thread' to terminate and
      *      returns the thread's exit value if 'value_ptr' is not
      *      NULL. This also detaches the thread on successful
      *      completion.
      *      NOTE:   detached threads cannot be joined or canceled
      *
      * RESULTS
      *              0               'thread' has completed
      *              EINVAL          thread is not a joinable thread,
      *              ESRCH           no thread could be found with ID 'thread',
      *              EDEADLK         attempt to join thread with self
      *
      * ------------------------------------------------------
      */
{
  int result = 0;
  pthread_t self;

  self = pthread_self ();

  if (pthread_equal (self, thread) == 0)
    {
      result = EDEADLK;

    }
  else
    {
      DWORD stat;

      stat = WaitForSingleObject (thread->threadH, INFINITE);

      if (stat != WAIT_OBJECT_0 &&
	  !GetExitCodeThread (thread->threadH, (LPDWORD) value_ptr))
	{
	  result = ESRCH;
	}
      else
	{
	  _pthread_threadDestroy (thread);
	}
    }

  return (result);

}				/* pthread_join */

/* </JEB> */


#if 0 /* Pre Bossom */

#include <errno.h>

/* POSIX STANDARD: A thread may pass a value pointer to some data via
   pthread_exit(). That pointer will be stored in a location supplied
   as an argument to pthread_join().

   IMPLEMENTATION: The value_ptr is stored in the thread entry. When
   pthread_join() wakes up after waiting, or immediately if the target
   thread has already terminated but is not detached, the value
   pointer from pthread_exit() will be copied to *value_ptr.

   If the target thread does not become detached in the mean time, all
   waiting joins on that thread will get the value pointer. The last
   waiting join will delete the target thread entry.

   ----

   POSIX STANDARD: The results of multiple simultaneous calls to
   pthread_join() specifying the same target thread are undefined.

   IMPLEMENTATION: Any such join that occurs before the first such
   join wakes up, or the thread is otherwise detached (by a call to
   pthread_detach), will return successfully with the value that was
   passed to pthread_exit(). After the last such join returns, the
   target thread will have be detached and it's entry removed from the
   thread table.
  
   Until the target thread entry is deleted it will be counted against
   {PTHREAD_COUNT_MAX}.

   ----

   ----

   POSIX STANDARD: It is unspecified whether a thread that has exited
   but remains unjoined counts against {PTHREAD_COUNT_MAX}.

   IMPLEMENTATION: A thread that has exited but remains unjoined will
   be counted against {PTHREAD_COUNT_MAX}. The first call to
   pthread_join() or pthread_detach() will remove the target thread's
   table entry and decrement the count.

   ---- */

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

int
pthread_join(pthread_t thread, void ** valueptr)
{
  int detachstate;

  /* First check if we are trying to join to ourselves. */
  if (thread == pthread_self())
    {
      return EDEADLK;
    }

  if (thread != NULL)
    {
      int ret;

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

      /* If the thread is in DETACHED state, then join will return
	 immediately. */

      if (pthread_attr_getdetachstate(&(thread->attr), &detachstate) != 0 
	  || detachstate == PTHREAD_CREATE_DETACHED)
	{
	  return EINVAL;
	}

      thread->join_count++;

      pthread_mutex_unlock(&_pthread_table_mutex);
      /* END CRITICAL SECTION */

      /* CANCELATION POINT */
      pthread_testcancel();

      /* Wait on the kernel thread object. */
      switch (WaitForSingleObject(thread->win32handle, INFINITE))
	{
	case WAIT_FAILED:
	  /* The thread does not exist. */
	  return ESRCH;
	case WAIT_OBJECT_0:
	  /* The thread has finished. */
	  break;
	default:
	  /* This should never happen. */
	  break;
	}

      /* We know the target thread entry still exists at this point
	 because we incremented join_count above after checking. The
	 thread entry will not be removed until join_count == 0 again,
	 ie. when the last waiting join has passed through the
	 following critical section. */

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

      /* Collect the value pointer passed to pthread_exit().  If
	 another thread detaches our target thread while we're
	 waiting, then we report a deadlock as it likely that storage
	 pointed to by thread->joinvalueptr has been freed or
	 otherwise no longer valid. */

      if (pthread_attr_getdetachstate(&(thread->attr), &detachstate) != 0 
	  || detachstate == PTHREAD_CREATE_DETACHED)
	{
	  ret = EDEADLK;
	}
      else
	{
	  *valueptr = thread->joinvalueptr;
	  ret = 0;
	}

      thread->join_count--;

      /* If we're the last join to return then we are responsible for
	 removing the target thread's table entry. */
      if (thread->join_count == 0)
	{
	  ret = _pthread_delete_thread(thread);
	}

      pthread_mutex_unlock(&_pthread_table_mutex);
      /* END CRITICAL SECTION */

      return ret;
    }

  /* Thread not found. */
  return ESRCH;
}

int
pthread_detach(pthread_t thread)
{
  int detachstate;
  int ret;

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

  if (thread == NULL)
    {
      ret = ESRCH;
    }
  else
    {
      /* Check that we can detach this thread. */
      if (pthread_attr_getdetachstate(&(thread->attr), &detachstate) != 0 
	  || detachstate == PTHREAD_CREATE_DETACHED)
	{
	  ret = EINVAL;
	}
      else
	{
	  /* This is all we do here - the rest is done either when the
	     thread exits or when pthread_join() exits. Once this is
	     set it will never be unset. */
	  pthread_attr_setdetachstate(&(thread->attr), 
					PTHREAD_CREATE_DETACHED);

	  ret = 0;
	}
    }

  pthread_mutex_unlock(&_pthread_table_mutex);
  /* END CRITICAL SECTION */

  return ret;
}

#endif /* Pre Bossom */