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