- Implementation of [Internet|Ftp]*W functions to extend (almost)
[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 #include "wine/port.h"
26
27 #define _GNU_SOURCE /* we may need to override some GNU extensions */
28
29 #include <assert.h>
30 #include <errno.h>
31 #include <stdlib.h>
32 #ifdef HAVE_UNISTD_H
33 # include <unistd.h>
34 #endif
35 #include <string.h>
36
37 #include "winbase.h"
38 #include "thread.h"
39 #include "winternl.h"
40
41 /* Currently this probably works only for glibc2,
42  * which checks for the presence of double-underscore-prepended
43  * pthread primitives, and use them if available.
44  * If they are not available, the libc defaults to
45  * non-threadsafe operation (not good). */
46
47 #if defined(__GLIBC__)
48 #include <pthread.h>
49 #include <signal.h>
50
51 #define PSTR(str) __ASM_NAME(#str)
52
53 /* adapt as necessary (a construct like this is used in glibc sources) */
54 #define strong_alias(orig, alias) \
55  asm(".globl " PSTR(alias) "\n" \
56      "\t.set " PSTR(alias) "," PSTR(orig))
57
58 static int init_done;
59
60 static pid_t (*libc_fork)(void);
61 static int (*libc_sigaction)(int signum, const struct sigaction *act, struct sigaction *oldact);
62
63 void PTHREAD_init_done(void)
64 {
65     init_done = 1;
66     if (!libc_fork) libc_fork = dlsym( RTLD_NEXT, "fork" );
67     if (!libc_sigaction) libc_sigaction = dlsym( RTLD_NEXT, "sigaction" );
68 }
69
70
71 /* NOTE: This is a truly extremely incredibly ugly hack!
72  * But it does seem to work... */
73
74 /* assume that pthread_mutex_t has room for at least one pointer,
75  * and hope that the users of pthread_mutex_t considers it opaque
76  * (never checks what's in it)
77  * also: assume that static initializer sets pointer to NULL
78  */
79 typedef struct {
80   CRITICAL_SECTION *critsect;
81 } *wine_mutex;
82
83 /* see wine_mutex above for comments */
84 typedef struct {
85   RTL_RWLOCK *lock;
86 } *wine_rwlock;
87
88 typedef struct _wine_cleanup {
89   void (*routine)(void *);
90   void *arg;
91 } *wine_cleanup;
92
93 typedef const void *key_data;
94
95 #define FIRST_KEY 0
96 #define MAX_KEYS 16 /* libc6 doesn't use that many, but... */
97
98 #define P_OUTPUT(stuff) write(2,stuff,strlen(stuff))
99
100 void __pthread_initialize(void)
101 {
102 }
103
104 struct pthread_thread_init {
105          void* (*start_routine)(void*);
106          void* arg;
107 };
108
109 static DWORD CALLBACK pthread_thread_start(LPVOID data)
110 {
111   struct pthread_thread_init init = *(struct pthread_thread_init*)data;
112   HeapFree(GetProcessHeap(),0,data);
113   return (DWORD)init.start_routine(init.arg);
114 }
115
116 int pthread_create(pthread_t* thread, const pthread_attr_t* attr, void*
117         (*start_routine)(void *), void* arg)
118 {
119   HANDLE hThread;
120   struct pthread_thread_init* idata = HeapAlloc(GetProcessHeap(), 0,
121                 sizeof(struct pthread_thread_init));
122
123   idata->start_routine = start_routine;
124   idata->arg = arg;
125   hThread = CreateThread(NULL, 0, pthread_thread_start, idata, 0, thread);
126
127   if(hThread)
128     CloseHandle(hThread);
129   else
130   {
131     HeapFree(GetProcessHeap(),0,idata); /* free idata struct on failure */
132     return EAGAIN;
133   }
134
135   return 0;
136 }
137
138 int pthread_cancel(pthread_t thread)
139 {
140   HANDLE hThread = OpenThread(THREAD_ALL_ACCESS, FALSE, thread);
141
142   if(!TerminateThread(hThread, 0))
143   {
144     CloseHandle(hThread);
145     return EINVAL;      /* return error */
146   }
147
148   CloseHandle(hThread);
149
150   return 0;             /* return success */
151 }
152
153 int pthread_join(pthread_t thread, void **value_ptr)
154 {
155   HANDLE hThread = OpenThread(THREAD_ALL_ACCESS, FALSE, thread);
156
157   WaitForSingleObject(hThread, INFINITE);
158   if(!GetExitCodeThread(hThread, (LPDWORD)value_ptr))
159   {
160     CloseHandle(hThread);
161     return EINVAL; /* FIXME: make this more correctly match */
162   }                /* windows errors */
163
164   CloseHandle(hThread);
165   return 0;
166 }
167
168 /*FIXME: not sure what to do with this one... */
169 int pthread_detach(pthread_t thread)
170 {
171   P_OUTPUT("FIXME:pthread_detach\n");
172   return 0;
173 }
174
175 /* FIXME: we have no equivalents in win32 for the policys */
176 /* so just keep this as a stub */
177 int pthread_attr_setschedpolicy(pthread_attr_t *attr, int policy)
178 {
179   P_OUTPUT("FIXME:pthread_attr_setschedpolicy\n");
180   return 0;
181 }
182
183 /* FIXME: no win32 equivalent for scope */
184 int pthread_attr_setscope(pthread_attr_t *attr, int scope)
185 {
186   P_OUTPUT("FIXME:pthread_attr_setscope\n");
187   return 0; /* return success */
188 }
189
190 /* FIXME: no win32 equivalent for schedule param */
191 int pthread_attr_setschedparam(pthread_attr_t *attr,
192     const struct sched_param *param)
193 {
194   P_OUTPUT("FIXME:pthread_attr_setschedparam\n");
195   return 0; /* return success */
196 }
197
198 int __pthread_once(pthread_once_t *once_control, void (*init_routine)(void))
199 {
200   static pthread_once_t the_once = PTHREAD_ONCE_INIT;
201   LONG once_now = *(LONG *)&the_once;
202
203   if (InterlockedCompareExchange((LONG*)once_control, once_now+1, once_now) == once_now)
204     (*init_routine)();
205   return 0;
206 }
207 strong_alias(__pthread_once, pthread_once);
208
209 void __pthread_kill_other_threads_np(void)
210 {
211     /* we don't need to do anything here */
212 }
213 strong_alias(__pthread_kill_other_threads_np, pthread_kill_other_threads_np);
214
215 /***** atfork *****/
216
217 #define MAX_ATFORK 8  /* libc doesn't need that many anyway */
218
219 static CRITICAL_SECTION atfork_section = CRITICAL_SECTION_INIT("atfork_section");
220 typedef void (*atfork_handler)();
221 static atfork_handler atfork_prepare[MAX_ATFORK];
222 static atfork_handler atfork_parent[MAX_ATFORK];
223 static atfork_handler atfork_child[MAX_ATFORK];
224 static int atfork_count;
225
226 int __pthread_atfork(void (*prepare)(void),
227                      void (*parent)(void),
228                      void (*child)(void))
229 {
230     if (init_done) EnterCriticalSection( &atfork_section );
231     assert( atfork_count < MAX_ATFORK );
232     atfork_prepare[atfork_count] = prepare;
233     atfork_parent[atfork_count] = parent;
234     atfork_child[atfork_count] = child;
235     atfork_count++;
236     if (init_done) LeaveCriticalSection( &atfork_section );
237     return 0;
238 }
239 strong_alias(__pthread_atfork, pthread_atfork);
240
241 pid_t __fork(void)
242 {
243     pid_t pid;
244     int i;
245
246     if (!libc_fork)
247     {
248         libc_fork = dlsym( RTLD_NEXT, "fork" );
249         assert( libc_fork );
250     }
251     EnterCriticalSection( &atfork_section );
252     /* prepare handlers are called in reverse insertion order */
253     for (i = atfork_count - 1; i >= 0; i--) if (atfork_prepare[i]) atfork_prepare[i]();
254     if (!(pid = libc_fork()))
255     {
256         InitializeCriticalSection( &atfork_section );
257         for (i = 0; i < atfork_count; i++) if (atfork_child[i]) atfork_child[i]();
258     }
259     else
260     {
261         for (i = 0; i < atfork_count; i++) if (atfork_parent[i]) atfork_parent[i]();
262         LeaveCriticalSection( &atfork_section );
263     }
264     return pid;
265 }
266 strong_alias(__fork, fork);
267
268 /***** MUTEXES *****/
269
270 int __pthread_mutex_init(pthread_mutex_t *mutex,
271                         const pthread_mutexattr_t *mutexattr)
272 {
273   /* glibc has a tendency to initialize mutexes very often, even
274      in situations where they are not really used later on.
275
276      As for us, initializing a mutex is very expensive, we postpone
277      the real initialization until the time the mutex is first used. */
278
279   ((wine_mutex)mutex)->critsect = NULL;
280   return 0;
281 }
282 strong_alias(__pthread_mutex_init, pthread_mutex_init);
283
284 static void mutex_real_init( pthread_mutex_t *mutex )
285 {
286   CRITICAL_SECTION *critsect = HeapAlloc(GetProcessHeap(), 0, sizeof(CRITICAL_SECTION));
287   InitializeCriticalSection(critsect);
288
289   if (InterlockedCompareExchangePointer((void**)&(((wine_mutex)mutex)->critsect),critsect,NULL) != NULL) {
290     /* too late, some other thread already did it */
291     DeleteCriticalSection(critsect);
292     HeapFree(GetProcessHeap(), 0, critsect);
293   }
294 }
295
296 int __pthread_mutex_lock(pthread_mutex_t *mutex)
297 {
298   if (!init_done) return 0;
299   if (!((wine_mutex)mutex)->critsect)
300     mutex_real_init( mutex );
301
302   EnterCriticalSection(((wine_mutex)mutex)->critsect);
303   return 0;
304 }
305 strong_alias(__pthread_mutex_lock, pthread_mutex_lock);
306
307 int __pthread_mutex_trylock(pthread_mutex_t *mutex)
308 {
309   if (!init_done) return 0;
310   if (!((wine_mutex)mutex)->critsect)
311     mutex_real_init( mutex );
312
313   if (!TryEnterCriticalSection(((wine_mutex)mutex)->critsect)) {
314     errno = EBUSY;
315     return -1;
316   }
317   return 0;
318 }
319 strong_alias(__pthread_mutex_trylock, pthread_mutex_trylock);
320
321 int __pthread_mutex_unlock(pthread_mutex_t *mutex)
322 {
323   if (!((wine_mutex)mutex)->critsect) return 0;
324   LeaveCriticalSection(((wine_mutex)mutex)->critsect);
325   return 0;
326 }
327 strong_alias(__pthread_mutex_unlock, pthread_mutex_unlock);
328
329 int __pthread_mutex_destroy(pthread_mutex_t *mutex)
330 {
331   if (!((wine_mutex)mutex)->critsect) return 0;
332   if (((wine_mutex)mutex)->critsect->RecursionCount) {
333 #if 0 /* there seems to be a bug in libc6 that makes this a bad idea */
334     return EBUSY;
335 #else
336     while (((wine_mutex)mutex)->critsect->RecursionCount)
337       LeaveCriticalSection(((wine_mutex)mutex)->critsect);
338 #endif
339   }
340   DeleteCriticalSection(((wine_mutex)mutex)->critsect);
341   HeapFree(GetProcessHeap(), 0, ((wine_mutex)mutex)->critsect);
342   return 0;
343 }
344 strong_alias(__pthread_mutex_destroy, pthread_mutex_destroy);
345
346
347 /***** MUTEX ATTRIBUTES *****/
348 /* just dummies, since critical sections are always recursive */
349
350 int __pthread_mutexattr_init(pthread_mutexattr_t *attr)
351 {
352   return 0;
353 }
354 strong_alias(__pthread_mutexattr_init, pthread_mutexattr_init);
355
356 int __pthread_mutexattr_destroy(pthread_mutexattr_t *attr)
357 {
358   return 0;
359 }
360 strong_alias(__pthread_mutexattr_destroy, pthread_mutexattr_destroy);
361
362 int __pthread_mutexattr_setkind_np(pthread_mutexattr_t *attr, int kind)
363 {
364   return 0;
365 }
366 strong_alias(__pthread_mutexattr_setkind_np, pthread_mutexattr_setkind_np);
367
368 int __pthread_mutexattr_getkind_np(pthread_mutexattr_t *attr, int *kind)
369 {
370   *kind = PTHREAD_MUTEX_RECURSIVE_NP;
371   return 0;
372 }
373 strong_alias(__pthread_mutexattr_getkind_np, pthread_mutexattr_getkind_np);
374
375 int __pthread_mutexattr_settype(pthread_mutexattr_t *attr, int kind)
376 {
377   return 0;
378 }
379 strong_alias(__pthread_mutexattr_settype, pthread_mutexattr_settype);
380
381 int __pthread_mutexattr_gettype(pthread_mutexattr_t *attr, int *kind)
382 {
383   *kind = PTHREAD_MUTEX_RECURSIVE_NP;
384   return 0;
385 }
386 strong_alias(__pthread_mutexattr_gettype, pthread_mutexattr_gettype);
387
388
389 /***** THREAD-SPECIFIC VARIABLES (KEYS) *****/
390
391 int __pthread_key_create(pthread_key_t *key, void (*destr_function)(void *))
392 {
393   static LONG keycnt = FIRST_KEY;
394   *key = InterlockedExchangeAdd(&keycnt, 1);
395   return 0;
396 }
397 strong_alias(__pthread_key_create, pthread_key_create);
398
399 int __pthread_key_delete(pthread_key_t key)
400 {
401   return 0;
402 }
403 strong_alias(__pthread_key_delete, pthread_key_delete);
404
405 int __pthread_setspecific(pthread_key_t key, const void *pointer)
406 {
407   TEB *teb = NtCurrentTeb();
408   if (!teb->pthread_data) {
409     teb->pthread_data = calloc(MAX_KEYS,sizeof(key_data));
410   }
411   ((key_data*)(teb->pthread_data))[key] = pointer;
412   return 0;
413 }
414 strong_alias(__pthread_setspecific, pthread_setspecific);
415
416 void *__pthread_getspecific(pthread_key_t key)
417 {
418   TEB *teb = NtCurrentTeb();
419   if (!teb) return NULL;
420   if (!teb->pthread_data) return NULL;
421   return (void *)(((key_data*)(teb->pthread_data))[key]);
422 }
423 strong_alias(__pthread_getspecific, pthread_getspecific);
424
425
426 /***** "EXCEPTION" FRAMES *****/
427 /* not implemented right now */
428
429 void _pthread_cleanup_push(struct _pthread_cleanup_buffer *buffer, void (*routine)(void *), void *arg)
430 {
431   ((wine_cleanup)buffer)->routine = routine;
432   ((wine_cleanup)buffer)->arg = arg;
433 }
434
435 void _pthread_cleanup_pop(struct _pthread_cleanup_buffer *buffer, int execute)
436 {
437   if (execute) (*(((wine_cleanup)buffer)->routine))(((wine_cleanup)buffer)->arg);
438 }
439
440 void _pthread_cleanup_push_defer(struct _pthread_cleanup_buffer *buffer, void (*routine)(void *), void *arg)
441 {
442   _pthread_cleanup_push(buffer, routine, arg);
443 }
444
445 void _pthread_cleanup_pop_restore(struct _pthread_cleanup_buffer *buffer, int execute)
446 {
447   _pthread_cleanup_pop(buffer, execute);
448 }
449
450
451 /***** CONDITIONS *****/
452 /* not implemented right now */
453
454 int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *cond_attr)
455 {
456   P_OUTPUT("FIXME:pthread_cond_init\n");
457   return 0;
458 }
459
460 int pthread_cond_destroy(pthread_cond_t *cond)
461 {
462   P_OUTPUT("FIXME:pthread_cond_destroy\n");
463   return 0;
464 }
465
466 int pthread_cond_signal(pthread_cond_t *cond)
467 {
468   P_OUTPUT("FIXME:pthread_cond_signal\n");
469   return 0;
470 }
471
472 int pthread_cond_broadcast(pthread_cond_t *cond)
473 {
474   P_OUTPUT("FIXME:pthread_cond_broadcast\n");
475   return 0;
476 }
477
478 int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
479 {
480   P_OUTPUT("FIXME:pthread_cond_wait\n");
481   return 0;
482 }
483
484 int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, const struct timespec *abstime)
485 {
486   P_OUTPUT("FIXME:pthread_cond_timedwait\n");
487   return 0;
488 }
489
490 /**** CONDITION ATTRIBUTES *****/
491 /* not implemented right now */
492
493 int pthread_condattr_init(pthread_condattr_t *attr)
494 {
495   return 0;
496 }
497
498 int pthread_condattr_destroy(pthread_condattr_t *attr)
499 {
500   return 0;
501 }
502
503 #if (__GLIBC__ == 2) && (__GLIBC_MINOR__ >= 2)
504 /***** READ-WRITE LOCKS *****/
505
506 static void rwlock_real_init(pthread_rwlock_t *rwlock)
507 {
508   RTL_RWLOCK *lock = HeapAlloc(GetProcessHeap(), 0, sizeof(RTL_RWLOCK));
509   RtlInitializeResource(lock);
510
511   if (InterlockedCompareExchangePointer((void**)&(((wine_rwlock)rwlock)->lock),lock,NULL) != NULL) {
512     /* too late, some other thread already did it */
513     RtlDeleteResource(lock);
514     HeapFree(GetProcessHeap(), 0, lock);
515   }
516 }
517
518 int __pthread_rwlock_init(pthread_rwlock_t *rwlock, const pthread_rwlockattr_t *rwlock_attr)
519 {
520   ((wine_rwlock)rwlock)->lock = NULL;
521   return 0;
522 }
523 strong_alias(__pthread_rwlock_init, pthread_rwlock_init);
524
525 int __pthread_rwlock_destroy(pthread_rwlock_t *rwlock)
526 {
527   if (!((wine_rwlock)rwlock)->lock) return 0;
528   RtlDeleteResource(((wine_rwlock)rwlock)->lock);
529   HeapFree(GetProcessHeap(), 0, ((wine_rwlock)rwlock)->lock);
530   return 0;
531 }
532 strong_alias(__pthread_rwlock_destroy, pthread_rwlock_destroy);
533
534 int __pthread_rwlock_rdlock(pthread_rwlock_t *rwlock)
535 {
536   if (!init_done) return 0;
537   if (!((wine_rwlock)rwlock)->lock)
538     rwlock_real_init( rwlock );
539
540   while(TRUE)
541     if (RtlAcquireResourceShared(((wine_rwlock)rwlock)->lock, TRUE))
542       return 0;
543 }
544 strong_alias(__pthread_rwlock_rdlock, pthread_rwlock_rdlock);
545
546 int __pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock)
547 {
548   if (!init_done) return 0;
549   if (!((wine_rwlock)rwlock)->lock)
550     rwlock_real_init( rwlock );
551
552   if (!RtlAcquireResourceShared(((wine_rwlock)rwlock)->lock, FALSE)) {
553     errno = EBUSY;
554     return -1;
555   }
556   return 0;
557 }
558 strong_alias(__pthread_rwlock_tryrdlock, pthread_rwlock_tryrdlock);
559
560 int __pthread_rwlock_wrlock(pthread_rwlock_t *rwlock)
561 {
562   if (!init_done) return 0;
563   if (!((wine_rwlock)rwlock)->lock)
564     rwlock_real_init( rwlock );
565
566   while(TRUE)
567     if (RtlAcquireResourceExclusive(((wine_rwlock)rwlock)->lock, TRUE))
568       return 0;
569 }
570 strong_alias(__pthread_rwlock_wrlock, pthread_rwlock_wrlock);
571
572 int __pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock)
573 {
574   if (!init_done) return 0;
575   if (!((wine_rwlock)rwlock)->lock)
576     rwlock_real_init( rwlock );
577
578   if (!RtlAcquireResourceExclusive(((wine_rwlock)rwlock)->lock, FALSE)) {
579     errno = EBUSY;
580     return -1;
581   }
582   return 0;
583 }
584 strong_alias(__pthread_rwlock_trywrlock, pthread_rwlock_trywrlock);
585
586 int __pthread_rwlock_unlock(pthread_rwlock_t *rwlock)
587 {
588   if (!((wine_rwlock)rwlock)->lock) return 0;
589   RtlReleaseResource( ((wine_rwlock)rwlock)->lock );
590   return 0;
591 }
592 strong_alias(__pthread_rwlock_unlock, pthread_rwlock_unlock);
593
594 /**** READ-WRITE LOCK ATTRIBUTES *****/
595 /* not implemented right now */
596
597 int pthread_rwlockattr_init(pthread_rwlockattr_t *attr)
598 {
599   return 0;
600 }
601
602 int __pthread_rwlockattr_destroy(pthread_rwlockattr_t *attr)
603 {
604   return 0;
605 }
606 strong_alias(__pthread_rwlockattr_destroy, pthread_rwlockattr_destroy);
607
608 int pthread_rwlockattr_getkind_np(const pthread_rwlockattr_t *attr, int *pref)
609 {
610   *pref = 0;
611   return 0;
612 }
613
614 int pthread_rwlockattr_setkind_np(pthread_rwlockattr_t *attr, int pref)
615 {
616   return 0;
617 }
618 #endif /* glibc 2.2 */
619
620 /***** MISC *****/
621
622 pthread_t pthread_self(void)
623 {
624   return (pthread_t)GetCurrentThreadId();
625 }
626
627 int pthread_equal(pthread_t thread1, pthread_t thread2)
628 {
629   return (DWORD)thread1 == (DWORD)thread2;
630 }
631
632 void pthread_exit(void *retval)
633 {
634   /* FIXME: pthread cleanup */
635   ExitThread((DWORD)retval);
636 }
637
638 int pthread_setcanceltype(int type, int *oldtype)
639 {
640   if (oldtype) *oldtype = PTHREAD_CANCEL_ASYNCHRONOUS;
641   return 0;
642 }
643
644 /***** ANTI-OVERRIDES *****/
645 /* pthreads tries to override these, point them back to libc */
646
647 int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact)
648 {
649     if (!libc_sigaction)
650     {
651         libc_sigaction = dlsym( RTLD_NEXT, "sigaction" );
652         assert( libc_sigaction );
653     }
654     return libc_sigaction(signum, act, oldact);
655 }
656
657 #else /* __GLIBC__ */
658
659 void PTHREAD_init_done(void)
660 {
661 }
662
663 #endif /* __GLIBC__ */