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
|
/*
* sync.c
*
* Description:
* This translation unit implements functions related to thread
* synchronisation.
*/
/* 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)
{
LPDWORD exitcode;
int detachstate;
_pthread_threads_thread_t * target;
/* First check if we are trying to join to ourselves. */
if (thread == pthread_self())
{
return EDEADLK;
}
/* Find the thread. */
target = _pthread_find_thread_entry(thread);
if (target != NULL)
{
pthread_mutex_t * target_thread_mutex;
int ret;
target_thread_mutex = _PTHREAD_THREAD_MUTEX(target);
/* CRITICAL SECTION */
pthread_mutex_lock(&_pthread_count_mutex);
/* If the thread is in DETACHED state, then join will return
immediately. */
if (pthread_attr_getdetachedstate(&(target->attr), &detachstate) != 0
|| detachstate == PTHREAD_CREATE_DETACHED)
{
return EINVAL;
}
target->join_count++;
pthread_mutex_lock(&_pthread_count_mutex);
/* END CRITICAL SECTION */
/* CANCELATION POINT */
pthread_testcancel();
/* Wait on the kernel thread object. */
switch (WaitForSingleObject(thread, 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_count_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 target->joinvalueptr has been freed or
otherwise no longer valid. */
if (pthread_attr_getdetachedstate(&(target->attr), &detachstate) != 0
|| detachstate == PTHREAD_CREATE_DETACHED)
{
ret = EDEADLK;
}
else
{
*value_ptr = target->joinvalueptr;
ret = 0;
}
target->join_count--;
/* If we're the last join to return then we are responsible for
removing the target thread's table entry. */
if (target->join_count == 0)
{
_pthread_delete_thread_entry(target);
}
pthread_mutex_lock(&_pthread_count_mutex);
/* END CRITICAL SECTION */
return ret;
}
/* Thread not found. */
return ESRCH;
}
int
pthread_detach(pthread_t thread)
{
_pthread_threads_thread_t * target;
int detachstate;
int ret;
pthread_mutex_t * target_thread_mutex;
/* CRITICAL SECTION */
pthread_mutex_lock(&_pthread_count_mutex);
target = _pthread_find_thread_entry(thread);
if (target == NULL)
{
ret = ESRCH;
}
else
{
target_thread_mutex = _PTHREAD_THREAD_MUTEX(target);
/* Check that we can detach this thread. */
if (pthread_attr_getdetachedstate(&(target->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_setdetachedstate(&(target->attr),
PTHREAD_CREATE_DETACHED);
ret = 0;
}
}
pthread_mutex_unlock(&_pthread_count_mutex);
/* END CRITICAL SECTION */
return ret;
}
|