Do not use the PEB lock as loader lock, use a separate critical
[wine] / scheduler / pthread.c
1 /*
2  * pthread emulation for re-entrant libcs
3  *
4  * We can't use pthreads directly, so why not let libcs
5  * that want pthreads use Wine's own threading instead...
6  *
7  * Copyright 1999 Ove Kåven
8  */
9
10 #include "config.h"
11 #define _GNU_SOURCE /* we may need to override some GNU extensions */
12
13 #include <assert.h>
14 #include <errno.h>
15 #include <stdlib.h>
16 #include <unistd.h>
17 #include <string.h>
18
19 #include "winbase.h"
20 #include "thread.h"
21 #include "ntddk.h"
22
23 static int init_done;
24
25 void PTHREAD_init_done(void)
26 {
27     init_done = 1;
28 }
29
30 /* Currently this probably works only for glibc2,
31  * which checks for the presence of double-underscore-prepended
32  * pthread primitives, and use them if available.
33  * If they are not available, the libc defaults to
34  * non-threadsafe operation (not good). */
35
36 #if defined(__GLIBC__)
37 #include <pthread.h>
38 #include <signal.h>
39
40 #ifdef NEED_UNDERSCORE_PREFIX
41 # define PREFIX "_"
42 #else
43 # define PREFIX
44 #endif
45
46 #define PSTR(str) PREFIX #str
47
48 /* adapt as necessary (a construct like this is used in glibc sources) */
49 #define strong_alias(orig, alias) \
50  asm(".globl " PSTR(alias) "\n" \
51      "\t.set " PSTR(alias) "," PSTR(orig))
52
53 /* strong_alias does not work on external symbols (.o format limitation?),
54  * so for those, we need to use the pogo stick */
55 #if defined(__i386__) && !defined(__PIC__)
56 /* FIXME: PIC */
57 #define jump_alias(orig, alias) \
58  asm(".globl " PSTR(alias) "\n" \
59      "\t.type " PSTR(alias) ",@function\n" \
60      PSTR(alias) ":\n" \
61      "\tjmp " PSTR(orig))
62 #endif
63
64 /* get necessary libc symbols */
65 #if (__GLIBC__ == 2) && (__GLIBC_MINOR__ >= 1) && defined(HAVE___LIBC_FORK)
66 #define LIBC_FORK __libc_fork
67 #define PTHREAD_FORK __fork
68 #define ALIAS_FORK
69 #else
70 #define LIBC_FORK __fork
71 #define PTHREAD_FORK fork
72 #endif
73 extern pid_t LIBC_FORK(void);
74
75 #define LIBC_SIGACTION __sigaction
76 extern int LIBC_SIGACTION(int signum, 
77                          const struct sigaction *act, 
78                          struct sigaction *oldact);
79
80 /* NOTE: This is a truly extremely incredibly ugly hack!
81  * But it does seem to work... */
82
83 /* assume that pthread_mutex_t has room for at least one pointer,
84  * and hope that the users of pthread_mutex_t considers it opaque
85  * (never checks what's in it) 
86  * also: assume that static initializer sets pointer to NULL
87  */
88 typedef struct {
89   CRITICAL_SECTION *critsect;
90 } *wine_mutex;
91
92 /* see wine_mutex above for comments */
93 typedef struct {
94   RTL_RWLOCK *lock;
95 } *wine_rwlock;
96
97 typedef struct _wine_cleanup {
98   void (*routine)(void *);
99   void *arg;
100 } *wine_cleanup;
101
102 typedef const void *key_data;
103
104 #define FIRST_KEY 0
105 #define MAX_KEYS 16 /* libc6 doesn't use that many, but... */
106
107 #define P_OUTPUT(stuff) write(2,stuff,strlen(stuff))
108
109 void __pthread_initialize(void)
110 {
111 }
112
113 int __pthread_once(pthread_once_t *once_control, void (*init_routine)(void))
114 {
115   static pthread_once_t the_once = PTHREAD_ONCE_INIT;
116   LONG once_now = *(LONG *)&the_once;
117
118   if (InterlockedCompareExchange((LONG*)once_control, once_now+1, once_now) == once_now)
119     (*init_routine)();
120   return 0;
121 }
122 strong_alias(__pthread_once, pthread_once);
123
124 void __pthread_kill_other_threads_np(void)
125 {
126     /* we don't need to do anything here */
127 }
128 strong_alias(__pthread_kill_other_threads_np, pthread_kill_other_threads_np);
129
130 /***** atfork *****/
131
132 #define MAX_ATFORK 8  /* libc doesn't need that many anyway */
133
134 static CRITICAL_SECTION atfork_section = CRITICAL_SECTION_INIT("atfork_section");
135 typedef void (*atfork_handler)();
136 static atfork_handler atfork_prepare[MAX_ATFORK];
137 static atfork_handler atfork_parent[MAX_ATFORK];
138 static atfork_handler atfork_child[MAX_ATFORK];
139 static int atfork_count;
140
141 int __pthread_atfork(void (*prepare)(void),
142                      void (*parent)(void),
143                      void (*child)(void))
144 {
145     if (init_done) EnterCriticalSection( &atfork_section );
146     assert( atfork_count < MAX_ATFORK );
147     atfork_prepare[atfork_count] = prepare;
148     atfork_parent[atfork_count] = parent;
149     atfork_child[atfork_count] = child;
150     atfork_count++;
151     if (init_done) LeaveCriticalSection( &atfork_section );
152     return 0;
153 }
154 strong_alias(__pthread_atfork, pthread_atfork);
155
156 pid_t PTHREAD_FORK(void)
157 {
158     pid_t pid;
159     int i;
160
161     EnterCriticalSection( &atfork_section );
162     /* prepare handlers are called in reverse insertion order */
163     for (i = atfork_count - 1; i >= 0; i--) if (atfork_prepare[i]) atfork_prepare[i]();
164     if (!(pid = LIBC_FORK()))
165     {
166         InitializeCriticalSection( &atfork_section );
167         for (i = 0; i < atfork_count; i++) if (atfork_child[i]) atfork_child[i]();
168     }
169     else
170     {
171         for (i = 0; i < atfork_count; i++) if (atfork_parent[i]) atfork_parent[i]();
172         LeaveCriticalSection( &atfork_section );
173     }
174     return pid;
175 }
176 #ifdef ALIAS_FORK
177 strong_alias(PTHREAD_FORK, fork);
178 #endif
179
180 /***** MUTEXES *****/
181
182 int __pthread_mutex_init(pthread_mutex_t *mutex,
183                         const pthread_mutexattr_t *mutexattr)
184 {
185   /* glibc has a tendency to initialize mutexes very often, even
186      in situations where they are not really used later on.
187
188      As for us, initializing a mutex is very expensive, we postpone
189      the real initialization until the time the mutex is first used. */
190
191   ((wine_mutex)mutex)->critsect = NULL;
192   return 0;
193 }
194 strong_alias(__pthread_mutex_init, pthread_mutex_init);
195
196 static void mutex_real_init( pthread_mutex_t *mutex )
197 {
198   CRITICAL_SECTION *critsect = HeapAlloc(GetProcessHeap(), 0, sizeof(CRITICAL_SECTION));
199   InitializeCriticalSection(critsect);
200
201   if (InterlockedCompareExchangePointer((void**)&(((wine_mutex)mutex)->critsect),critsect,NULL) != NULL) {
202     /* too late, some other thread already did it */
203     DeleteCriticalSection(critsect);
204     HeapFree(GetProcessHeap(), 0, critsect);
205   }
206 }
207
208 int __pthread_mutex_lock(pthread_mutex_t *mutex)
209 {
210   if (!init_done) return 0;
211   if (!((wine_mutex)mutex)->critsect) 
212     mutex_real_init( mutex );
213
214   EnterCriticalSection(((wine_mutex)mutex)->critsect);
215   return 0;
216 }
217 strong_alias(__pthread_mutex_lock, pthread_mutex_lock);
218
219 int __pthread_mutex_trylock(pthread_mutex_t *mutex)
220 {
221   if (!init_done) return 0;
222   if (!((wine_mutex)mutex)->critsect) 
223     mutex_real_init( mutex );
224
225   if (!TryEnterCriticalSection(((wine_mutex)mutex)->critsect)) {
226     errno = EBUSY;
227     return -1;
228   }
229   return 0;
230 }
231 strong_alias(__pthread_mutex_trylock, pthread_mutex_trylock);
232
233 int __pthread_mutex_unlock(pthread_mutex_t *mutex)
234 {
235   if (!((wine_mutex)mutex)->critsect) return 0;
236   LeaveCriticalSection(((wine_mutex)mutex)->critsect);
237   return 0;
238 }
239 strong_alias(__pthread_mutex_unlock, pthread_mutex_unlock);
240
241 int __pthread_mutex_destroy(pthread_mutex_t *mutex)
242 {
243   if (!((wine_mutex)mutex)->critsect) return 0;
244   if (((wine_mutex)mutex)->critsect->RecursionCount) {
245 #if 0 /* there seems to be a bug in libc6 that makes this a bad idea */
246     return EBUSY;
247 #else
248     while (((wine_mutex)mutex)->critsect->RecursionCount)
249       LeaveCriticalSection(((wine_mutex)mutex)->critsect);
250 #endif
251   }
252   DeleteCriticalSection(((wine_mutex)mutex)->critsect);
253   HeapFree(GetProcessHeap(), 0, ((wine_mutex)mutex)->critsect);
254   return 0;
255 }
256 strong_alias(__pthread_mutex_destroy, pthread_mutex_destroy);
257
258
259 /***** MUTEX ATTRIBUTES *****/
260 /* just dummies, since critical sections are always recursive */
261
262 int __pthread_mutexattr_init(pthread_mutexattr_t *attr)
263 {
264   return 0;
265 }
266 strong_alias(__pthread_mutexattr_init, pthread_mutexattr_init);
267
268 int __pthread_mutexattr_destroy(pthread_mutexattr_t *attr)
269 {
270   return 0;
271 }
272 strong_alias(__pthread_mutexattr_destroy, pthread_mutexattr_destroy);
273
274 int __pthread_mutexattr_setkind_np(pthread_mutexattr_t *attr, int kind)
275 {
276   return 0;
277 }
278 strong_alias(__pthread_mutexattr_setkind_np, pthread_mutexattr_setkind_np);
279
280 int __pthread_mutexattr_getkind_np(pthread_mutexattr_t *attr, int *kind)
281 {
282   *kind = PTHREAD_MUTEX_RECURSIVE_NP;
283   return 0;
284 }
285 strong_alias(__pthread_mutexattr_getkind_np, pthread_mutexattr_getkind_np);
286
287 int __pthread_mutexattr_settype(pthread_mutexattr_t *attr, int kind)
288 {
289   return 0;
290 }
291 strong_alias(__pthread_mutexattr_settype, pthread_mutexattr_settype);
292
293 int __pthread_mutexattr_gettype(pthread_mutexattr_t *attr, int *kind)
294 {
295   *kind = PTHREAD_MUTEX_RECURSIVE_NP;
296   return 0;
297 }
298 strong_alias(__pthread_mutexattr_gettype, pthread_mutexattr_gettype);
299
300
301 /***** THREAD-SPECIFIC VARIABLES (KEYS) *****/
302
303 int __pthread_key_create(pthread_key_t *key, void (*destr_function)(void *))
304 {
305   static LONG keycnt = FIRST_KEY;
306   *key = InterlockedExchangeAdd(&keycnt, 1);
307   return 0;
308 }
309 strong_alias(__pthread_key_create, pthread_key_create);
310
311 int __pthread_key_delete(pthread_key_t key)
312 {
313   return 0;
314 }
315 strong_alias(__pthread_key_delete, pthread_key_delete);
316
317 int __pthread_setspecific(pthread_key_t key, const void *pointer)
318 {
319   TEB *teb = NtCurrentTeb();
320   if (!teb->pthread_data) {
321     teb->pthread_data = calloc(MAX_KEYS,sizeof(key_data));
322   }
323   ((key_data*)(teb->pthread_data))[key] = pointer;
324   return 0;
325 }
326 strong_alias(__pthread_setspecific, pthread_setspecific);
327
328 void *__pthread_getspecific(pthread_key_t key)
329 {
330   TEB *teb = NtCurrentTeb();
331   if (!teb) return NULL;
332   if (!teb->pthread_data) return NULL;
333   return (void *)(((key_data*)(teb->pthread_data))[key]);
334 }
335 strong_alias(__pthread_getspecific, pthread_getspecific);
336
337
338 /***** "EXCEPTION" FRAMES *****/
339 /* not implemented right now */
340
341 void _pthread_cleanup_push(struct _pthread_cleanup_buffer *buffer, void (*routine)(void *), void *arg)
342 {
343   ((wine_cleanup)buffer)->routine = routine;
344   ((wine_cleanup)buffer)->arg = arg;
345 }
346
347 void _pthread_cleanup_pop(struct _pthread_cleanup_buffer *buffer, int execute)
348 {
349   if (execute) (*(((wine_cleanup)buffer)->routine))(((wine_cleanup)buffer)->arg);
350 }
351
352 void _pthread_cleanup_push_defer(struct _pthread_cleanup_buffer *buffer, void (*routine)(void *), void *arg)
353 {
354   _pthread_cleanup_push(buffer, routine, arg);
355 }
356
357 void _pthread_cleanup_pop_restore(struct _pthread_cleanup_buffer *buffer, int execute)
358 {
359   _pthread_cleanup_pop(buffer, execute);
360 }
361
362
363 /***** CONDITIONS *****/
364 /* not implemented right now */
365
366 int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *cond_attr)
367 {
368   P_OUTPUT("FIXME:pthread_cond_init\n");
369   return 0;
370 }
371
372 int pthread_cond_destroy(pthread_cond_t *cond)
373 {
374   P_OUTPUT("FIXME:pthread_cond_destroy\n");
375   return 0;
376 }
377
378 int pthread_cond_signal(pthread_cond_t *cond)
379 {
380   P_OUTPUT("FIXME:pthread_cond_signal\n");
381   return 0;
382 }
383
384 int pthread_cond_broadcast(pthread_cond_t *cond)
385 {
386   P_OUTPUT("FIXME:pthread_cond_broadcast\n");
387   return 0;
388 }
389
390 int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
391 {
392   P_OUTPUT("FIXME:pthread_cond_wait\n");
393   return 0;
394 }
395
396 int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, const struct timespec *abstime)
397 {
398   P_OUTPUT("FIXME:pthread_cond_timedwait\n");
399   return 0;
400 }
401
402 /**** CONDITION ATTRIBUTES *****/
403 /* not implemented right now */
404
405 int pthread_condattr_init(pthread_condattr_t *attr)
406 {
407   return 0;
408 }
409
410 int pthread_condattr_destroy(pthread_condattr_t *attr)
411 {
412   return 0;
413 }
414
415 #if (__GLIBC__ == 2) && (__GLIBC_MINOR__ >= 2)
416 /***** READ-WRITE LOCKS *****/
417
418 static void rwlock_real_init(pthread_rwlock_t *rwlock)
419 {
420   RTL_RWLOCK *lock = HeapAlloc(GetProcessHeap(), 0, sizeof(RTL_RWLOCK));
421   RtlInitializeResource(lock);
422
423   if (InterlockedCompareExchangePointer((void**)&(((wine_rwlock)rwlock)->lock),lock,NULL) != NULL) {
424     /* too late, some other thread already did it */
425     RtlDeleteResource(lock);
426     HeapFree(GetProcessHeap(), 0, lock);
427   }
428 }
429
430 int __pthread_rwlock_init(pthread_rwlock_t *rwlock, const pthread_rwlockattr_t *rwlock_attr)
431 {
432   ((wine_rwlock)rwlock)->lock = NULL;
433   return 0;
434 }
435 strong_alias(__pthread_rwlock_init, pthread_rwlock_init);
436
437 int __pthread_rwlock_destroy(pthread_rwlock_t *rwlock)
438 {
439   if (!((wine_rwlock)rwlock)->lock) return 0;
440   RtlDeleteResource(((wine_rwlock)rwlock)->lock);
441   HeapFree(GetProcessHeap(), 0, ((wine_rwlock)rwlock)->lock);
442   return 0;
443 }
444 strong_alias(__pthread_rwlock_destroy, pthread_rwlock_destroy);
445
446 int __pthread_rwlock_rdlock(pthread_rwlock_t *rwlock)
447 {
448   if (!init_done) return 0;
449   if (!((wine_rwlock)rwlock)->lock)
450     rwlock_real_init( rwlock );
451
452   while(TRUE)
453     if (RtlAcquireResourceShared(((wine_rwlock)rwlock)->lock, TRUE))
454       return 0;
455 }
456 strong_alias(__pthread_rwlock_rdlock, pthread_rwlock_rdlock);
457
458 int __pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock)
459 {
460   if (!init_done) return 0;
461   if (!((wine_rwlock)rwlock)->lock)
462     rwlock_real_init( rwlock );
463
464   if (!RtlAcquireResourceShared(((wine_rwlock)rwlock)->lock, FALSE)) {
465     errno = EBUSY;
466     return -1;
467   }
468   return 0;
469 }
470 strong_alias(__pthread_rwlock_tryrdlock, pthread_rwlock_tryrdlock);
471
472 int __pthread_rwlock_wrlock(pthread_rwlock_t *rwlock)
473 {
474   if (!init_done) return 0;
475   if (!((wine_rwlock)rwlock)->lock)
476     rwlock_real_init( rwlock );
477
478   while(TRUE)
479     if (RtlAcquireResourceExclusive(((wine_rwlock)rwlock)->lock, TRUE))
480       return 0;
481 }
482 strong_alias(__pthread_rwlock_wrlock, pthread_rwlock_wrlock);
483
484 int __pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock)
485 {
486   if (!init_done) return 0;
487   if (!((wine_rwlock)rwlock)->lock)
488     rwlock_real_init( rwlock );
489
490   if (!RtlAcquireResourceExclusive(((wine_rwlock)rwlock)->lock, FALSE)) {
491     errno = EBUSY;
492     return -1;
493   }
494   return 0;
495 }
496 strong_alias(__pthread_rwlock_trywrlock, pthread_rwlock_trywrlock);
497
498 int __pthread_rwlock_unlock(pthread_rwlock_t *rwlock)
499 {
500   if (!((wine_rwlock)rwlock)->lock) return 0;
501   RtlReleaseResource( ((wine_rwlock)rwlock)->lock );
502   return 0;
503 }
504 strong_alias(__pthread_rwlock_unlock, pthread_rwlock_unlock);
505
506 /**** READ-WRITE LOCK ATTRIBUTES *****/
507 /* not implemented right now */
508
509 int pthread_rwlockattr_init(pthread_rwlockattr_t *attr)
510 {
511   return 0;
512 }
513
514 int __pthread_rwlockattr_destroy(pthread_rwlockattr_t *attr)
515 {
516   return 0;
517 }
518 strong_alias(__pthread_rwlockattr_destroy, pthread_rwlockattr_destroy);
519
520 int pthread_rwlockattr_getkind_np(const pthread_rwlockattr_t *attr, int *pref)
521 {
522   *pref = 0;
523   return 0;
524 }
525
526 int pthread_rwlockattr_setkind_np(pthread_rwlockattr_t *attr, int pref)
527 {
528   return 0;
529 }
530 #endif /* glibc 2.2 */
531
532 /***** MISC *****/
533
534 pthread_t pthread_self(void)
535 {
536   return (pthread_t)GetCurrentThreadId();
537 }
538
539 int pthread_equal(pthread_t thread1, pthread_t thread2)
540 {
541   return (DWORD)thread1 == (DWORD)thread2;
542 }
543
544 void pthread_exit(void *retval)
545 {
546   /* FIXME: pthread cleanup */
547   ExitThread((DWORD)retval);
548 }
549
550 int pthread_setcanceltype(int type, int *oldtype)
551 {
552   if (oldtype) *oldtype = PTHREAD_CANCEL_ASYNCHRONOUS;
553   return 0;
554 }
555
556 /***** ANTI-OVERRIDES *****/
557 /* pthreads tries to override these, point them back to libc */
558
559 #ifdef jump_alias
560 jump_alias(LIBC_SIGACTION, sigaction);
561 #else
562 int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact)
563 {
564   return LIBC_SIGACTION(signum, act, oldact);
565 }
566 #endif
567
568 #endif /* __GLIBC__ */