20
20
#include <stdint.h>
21
21
#include <errno.h>
22
22
#include <sys/time.h>
23
+ #include <assert.h>
23
24
24
25
int pthread_once (pthread_once_t * once_control , void (* init_routine )(void ))
25
26
{
@@ -113,87 +114,132 @@ int pthread_cond_wait(pthread_cond_t *restrict cond,
113
114
return cond_wait (cond , mutex , INFINITE );
114
115
}
115
116
117
+ static pthread_mutex_t pthread_table_lock = PTHREAD_MUTEX_INITIALIZER ;
118
+ static struct m_thread_info * pthread_table ;
119
+ size_t pthread_table_num ;
120
+
116
121
struct m_thread_info {
122
+ DWORD id ;
117
123
HANDLE handle ;
118
124
void * (* user_fn )(void * );
119
125
void * user_arg ;
120
126
void * res ;
121
127
};
122
128
123
- // Assuming __thread maps to __declspec(thread)
124
- static __thread struct m_thread_info * self ;
129
+ static struct m_thread_info * find_thread_info (DWORD id )
130
+ {
131
+ for (int n = 0 ; n < pthread_table_num ; n ++ ) {
132
+ if (id == pthread_table [n ].id )
133
+ return & pthread_table [n ];
134
+ }
135
+ return NULL ;
136
+ }
125
137
126
- pthread_t pthread_self ( void )
138
+ static void remove_thread_info ( struct m_thread_info * info )
127
139
{
128
- return (pthread_t ){GetCurrentThreadId (), self };
140
+ assert (pthread_table_num );
141
+ assert (info >= & pthread_table [0 ] && info < & pthread_table [pthread_table_num ]);
142
+
143
+ pthread_table [info - pthread_table ] = pthread_table [pthread_table_num - 1 ];
144
+ pthread_table_num -= 1 ;
145
+
146
+ // Avoid upsetting leak detectors.
147
+ if (pthread_table_num == 0 ) {
148
+ free (pthread_table );
149
+ pthread_table = NULL ;
150
+ }
129
151
}
130
152
131
153
void pthread_exit (void * retval )
132
154
{
133
- if (! self )
134
- abort (); // not started with pthread_create
135
- self -> res = retval ;
136
- if (! self -> handle ) {
137
- // detached case
138
- free ( self );
139
- self = NULL ;
140
- }
155
+ pthread_mutex_lock ( & pthread_table_lock );
156
+ struct m_thread_info * info = find_thread_info ( pthread_self ());
157
+ assert ( info ); // not started with pthread_create, or pthread_join() race
158
+ info -> res = retval ;
159
+ if (! info -> handle )
160
+ remove_thread_info ( info ); // detached case
161
+ pthread_mutex_unlock ( & pthread_table_lock ) ;
162
+
141
163
ExitThread (0 );
142
164
}
143
165
144
166
int pthread_join (pthread_t thread , void * * retval )
145
167
{
146
- if (!thread .info )
147
- abort (); // not started with pthread_create
148
- HANDLE h = thread .info -> handle ;
149
- if (!h )
150
- abort (); // thread was detached
168
+ pthread_mutex_lock (& pthread_table_lock );
169
+ struct m_thread_info * info = find_thread_info (thread );
170
+ assert (info ); // not started with pthread_create, or pthread_join() race
171
+ HANDLE h = info -> handle ;
172
+ assert (h ); // thread was detached
173
+ pthread_mutex_unlock (& pthread_table_lock );
174
+
151
175
WaitForSingleObject (h , INFINITE );
176
+
177
+ pthread_mutex_lock (& pthread_table_lock );
178
+ info = find_thread_info (thread );
179
+ assert (info );
180
+ assert (info -> handle == h );
152
181
CloseHandle (h );
153
182
if (retval )
154
- * retval = thread .info -> res ;
155
- free (thread .info );
183
+ * retval = info -> res ;
184
+ remove_thread_info (info );
185
+ pthread_mutex_unlock (& pthread_table_lock );
186
+
156
187
return 0 ;
157
188
}
158
189
159
190
int pthread_detach (pthread_t thread )
160
191
{
161
192
if (!pthread_equal (thread , pthread_self ()))
162
193
abort (); // restriction of this wrapper
163
- if (!thread .info )
164
- abort (); // not started with pthread_create
165
- if (!thread .info -> handle )
166
- abort (); // already deatched
167
- CloseHandle (thread .info -> handle );
168
- thread .info -> handle = NULL ;
194
+
195
+ pthread_mutex_lock (& pthread_table_lock );
196
+ struct m_thread_info * info = find_thread_info (thread );
197
+ assert (info ); // not started with pthread_create
198
+ assert (info -> handle ); // already detached
199
+ CloseHandle (info -> handle );
200
+ info -> handle = NULL ;
201
+ pthread_mutex_unlock (& pthread_table_lock );
202
+
169
203
return 0 ;
170
204
}
171
205
172
206
static DWORD WINAPI run_thread (LPVOID lpParameter )
173
207
{
174
208
struct m_thread_info * info = lpParameter ;
175
- self = info ;
176
209
pthread_exit (info -> user_fn (info -> user_arg ));
177
210
abort (); // not reached
178
211
}
179
212
180
213
int pthread_create (pthread_t * thread , const pthread_attr_t * attr ,
181
214
void * (* start_routine ) (void * ), void * arg )
182
215
{
183
- struct m_thread_info * info = calloc (1 , sizeof (* info ));
184
- if (!info )
185
- return EAGAIN ;
186
- info -> user_fn = start_routine ;
187
- info -> user_arg = arg ;
188
- HANDLE h = CreateThread (NULL , 0 , run_thread , info , CREATE_SUSPENDED , NULL );
189
- if (!h ) {
190
- free (info );
191
- return EAGAIN ;
216
+ int res = 0 ;
217
+ pthread_mutex_lock (& pthread_table_lock );
218
+ void * nalloc =
219
+ realloc (pthread_table , (pthread_table_num + 1 ) * sizeof (pthread_table [0 ]));
220
+ if (!nalloc ) {
221
+ res = EAGAIN ;
222
+ goto done ;
192
223
}
193
- info -> handle = h ;
194
- * thread = (pthread_t ){GetThreadId (h ), info };
195
- ResumeThread (h );
196
- return 0 ;
224
+ pthread_table = nalloc ;
225
+ pthread_table_num += 1 ;
226
+ struct m_thread_info * info = & pthread_table [pthread_table_num - 1 ];
227
+ * info = (struct m_thread_info ) {
228
+ .user_fn = start_routine ,
229
+ .user_arg = arg ,
230
+ };
231
+ info -> handle = CreateThread (NULL , 0 , run_thread , info , CREATE_SUSPENDED ,
232
+ & info -> id );
233
+ if (!info -> handle ) {
234
+ remove_thread_info (info );
235
+ res = EAGAIN ;
236
+ goto done ;
237
+ }
238
+ * thread = info -> id ;
239
+ ResumeThread (info -> handle );
240
+ done :
241
+ pthread_mutex_unlock (& pthread_table_lock );
242
+ return res ;
197
243
}
198
244
199
245
void pthread_set_name_np (pthread_t thread , const char * name )
@@ -206,7 +252,7 @@ void pthread_set_name_np(pthread_t thread, const char *name)
206
252
if (!pSetThreadDescription )
207
253
return ;
208
254
209
- HANDLE th = OpenThread (THREAD_SET_LIMITED_INFORMATION , FALSE, thread . id );
255
+ HANDLE th = OpenThread (THREAD_SET_LIMITED_INFORMATION , FALSE, thread );
210
256
if (!th )
211
257
return ;
212
258
wchar_t wname [80 ];
0 commit comments