2 * pthread emulation for re-entrant libcs
4 * Copyright 1999 Ove Kåven
5 * Copyright 2003 Alexandre Julliard
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.
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.
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 #include "wine/port.h"
27 #define _GNU_SOURCE /* we may need to override some GNU extensions */
38 #include <sys/types.h>
39 #ifdef HAVE_SYS_SOCKET_H
40 # include <sys/socket.h>
42 #ifdef HAVE_SYS_MMAN_H
50 #include "kernel_private.h"
51 #include "wine/pthread.h"
53 #define P_OUTPUT(stuff) write(2,stuff,strlen(stuff))
55 /* NOTE: This is a truly extremely incredibly ugly hack!
56 * But it does seem to work... */
58 /* assume that pthread_mutex_t has room for at least one pointer,
59 * and hope that the users of pthread_mutex_t considers it opaque
60 * (never checks what's in it)
61 * also: assume that static initializer sets pointer to NULL
68 CRITICAL_SECTION *critsect;
71 /* see wine_mutex above for comments */
76 struct pthread_thread_init
78 void* (*start_routine)(void*);
82 static DWORD CALLBACK pthread_thread_start(LPVOID data)
84 struct pthread_thread_init init = *(struct pthread_thread_init*)data;
85 HeapFree(GetProcessHeap(),0,data);
86 return (DWORD)init.start_routine(init.arg);
89 static int wine_pthread_create(pthread_t* thread, const pthread_attr_t* attr, void*
90 (*start_routine)(void *), void* arg)
93 struct pthread_thread_init* idata = HeapAlloc(GetProcessHeap(), 0, sizeof(struct pthread_thread_init));
95 idata->start_routine = start_routine;
97 hThread = CreateThread( NULL, 0, pthread_thread_start, idata, 0, (LPDWORD)thread);
100 CloseHandle(hThread);
103 HeapFree(GetProcessHeap(),0,idata); /* free idata struct on failure */
110 static int wine_pthread_cancel(pthread_t thread)
112 HANDLE hThread = OpenThread(THREAD_ALL_ACCESS, FALSE, (DWORD)thread);
114 if(!TerminateThread(hThread, 0))
116 CloseHandle(hThread);
117 return EINVAL; /* return error */
120 CloseHandle(hThread);
122 return 0; /* return success */
125 static int wine_pthread_join(pthread_t thread, void **value_ptr)
127 HANDLE hThread = OpenThread(THREAD_ALL_ACCESS, FALSE, (DWORD)thread);
129 WaitForSingleObject(hThread, INFINITE);
130 if(!GetExitCodeThread(hThread, (LPDWORD)value_ptr))
132 CloseHandle(hThread);
133 return EINVAL; /* FIXME: make this more correctly match */
134 } /* windows errors */
136 CloseHandle(hThread);
140 /*FIXME: not sure what to do with this one... */
141 static int wine_pthread_detach(pthread_t thread)
143 P_OUTPUT("FIXME:pthread_detach\n");
147 /***** MUTEXES *****/
149 static int wine_pthread_mutex_init(pthread_mutex_t *mutex,
150 const pthread_mutexattr_t *mutexattr)
152 /* glibc has a tendency to initialize mutexes very often, even
153 in situations where they are not really used later on.
155 As for us, initializing a mutex is very expensive, we postpone
156 the real initialization until the time the mutex is first used. */
158 ((wine_mutex)mutex)->critsect = NULL;
162 static void mutex_real_init( pthread_mutex_t *mutex )
164 CRITICAL_SECTION *critsect = HeapAlloc(GetProcessHeap(), 0, sizeof(CRITICAL_SECTION));
165 RtlInitializeCriticalSection(critsect);
167 if (InterlockedCompareExchangePointer((void**)&(((wine_mutex)mutex)->critsect),critsect,NULL) != NULL) {
168 /* too late, some other thread already did it */
169 RtlDeleteCriticalSection(critsect);
170 HeapFree(GetProcessHeap(), 0, critsect);
174 static int wine_pthread_mutex_lock(pthread_mutex_t *mutex)
176 if (!((wine_mutex)mutex)->critsect)
177 mutex_real_init( mutex );
179 RtlEnterCriticalSection(((wine_mutex)mutex)->critsect);
183 static int wine_pthread_mutex_trylock(pthread_mutex_t *mutex)
185 if (!((wine_mutex)mutex)->critsect)
186 mutex_real_init( mutex );
188 if (!RtlTryEnterCriticalSection(((wine_mutex)mutex)->critsect)) return EBUSY;
192 static int wine_pthread_mutex_unlock(pthread_mutex_t *mutex)
194 CRITICAL_SECTION *crit = ((wine_mutex)mutex)->critsect;
197 if (crit->OwningThread != (HANDLE)GetCurrentThreadId()) return EPERM;
198 RtlLeaveCriticalSection( crit );
202 static int wine_pthread_mutex_destroy(pthread_mutex_t *mutex)
204 if (!((wine_mutex)mutex)->critsect) return 0;
205 if (((wine_mutex)mutex)->critsect->RecursionCount) {
206 #if 0 /* there seems to be a bug in libc6 that makes this a bad idea */
209 while (((wine_mutex)mutex)->critsect->RecursionCount)
210 RtlLeaveCriticalSection(((wine_mutex)mutex)->critsect);
213 RtlDeleteCriticalSection(((wine_mutex)mutex)->critsect);
214 HeapFree(GetProcessHeap(), 0, ((wine_mutex)mutex)->critsect);
215 ((wine_mutex)mutex)->critsect = NULL;
219 /***** READ-WRITE LOCKS *****/
221 static void rwlock_real_init(pthread_rwlock_t *rwlock)
223 RTL_RWLOCK *lock = HeapAlloc(GetProcessHeap(), 0, sizeof(RTL_RWLOCK));
224 RtlInitializeResource(lock);
226 if (InterlockedCompareExchangePointer((void**)&(((wine_rwlock)rwlock)->lock),lock,NULL) != NULL) {
227 /* too late, some other thread already did it */
228 RtlDeleteResource(lock);
229 HeapFree(GetProcessHeap(), 0, lock);
233 static int wine_pthread_rwlock_init(pthread_rwlock_t *rwlock, const pthread_rwlockattr_t *rwlock_attr)
235 ((wine_rwlock)rwlock)->lock = NULL;
239 static int wine_pthread_rwlock_destroy(pthread_rwlock_t *rwlock)
241 if (!((wine_rwlock)rwlock)->lock) return 0;
242 RtlDeleteResource(((wine_rwlock)rwlock)->lock);
243 HeapFree(GetProcessHeap(), 0, ((wine_rwlock)rwlock)->lock);
247 static int wine_pthread_rwlock_rdlock(pthread_rwlock_t *rwlock)
249 if (!((wine_rwlock)rwlock)->lock)
250 rwlock_real_init( rwlock );
253 if (RtlAcquireResourceShared(((wine_rwlock)rwlock)->lock, TRUE))
257 static int wine_pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock)
259 if (!((wine_rwlock)rwlock)->lock)
260 rwlock_real_init( rwlock );
262 if (!RtlAcquireResourceShared(((wine_rwlock)rwlock)->lock, FALSE)) return EBUSY;
266 static int wine_pthread_rwlock_wrlock(pthread_rwlock_t *rwlock)
268 if (!((wine_rwlock)rwlock)->lock)
269 rwlock_real_init( rwlock );
272 if (RtlAcquireResourceExclusive(((wine_rwlock)rwlock)->lock, TRUE))
276 static int wine_pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock)
278 if (!((wine_rwlock)rwlock)->lock)
279 rwlock_real_init( rwlock );
281 if (!RtlAcquireResourceExclusive(((wine_rwlock)rwlock)->lock, FALSE)) return EBUSY;
285 static int wine_pthread_rwlock_unlock(pthread_rwlock_t *rwlock)
287 if (!((wine_rwlock)rwlock)->lock) return 0;
288 RtlReleaseResource( ((wine_rwlock)rwlock)->lock );
292 /***** CONDITIONS *****/
294 /* The condition code is basically cut-and-pasted from Douglas
296 * "Strategies for Implementing POSIX Condition Variables on Win32",
297 * at http://www.cs.wustl.edu/~schmidt/win32-cv-1.html and
298 * http://www.cs.wustl.edu/~schmidt/win32-cv-2.html.
299 * This paper formed the basis for the condition variable
300 * impementation used in the ACE library.
303 /* Possible problems with ACE:
304 * - unimplemented pthread_mutexattr_init
307 /* Number of waiting threads. */
310 /* Serialize access to <waiters_count>. */
311 CRITICAL_SECTION waiters_count_lock;
314 * Semaphore used to queue up threads waiting for the condition to
320 * An auto-reset event used by the broadcast/signal thread to wait
321 * for all the waiting thread(s) to wake up and be released from the
327 * Keeps track of whether we were broadcasting or signaling. This
328 * allows us to optimize the code if we're just signaling.
330 size_t was_broadcast;
333 /* see wine_mutex above for comments */
335 wine_cond_detail *cond;
338 static void wine_cond_real_init(pthread_cond_t *cond)
340 wine_cond_detail *detail = HeapAlloc(GetProcessHeap(), 0, sizeof(wine_cond_detail));
341 detail->waiters_count = 0;
342 detail->was_broadcast = 0;
343 detail->sema = CreateSemaphoreW( NULL, 0, 0x7fffffff, NULL );
344 detail->waiters_done = CreateEventW( NULL, FALSE, FALSE, NULL );
345 RtlInitializeCriticalSection (&detail->waiters_count_lock);
347 if (InterlockedCompareExchangePointer((void**)&(((wine_cond)cond)->cond), detail, NULL) != NULL)
349 /* too late, some other thread already did it */
350 P_OUTPUT("FIXME:pthread_cond_init:expect troubles...\n");
351 CloseHandle(detail->sema);
352 RtlDeleteCriticalSection(&detail->waiters_count_lock);
353 CloseHandle(detail->waiters_done);
354 HeapFree(GetProcessHeap(), 0, detail);
358 int wine_pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *cond_attr)
360 /* The same as for wine_pthread_mutex_init, we postpone initialization
361 until condition is really used.*/
362 ((wine_cond)cond)->cond = NULL;
366 int wine_pthread_cond_destroy(pthread_cond_t *cond)
368 wine_cond_detail *detail = ((wine_cond)cond)->cond;
370 if (!detail) return 0;
371 CloseHandle(detail->sema);
372 RtlDeleteCriticalSection(&detail->waiters_count_lock);
373 CloseHandle(detail->waiters_done);
374 HeapFree(GetProcessHeap(), 0, detail);
375 ((wine_cond)cond)->cond = NULL;
379 int wine_pthread_cond_signal(pthread_cond_t *cond)
382 wine_cond_detail *detail;
384 if ( !((wine_cond)cond)->cond ) wine_cond_real_init(cond);
385 detail = ((wine_cond)cond)->cond;
387 RtlEnterCriticalSection (&detail->waiters_count_lock);
388 have_waiters = detail->waiters_count > 0;
389 RtlLeaveCriticalSection (&detail->waiters_count_lock);
391 /* If there aren't any waiters, then this is a no-op. */
393 ReleaseSemaphore(detail->sema, 1, NULL);
398 int wine_pthread_cond_broadcast(pthread_cond_t *cond)
400 int have_waiters = 0;
401 wine_cond_detail *detail;
403 if ( !((wine_cond)cond)->cond ) wine_cond_real_init(cond);
404 detail = ((wine_cond)cond)->cond;
407 * This is needed to ensure that <waiters_count> and <was_broadcast> are
408 * consistent relative to each other.
410 RtlEnterCriticalSection (&detail->waiters_count_lock);
412 if (detail->waiters_count > 0) {
414 * We are broadcasting, even if there is just one waiter...
415 * Record that we are broadcasting, which helps optimize
416 * <pthread_cond_wait> for the non-broadcast case.
418 detail->was_broadcast = 1;
423 /* Wake up all the waiters atomically. */
424 ReleaseSemaphore(detail->sema, detail->waiters_count, NULL);
426 RtlLeaveCriticalSection (&detail->waiters_count_lock);
428 /* Wait for all the awakened threads to acquire the counting semaphore. */
429 WaitForSingleObject (detail->waiters_done, INFINITE);
432 * This assignment is okay, even without the <waiters_count_lock> held
433 * because no other waiter threads can wake up to access it.
435 detail->was_broadcast = 0;
438 RtlLeaveCriticalSection (&detail->waiters_count_lock);
442 int wine_pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
444 wine_cond_detail *detail;
447 if ( !((wine_cond)cond)->cond ) wine_cond_real_init(cond);
448 detail = ((wine_cond)cond)->cond;
450 /* Avoid race conditions. */
451 RtlEnterCriticalSection (&detail->waiters_count_lock);
452 detail->waiters_count++;
453 RtlLeaveCriticalSection (&detail->waiters_count_lock);
455 RtlLeaveCriticalSection ( ((wine_mutex)mutex)->critsect );
456 WaitForSingleObject(detail->sema, INFINITE);
458 /* Reacquire lock to avoid race conditions. */
459 RtlEnterCriticalSection (&detail->waiters_count_lock);
461 /* We're no longer waiting... */
462 detail->waiters_count--;
464 /* Check to see if we're the last waiter after <pthread_cond_broadcast>. */
465 last_waiter = detail->was_broadcast && detail->waiters_count == 0;
467 RtlLeaveCriticalSection (&detail->waiters_count_lock);
470 * If we're the last waiter thread during this particular broadcast
471 * then let all the other threads proceed.
473 if (last_waiter) SetEvent(detail->waiters_done);
474 RtlEnterCriticalSection (((wine_mutex)mutex)->critsect);
478 int wine_pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex,
479 const struct timespec *abstime)
481 DWORD ms = abstime->tv_sec * 1000 + abstime->tv_nsec / 1000000;
483 wine_cond_detail *detail;
485 if ( !((wine_cond)cond)->cond ) wine_cond_real_init(cond);
486 detail = ((wine_cond)cond)->cond;
488 /* Avoid race conditions. */
489 RtlEnterCriticalSection (&detail->waiters_count_lock);
490 detail->waiters_count++;
491 RtlLeaveCriticalSection (&detail->waiters_count_lock);
493 RtlLeaveCriticalSection (((wine_mutex)mutex)->critsect);
494 WaitForSingleObject (detail->sema, ms);
496 /* Reacquire lock to avoid race conditions. */
497 RtlEnterCriticalSection (&detail->waiters_count_lock);
499 /* We're no longer waiting... */
500 detail->waiters_count--;
502 /* Check to see if we're the last waiter after <pthread_cond_broadcast>. */
503 last_waiter = detail->was_broadcast && detail->waiters_count == 0;
505 RtlLeaveCriticalSection (&detail->waiters_count_lock);
508 * If we're the last waiter thread during this particular broadcast
509 * then let all the other threads proceed.
511 if (last_waiter) SetEvent (detail->waiters_done);
512 RtlEnterCriticalSection (((wine_mutex)mutex)->critsect);
518 static pthread_t wine_pthread_self(void)
520 return (pthread_t)GetCurrentThreadId();
523 static int wine_pthread_equal(pthread_t thread1, pthread_t thread2)
525 return (DWORD)thread1 == (DWORD)thread2;
528 static void wine_pthread_exit(void *retval, char *currentframe)
530 ExitThread((DWORD)retval);
533 static void *wine_get_thread_data(void)
535 return kernel_get_thread_data()->pthread_data;
538 static void wine_set_thread_data( void *data )
540 kernel_get_thread_data()->pthread_data = data;
543 static const struct wine_pthread_functions functions =
545 sizeof(functions), /* size */
546 wine_get_thread_data, /* ptr_get_thread_data */
547 wine_set_thread_data, /* ptr_set_thread_data */
548 wine_pthread_self, /* ptr_pthread_self */
549 wine_pthread_equal, /* ptr_pthread_equal */
550 wine_pthread_create, /* ptr_pthread_create */
551 wine_pthread_cancel, /* ptr_pthread_cancel */
552 wine_pthread_join, /* ptr_pthread_join */
553 wine_pthread_detach, /* ptr_pthread_detach */
554 wine_pthread_exit, /* ptr_pthread_exit */
555 wine_pthread_mutex_init, /* ptr_pthread_mutex_init */
556 wine_pthread_mutex_lock, /* ptr_pthread_mutex_lock */
557 wine_pthread_mutex_trylock, /* ptr_pthread_mutex_trylock */
558 wine_pthread_mutex_unlock, /* ptr_pthread_mutex_unlock */
559 wine_pthread_mutex_destroy, /* ptr_pthread_mutex_destroy */
560 wine_pthread_rwlock_init, /* ptr_pthread_rwlock_init */
561 wine_pthread_rwlock_destroy, /* ptr_pthread_rwlock_destroy */
562 wine_pthread_rwlock_rdlock, /* ptr_pthread_rwlock_rdlock */
563 wine_pthread_rwlock_tryrdlock, /* ptr_pthread_rwlock_tryrdlock */
564 wine_pthread_rwlock_wrlock, /* ptr_pthread_rwlock_wrlock */
565 wine_pthread_rwlock_trywrlock, /* ptr_pthread_rwlock_trywrlock */
566 wine_pthread_rwlock_unlock, /* ptr_pthread_rwlock_unlock */
567 wine_pthread_cond_init, /* ptr_pthread_cond_init */
568 wine_pthread_cond_destroy, /* ptr_pthread_cond_destroy */
569 wine_pthread_cond_signal, /* ptr_pthread_cond_signal */
570 wine_pthread_cond_broadcast, /* ptr_pthread_cond_broadcast */
571 wine_pthread_cond_wait, /* ptr_pthread_cond_wait */
572 wine_pthread_cond_timedwait /* ptr_pthread_cond_timedwait */
575 void PTHREAD_Init(void)
577 wine_pthread_init_process( &functions );
580 #endif /* HAVE_PTHREAD_H */