winebuild: Implement register entry points for x86_64.
[wine] / dlls / ntdll / pthread.c
1 /*
2  * pthread emulation for re-entrant libcs
3  *
4  * Copyright 1999 Ove Kåven
5  * Copyright 2003 Alexandre Julliard
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  */
21
22 #include "config.h"
23 #include "wine/port.h"
24
25 #ifdef HAVE_PTHREAD_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 <stdarg.h>
32 #include <stdlib.h>
33 #include <setjmp.h>
34 #ifdef HAVE_UNISTD_H
35 # include <unistd.h>
36 #endif
37 #include <string.h>
38 #include <sys/types.h>
39 #ifdef HAVE_SYS_SOCKET_H
40 # include <sys/socket.h>
41 #endif
42 #ifdef HAVE_SYS_MMAN_H
43 #include <sys/mman.h>
44 #endif
45
46 #include "windef.h"
47 #include "winbase.h"
48 #include "winternl.h"
49 #include "ntdll_misc.h"
50 #include "wine/pthread.h"
51
52 #define P_OUTPUT(stuff) write(2,stuff,strlen(stuff))
53
54 /* NOTE: This is a truly extremely incredibly ugly hack!
55  * But it does seem to work... */
56
57 /* assume that pthread_mutex_t has room for at least one pointer,
58  * and hope that the users of pthread_mutex_t considers it opaque
59  * (never checks what's in it)
60  * also: assume that static initializer sets pointer to NULL
61  */
62 typedef struct
63 {
64 #ifdef __GLIBC__
65   int reserved;
66 #endif
67   CRITICAL_SECTION *critsect;
68 } *wine_mutex;
69
70 /* see wine_mutex above for comments */
71 typedef struct {
72   RTL_RWLOCK *lock;
73 } *wine_rwlock;
74
75 struct pthread_thread_init
76 {
77     void* (*start_routine)(void*);
78     void* arg;
79 };
80
81 static void wine_pthread_exit(void *retval, char *currentframe)
82 {
83     RtlFreeThreadActivationContextStack();
84     RtlExitUserThread( PtrToUlong(retval) );
85 }
86
87 static void CALLBACK pthread_thread_start(LPVOID data)
88 {
89   struct pthread_thread_init init = *(struct pthread_thread_init*)data;
90   RtlFreeHeap(GetProcessHeap(),0,data);
91   wine_pthread_exit( init.start_routine(init.arg), NULL );
92 }
93
94 static int wine_pthread_create(pthread_t* thread, const pthread_attr_t* attr, void*
95                                (*start_routine)(void *), void* arg)
96 {
97   HANDLE handle;
98   CLIENT_ID client_id;
99   struct pthread_thread_init* idata;
100
101   if (!(idata = RtlAllocateHeap(GetProcessHeap(), 0, sizeof(*idata)))) return ENOMEM;
102
103   idata->start_routine = start_routine;
104   idata->arg = arg;
105   if (!RtlCreateUserThread( NtCurrentProcess(), NULL, FALSE, NULL, 0, 0,
106                             pthread_thread_start, idata, &handle, &client_id ))
107   {
108     NtClose( handle );
109     *thread = (pthread_t)client_id.UniqueThread;
110   }
111   else
112   {
113     RtlFreeHeap( GetProcessHeap(), 0, idata );
114     return EAGAIN;
115   }
116
117   return 0;
118 }
119
120 static int wine_pthread_cancel(pthread_t thread)
121 {
122   CLIENT_ID cid;
123   NTSTATUS status;
124   HANDLE handle;
125
126   cid.UniqueProcess = 0;
127   cid.UniqueThread = (HANDLE)thread;
128   status = NtOpenThread( &handle, THREAD_TERMINATE, NULL, &cid );
129   if (!status)
130   {
131     status = NtTerminateThread( handle, 0 );
132     NtClose( handle );
133   }
134   if (status) return EINVAL;
135   return 0;
136 }
137
138 static int wine_pthread_join(pthread_t thread, void **value_ptr)
139 {
140   THREAD_BASIC_INFORMATION info;
141   CLIENT_ID cid;
142   NTSTATUS status;
143   HANDLE handle;
144
145   cid.UniqueProcess = 0;
146   cid.UniqueThread = (HANDLE)thread;
147   status = NtOpenThread( &handle, THREAD_QUERY_INFORMATION|SYNCHRONIZE, NULL, &cid );
148   if (!status)
149   {
150     NtWaitForMultipleObjects( 1, &handle, FALSE, FALSE, NULL );
151     status = NtQueryInformationThread( handle, ThreadBasicInformation, &info, sizeof(info), NULL );
152     NtClose( handle );
153     if (!status) *value_ptr = UlongToPtr(info.ExitStatus);
154   }
155   if (status) return EINVAL; /* FIXME: make this more correctly match windows errors */
156   return 0;
157 }
158
159 /*FIXME: not sure what to do with this one... */
160 static int wine_pthread_detach(pthread_t thread)
161 {
162   P_OUTPUT("FIXME:pthread_detach\n");
163   return 0;
164 }
165
166 /***** MUTEXES *****/
167
168 static int wine_pthread_mutex_init(pthread_mutex_t *mutex,
169                                    const pthread_mutexattr_t *mutexattr)
170 {
171   /* glibc has a tendency to initialize mutexes very often, even
172      in situations where they are not really used later on.
173
174      As for us, initializing a mutex is very expensive, we postpone
175      the real initialization until the time the mutex is first used. */
176
177   ((wine_mutex)mutex)->critsect = NULL;
178   return 0;
179 }
180
181 static void mutex_real_init( pthread_mutex_t *mutex )
182 {
183   CRITICAL_SECTION *critsect = RtlAllocateHeap(GetProcessHeap(), 0, sizeof(CRITICAL_SECTION));
184   RtlInitializeCriticalSection(critsect);
185
186   if (interlocked_cmpxchg_ptr((void**)&(((wine_mutex)mutex)->critsect),critsect,NULL) != NULL) {
187     /* too late, some other thread already did it */
188     RtlDeleteCriticalSection(critsect);
189     RtlFreeHeap(GetProcessHeap(), 0, critsect);
190   }
191 }
192
193 static int wine_pthread_mutex_lock(pthread_mutex_t *mutex)
194 {
195   if (!((wine_mutex)mutex)->critsect)
196     mutex_real_init( mutex );
197
198   RtlEnterCriticalSection(((wine_mutex)mutex)->critsect);
199   return 0;
200 }
201
202 static int wine_pthread_mutex_trylock(pthread_mutex_t *mutex)
203 {
204   if (!((wine_mutex)mutex)->critsect)
205     mutex_real_init( mutex );
206
207   if (!RtlTryEnterCriticalSection(((wine_mutex)mutex)->critsect)) return EBUSY;
208   return 0;
209 }
210
211 static int wine_pthread_mutex_unlock(pthread_mutex_t *mutex)
212 {
213     CRITICAL_SECTION *crit = ((wine_mutex)mutex)->critsect;
214
215     if (!crit) return 0;
216     if (crit->OwningThread != ULongToHandle(GetCurrentThreadId())) return EPERM;
217     RtlLeaveCriticalSection( crit );
218     return 0;
219 }
220
221 static int wine_pthread_mutex_destroy(pthread_mutex_t *mutex)
222 {
223   if (!((wine_mutex)mutex)->critsect) return 0;
224   if (((wine_mutex)mutex)->critsect->RecursionCount) {
225 #if 0 /* there seems to be a bug in libc6 that makes this a bad idea */
226     return EBUSY;
227 #else
228     while (((wine_mutex)mutex)->critsect->RecursionCount)
229       RtlLeaveCriticalSection(((wine_mutex)mutex)->critsect);
230 #endif
231   }
232   RtlDeleteCriticalSection(((wine_mutex)mutex)->critsect);
233   RtlFreeHeap(GetProcessHeap(), 0, ((wine_mutex)mutex)->critsect);
234   ((wine_mutex)mutex)->critsect = NULL;
235   return 0;
236 }
237
238 /***** READ-WRITE LOCKS *****/
239
240 static void rwlock_real_init(pthread_rwlock_t *rwlock)
241 {
242   RTL_RWLOCK *lock = RtlAllocateHeap(GetProcessHeap(), 0, sizeof(RTL_RWLOCK));
243   RtlInitializeResource(lock);
244
245   if (interlocked_cmpxchg_ptr((void**)&(((wine_rwlock)rwlock)->lock),lock,NULL) != NULL) {
246     /* too late, some other thread already did it */
247     RtlDeleteResource(lock);
248     RtlFreeHeap(GetProcessHeap(), 0, lock);
249   }
250 }
251
252 static int wine_pthread_rwlock_init(pthread_rwlock_t *rwlock, const pthread_rwlockattr_t *rwlock_attr)
253 {
254   ((wine_rwlock)rwlock)->lock = NULL;
255   return 0;
256 }
257
258 static int wine_pthread_rwlock_destroy(pthread_rwlock_t *rwlock)
259 {
260   if (!((wine_rwlock)rwlock)->lock) return 0;
261   RtlDeleteResource(((wine_rwlock)rwlock)->lock);
262   RtlFreeHeap(GetProcessHeap(), 0, ((wine_rwlock)rwlock)->lock);
263   return 0;
264 }
265
266 static int wine_pthread_rwlock_rdlock(pthread_rwlock_t *rwlock)
267 {
268   if (!((wine_rwlock)rwlock)->lock)
269     rwlock_real_init( rwlock );
270
271   while(TRUE)
272     if (RtlAcquireResourceShared(((wine_rwlock)rwlock)->lock, TRUE))
273       return 0;
274 }
275
276 static int wine_pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock)
277 {
278   if (!((wine_rwlock)rwlock)->lock)
279     rwlock_real_init( rwlock );
280
281   if (!RtlAcquireResourceShared(((wine_rwlock)rwlock)->lock, FALSE)) return EBUSY;
282   return 0;
283 }
284
285 static int wine_pthread_rwlock_wrlock(pthread_rwlock_t *rwlock)
286 {
287   if (!((wine_rwlock)rwlock)->lock)
288     rwlock_real_init( rwlock );
289
290   while(TRUE)
291     if (RtlAcquireResourceExclusive(((wine_rwlock)rwlock)->lock, TRUE))
292       return 0;
293 }
294
295 static int wine_pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock)
296 {
297   if (!((wine_rwlock)rwlock)->lock)
298     rwlock_real_init( rwlock );
299
300   if (!RtlAcquireResourceExclusive(((wine_rwlock)rwlock)->lock, FALSE)) return EBUSY;
301   return 0;
302 }
303
304 static int wine_pthread_rwlock_unlock(pthread_rwlock_t *rwlock)
305 {
306   if (!((wine_rwlock)rwlock)->lock) return 0;
307   RtlReleaseResource( ((wine_rwlock)rwlock)->lock );
308   return 0;
309 }
310
311 /***** CONDITIONS *****/
312
313 /* The condition code is basically cut-and-pasted from Douglas
314  * Schmidt's paper:
315  *   "Strategies for Implementing POSIX Condition Variables on Win32",
316  * at http://www.cs.wustl.edu/~schmidt/win32-cv-1.html and
317  * http://www.cs.wustl.edu/~schmidt/win32-cv-2.html.
318  * This paper formed the basis for the condition variable
319  * implementation used in the ACE library.
320  */
321
322 /* Possible problems with ACE:
323  * - unimplemented pthread_mutexattr_init
324  */
325 typedef struct {
326   /* Number of waiting threads. */
327   int waiters_count;
328
329   /* Serialize access to <waiters_count>. */
330   CRITICAL_SECTION waiters_count_lock;
331
332   /*
333    * Semaphore used to queue up threads waiting for the condition to
334    * become signaled.
335    */
336   HANDLE sema;
337
338   /*
339    * An auto-reset event used by the broadcast/signal thread to wait
340    * for all the waiting thread(s) to wake up and be released from the
341    * semaphore.
342    */
343   HANDLE waiters_done;
344
345   /*
346    * Keeps track of whether we were broadcasting or signaling.  This
347    * allows us to optimize the code if we're just signaling.
348    */
349   size_t was_broadcast;
350 } wine_cond_detail;
351
352 /* see wine_mutex above for comments */
353 typedef struct {
354   wine_cond_detail *cond;
355 } *wine_cond;
356
357 static void wine_cond_real_init(pthread_cond_t *cond)
358 {
359   wine_cond_detail *detail = RtlAllocateHeap(GetProcessHeap(), 0, sizeof(wine_cond_detail));
360   detail->waiters_count = 0;
361   detail->was_broadcast = 0;
362   NtCreateSemaphore( &detail->sema, SEMAPHORE_ALL_ACCESS, NULL, 0, 0x7fffffff );
363   NtCreateEvent( &detail->waiters_done, EVENT_ALL_ACCESS, NULL, FALSE, FALSE );
364   RtlInitializeCriticalSection (&detail->waiters_count_lock);
365
366   if (interlocked_cmpxchg_ptr((void**)&(((wine_cond)cond)->cond), detail, NULL) != NULL)
367   {
368     /* too late, some other thread already did it */
369     P_OUTPUT("FIXME:pthread_cond_init:expect troubles...\n");
370     NtClose(detail->sema);
371     RtlDeleteCriticalSection(&detail->waiters_count_lock);
372     NtClose(detail->waiters_done);
373     RtlFreeHeap(GetProcessHeap(), 0, detail);
374   }
375 }
376
377 static int wine_pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *cond_attr)
378 {
379   /* The same as for wine_pthread_mutex_init, we postpone initialization
380      until condition is really used.*/
381   ((wine_cond)cond)->cond = NULL;
382   return 0;
383 }
384
385 static int wine_pthread_cond_destroy(pthread_cond_t *cond)
386 {
387   wine_cond_detail *detail = ((wine_cond)cond)->cond;
388
389   if (!detail) return 0;
390   NtClose(detail->sema);
391   RtlDeleteCriticalSection(&detail->waiters_count_lock);
392   NtClose(detail->waiters_done);
393   RtlFreeHeap(GetProcessHeap(), 0, detail);
394   ((wine_cond)cond)->cond = NULL;
395   return 0;
396 }
397
398 static int wine_pthread_cond_signal(pthread_cond_t *cond)
399 {
400   int have_waiters;
401   wine_cond_detail *detail;
402
403   if ( !((wine_cond)cond)->cond ) wine_cond_real_init(cond);
404   detail = ((wine_cond)cond)->cond;
405
406   RtlEnterCriticalSection (&detail->waiters_count_lock);
407   have_waiters = detail->waiters_count > 0;
408   RtlLeaveCriticalSection (&detail->waiters_count_lock);
409
410   /* If there aren't any waiters, then this is a no-op. */
411   if (have_waiters)
412     NtReleaseSemaphore(detail->sema, 1, NULL);
413
414   return 0;
415 }
416
417 static int wine_pthread_cond_broadcast(pthread_cond_t *cond)
418 {
419   int have_waiters = 0;
420   wine_cond_detail *detail;
421
422   if ( !((wine_cond)cond)->cond ) wine_cond_real_init(cond);
423   detail = ((wine_cond)cond)->cond;
424
425   /*
426    * This is needed to ensure that <waiters_count> and <was_broadcast> are
427    * consistent relative to each other.
428    */
429   RtlEnterCriticalSection (&detail->waiters_count_lock);
430
431   if (detail->waiters_count > 0) {
432     /*
433      * We are broadcasting, even if there is just one waiter...
434      * Record that we are broadcasting, which helps optimize
435      * <pthread_cond_wait> for the non-broadcast case.
436      */
437     detail->was_broadcast = 1;
438     have_waiters = 1;
439   }
440
441   if (have_waiters) {
442     /* Wake up all the waiters atomically. */
443     NtReleaseSemaphore(detail->sema, detail->waiters_count, NULL);
444
445     RtlLeaveCriticalSection (&detail->waiters_count_lock);
446
447     /* Wait for all the awakened threads to acquire the counting semaphore. */
448     NtWaitForMultipleObjects( 1, &detail->waiters_done, FALSE, FALSE, NULL );
449
450     /*
451      * This assignment is okay, even without the <waiters_count_lock> held
452      * because no other waiter threads can wake up to access it.
453      */
454     detail->was_broadcast = 0;
455   }
456   else
457     RtlLeaveCriticalSection (&detail->waiters_count_lock);
458   return 0;
459 }
460
461 static int wine_pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
462 {
463   wine_cond_detail *detail;
464   int last_waiter;
465
466   if ( !((wine_cond)cond)->cond ) wine_cond_real_init(cond);
467   detail = ((wine_cond)cond)->cond;
468
469   /* Avoid race conditions. */
470   RtlEnterCriticalSection (&detail->waiters_count_lock);
471   detail->waiters_count++;
472   RtlLeaveCriticalSection (&detail->waiters_count_lock);
473
474   RtlLeaveCriticalSection ( ((wine_mutex)mutex)->critsect );
475   NtWaitForMultipleObjects( 1, &detail->sema, FALSE, FALSE, NULL );
476
477   /* Reacquire lock to avoid race conditions. */
478   RtlEnterCriticalSection (&detail->waiters_count_lock);
479
480   /* We're no longer waiting... */
481   detail->waiters_count--;
482
483   /* Check to see if we're the last waiter after <pthread_cond_broadcast>. */
484   last_waiter = detail->was_broadcast && detail->waiters_count == 0;
485
486   RtlLeaveCriticalSection (&detail->waiters_count_lock);
487
488   /*
489    * If we're the last waiter thread during this particular broadcast
490    * then let all the other threads proceed.
491    */
492   if (last_waiter) NtSetEvent( detail->waiters_done, NULL );
493   RtlEnterCriticalSection (((wine_mutex)mutex)->critsect);
494   return 0;
495 }
496
497 static int wine_pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex,
498                                        const struct timespec *abstime)
499 {
500   LARGE_INTEGER time;
501   int last_waiter;
502   wine_cond_detail *detail;
503
504   if ( !((wine_cond)cond)->cond ) wine_cond_real_init(cond);
505   detail = ((wine_cond)cond)->cond;
506
507   /* Avoid race conditions. */
508   RtlEnterCriticalSection (&detail->waiters_count_lock);
509   detail->waiters_count++;
510   RtlLeaveCriticalSection (&detail->waiters_count_lock);
511
512   RtlLeaveCriticalSection (((wine_mutex)mutex)->critsect);
513
514   time.QuadPart = (ULONGLONG)abstime->tv_sec * 10000000 + abstime->tv_nsec / 100;
515   time.QuadPart = -time.QuadPart;
516   NtWaitForMultipleObjects( 1, &detail->sema, FALSE, FALSE, &time );
517
518   /* Reacquire lock to avoid race conditions. */
519   RtlEnterCriticalSection (&detail->waiters_count_lock);
520
521   /* We're no longer waiting... */
522   detail->waiters_count--;
523
524   /* Check to see if we're the last waiter after <pthread_cond_broadcast>. */
525   last_waiter = detail->was_broadcast && detail->waiters_count == 0;
526
527   RtlLeaveCriticalSection (&detail->waiters_count_lock);
528
529   /*
530    * If we're the last waiter thread during this particular broadcast
531    * then let all the other threads proceed.
532    */
533   if (last_waiter) NtSetEvent( detail->waiters_done, NULL );
534   RtlEnterCriticalSection (((wine_mutex)mutex)->critsect);
535   return 0;
536 }
537
538 /***** MISC *****/
539
540 static pthread_t wine_pthread_self(void)
541 {
542   return (pthread_t)GetCurrentThreadId();
543 }
544
545 static int wine_pthread_equal(pthread_t thread1, pthread_t thread2)
546 {
547   return (DWORD)thread1 == (DWORD)thread2;
548 }
549
550 static void *wine_get_thread_data(void)
551 {
552     return ntdll_get_thread_data()->pthread_data;
553 }
554
555 static void wine_set_thread_data( void *data )
556 {
557     ntdll_get_thread_data()->pthread_data = data;
558 }
559
560 static const struct wine_pthread_callbacks callbacks =
561 {
562     wine_get_thread_data,           /* ptr_get_thread_data */
563     wine_set_thread_data,           /* ptr_set_thread_data */
564     wine_pthread_self,              /* ptr_pthread_self */
565     wine_pthread_equal,             /* ptr_pthread_equal */
566     wine_pthread_create,            /* ptr_pthread_create */
567     wine_pthread_cancel,            /* ptr_pthread_cancel */
568     wine_pthread_join,              /* ptr_pthread_join */
569     wine_pthread_detach,            /* ptr_pthread_detach */
570     wine_pthread_exit,              /* ptr_pthread_exit */
571     wine_pthread_mutex_init,        /* ptr_pthread_mutex_init */
572     wine_pthread_mutex_lock,        /* ptr_pthread_mutex_lock */
573     wine_pthread_mutex_trylock,     /* ptr_pthread_mutex_trylock */
574     wine_pthread_mutex_unlock,      /* ptr_pthread_mutex_unlock */
575     wine_pthread_mutex_destroy,     /* ptr_pthread_mutex_destroy */
576     wine_pthread_rwlock_init,       /* ptr_pthread_rwlock_init */
577     wine_pthread_rwlock_destroy,    /* ptr_pthread_rwlock_destroy */
578     wine_pthread_rwlock_rdlock,     /* ptr_pthread_rwlock_rdlock */
579     wine_pthread_rwlock_tryrdlock,  /* ptr_pthread_rwlock_tryrdlock */
580     wine_pthread_rwlock_wrlock,     /* ptr_pthread_rwlock_wrlock */
581     wine_pthread_rwlock_trywrlock,  /* ptr_pthread_rwlock_trywrlock */
582     wine_pthread_rwlock_unlock,     /* ptr_pthread_rwlock_unlock */
583     wine_pthread_cond_init,         /* ptr_pthread_cond_init */
584     wine_pthread_cond_destroy,      /* ptr_pthread_cond_destroy */
585     wine_pthread_cond_signal,       /* ptr_pthread_cond_signal */
586     wine_pthread_cond_broadcast,    /* ptr_pthread_cond_broadcast */
587     wine_pthread_cond_wait,         /* ptr_pthread_cond_wait */
588     wine_pthread_cond_timedwait     /* ptr_pthread_cond_timedwait */
589 };
590
591 static struct wine_pthread_functions pthread_functions;
592
593 void pthread_init(void)
594 {
595     wine_pthread_get_functions( &pthread_functions, sizeof(pthread_functions) );
596     pthread_functions.init_process( &callbacks, sizeof(callbacks) );
597 }
598
599 #endif /* HAVE_PTHREAD_H */