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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, 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
49 #include "kernel_private.h"
50 #include "wine/pthread.h"
52 #define P_OUTPUT(stuff) write(2,stuff,strlen(stuff))
54 /* NOTE: This is a truly extremely incredibly ugly hack!
55 * But it does seem to work... */
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
67 CRITICAL_SECTION
*critsect
;
70 /* see wine_mutex above for comments */
75 struct pthread_thread_init
77 void* (*start_routine
)(void*);
81 static DWORD CALLBACK
pthread_thread_start(LPVOID data
)
83 struct pthread_thread_init init
= *(struct pthread_thread_init
*)data
;
84 HeapFree(GetProcessHeap(),0,data
);
85 return (DWORD_PTR
)init
.start_routine(init
.arg
);
88 static int wine_pthread_create(pthread_t
* thread
, const pthread_attr_t
* attr
, void*
89 (*start_routine
)(void *), void* arg
)
92 struct pthread_thread_init
* idata
= HeapAlloc(GetProcessHeap(), 0, sizeof(struct pthread_thread_init
));
94 idata
->start_routine
= start_routine
;
96 hThread
= CreateThread( NULL
, 0, pthread_thread_start
, idata
, 0, (LPDWORD
)thread
);
102 HeapFree(GetProcessHeap(),0,idata
); /* free idata struct on failure */
109 static int wine_pthread_cancel(pthread_t thread
)
111 HANDLE hThread
= OpenThread(THREAD_ALL_ACCESS
, FALSE
, (DWORD
)thread
);
113 if(!TerminateThread(hThread
, 0))
115 CloseHandle(hThread
);
116 return EINVAL
; /* return error */
119 CloseHandle(hThread
);
121 return 0; /* return success */
124 static int wine_pthread_join(pthread_t thread
, void **value_ptr
)
126 HANDLE hThread
= OpenThread(THREAD_ALL_ACCESS
, FALSE
, (DWORD
)thread
);
128 WaitForSingleObject(hThread
, INFINITE
);
129 if(!GetExitCodeThread(hThread
, (LPDWORD
)value_ptr
))
131 CloseHandle(hThread
);
132 return EINVAL
; /* FIXME: make this more correctly match */
133 } /* windows errors */
135 CloseHandle(hThread
);
139 /*FIXME: not sure what to do with this one... */
140 static int wine_pthread_detach(pthread_t thread
)
142 P_OUTPUT("FIXME:pthread_detach\n");
146 /***** MUTEXES *****/
148 static int wine_pthread_mutex_init(pthread_mutex_t
*mutex
,
149 const pthread_mutexattr_t
*mutexattr
)
151 /* glibc has a tendency to initialize mutexes very often, even
152 in situations where they are not really used later on.
154 As for us, initializing a mutex is very expensive, we postpone
155 the real initialization until the time the mutex is first used. */
157 ((wine_mutex
)mutex
)->critsect
= NULL
;
161 static void mutex_real_init( pthread_mutex_t
*mutex
)
163 CRITICAL_SECTION
*critsect
= HeapAlloc(GetProcessHeap(), 0, sizeof(CRITICAL_SECTION
));
164 RtlInitializeCriticalSection(critsect
);
166 if (InterlockedCompareExchangePointer((void**)&(((wine_mutex
)mutex
)->critsect
),critsect
,NULL
) != NULL
) {
167 /* too late, some other thread already did it */
168 RtlDeleteCriticalSection(critsect
);
169 HeapFree(GetProcessHeap(), 0, critsect
);
173 static int wine_pthread_mutex_lock(pthread_mutex_t
*mutex
)
175 if (!((wine_mutex
)mutex
)->critsect
)
176 mutex_real_init( mutex
);
178 RtlEnterCriticalSection(((wine_mutex
)mutex
)->critsect
);
182 static int wine_pthread_mutex_trylock(pthread_mutex_t
*mutex
)
184 if (!((wine_mutex
)mutex
)->critsect
)
185 mutex_real_init( mutex
);
187 if (!RtlTryEnterCriticalSection(((wine_mutex
)mutex
)->critsect
)) return EBUSY
;
191 static int wine_pthread_mutex_unlock(pthread_mutex_t
*mutex
)
193 CRITICAL_SECTION
*crit
= ((wine_mutex
)mutex
)->critsect
;
196 if (crit
->OwningThread
!= ULongToHandle(GetCurrentThreadId())) return EPERM
;
197 RtlLeaveCriticalSection( crit
);
201 static int wine_pthread_mutex_destroy(pthread_mutex_t
*mutex
)
203 if (!((wine_mutex
)mutex
)->critsect
) return 0;
204 if (((wine_mutex
)mutex
)->critsect
->RecursionCount
) {
205 #if 0 /* there seems to be a bug in libc6 that makes this a bad idea */
208 while (((wine_mutex
)mutex
)->critsect
->RecursionCount
)
209 RtlLeaveCriticalSection(((wine_mutex
)mutex
)->critsect
);
212 RtlDeleteCriticalSection(((wine_mutex
)mutex
)->critsect
);
213 HeapFree(GetProcessHeap(), 0, ((wine_mutex
)mutex
)->critsect
);
214 ((wine_mutex
)mutex
)->critsect
= NULL
;
218 /***** READ-WRITE LOCKS *****/
220 static void rwlock_real_init(pthread_rwlock_t
*rwlock
)
222 RTL_RWLOCK
*lock
= HeapAlloc(GetProcessHeap(), 0, sizeof(RTL_RWLOCK
));
223 RtlInitializeResource(lock
);
225 if (InterlockedCompareExchangePointer((void**)&(((wine_rwlock
)rwlock
)->lock
),lock
,NULL
) != NULL
) {
226 /* too late, some other thread already did it */
227 RtlDeleteResource(lock
);
228 HeapFree(GetProcessHeap(), 0, lock
);
232 static int wine_pthread_rwlock_init(pthread_rwlock_t
*rwlock
, const pthread_rwlockattr_t
*rwlock_attr
)
234 ((wine_rwlock
)rwlock
)->lock
= NULL
;
238 static int wine_pthread_rwlock_destroy(pthread_rwlock_t
*rwlock
)
240 if (!((wine_rwlock
)rwlock
)->lock
) return 0;
241 RtlDeleteResource(((wine_rwlock
)rwlock
)->lock
);
242 HeapFree(GetProcessHeap(), 0, ((wine_rwlock
)rwlock
)->lock
);
246 static int wine_pthread_rwlock_rdlock(pthread_rwlock_t
*rwlock
)
248 if (!((wine_rwlock
)rwlock
)->lock
)
249 rwlock_real_init( rwlock
);
252 if (RtlAcquireResourceShared(((wine_rwlock
)rwlock
)->lock
, TRUE
))
256 static int wine_pthread_rwlock_tryrdlock(pthread_rwlock_t
*rwlock
)
258 if (!((wine_rwlock
)rwlock
)->lock
)
259 rwlock_real_init( rwlock
);
261 if (!RtlAcquireResourceShared(((wine_rwlock
)rwlock
)->lock
, FALSE
)) return EBUSY
;
265 static int wine_pthread_rwlock_wrlock(pthread_rwlock_t
*rwlock
)
267 if (!((wine_rwlock
)rwlock
)->lock
)
268 rwlock_real_init( rwlock
);
271 if (RtlAcquireResourceExclusive(((wine_rwlock
)rwlock
)->lock
, TRUE
))
275 static int wine_pthread_rwlock_trywrlock(pthread_rwlock_t
*rwlock
)
277 if (!((wine_rwlock
)rwlock
)->lock
)
278 rwlock_real_init( rwlock
);
280 if (!RtlAcquireResourceExclusive(((wine_rwlock
)rwlock
)->lock
, FALSE
)) return EBUSY
;
284 static int wine_pthread_rwlock_unlock(pthread_rwlock_t
*rwlock
)
286 if (!((wine_rwlock
)rwlock
)->lock
) return 0;
287 RtlReleaseResource( ((wine_rwlock
)rwlock
)->lock
);
291 /***** CONDITIONS *****/
293 /* The condition code is basically cut-and-pasted from Douglas
295 * "Strategies for Implementing POSIX Condition Variables on Win32",
296 * at http://www.cs.wustl.edu/~schmidt/win32-cv-1.html and
297 * http://www.cs.wustl.edu/~schmidt/win32-cv-2.html.
298 * This paper formed the basis for the condition variable
299 * implementation used in the ACE library.
302 /* Possible problems with ACE:
303 * - unimplemented pthread_mutexattr_init
306 /* Number of waiting threads. */
309 /* Serialize access to <waiters_count>. */
310 CRITICAL_SECTION waiters_count_lock
;
313 * Semaphore used to queue up threads waiting for the condition to
319 * An auto-reset event used by the broadcast/signal thread to wait
320 * for all the waiting thread(s) to wake up and be released from the
326 * Keeps track of whether we were broadcasting or signaling. This
327 * allows us to optimize the code if we're just signaling.
329 size_t was_broadcast
;
332 /* see wine_mutex above for comments */
334 wine_cond_detail
*cond
;
337 static void wine_cond_real_init(pthread_cond_t
*cond
)
339 wine_cond_detail
*detail
= HeapAlloc(GetProcessHeap(), 0, sizeof(wine_cond_detail
));
340 detail
->waiters_count
= 0;
341 detail
->was_broadcast
= 0;
342 detail
->sema
= CreateSemaphoreW( NULL
, 0, 0x7fffffff, NULL
);
343 detail
->waiters_done
= CreateEventW( NULL
, FALSE
, FALSE
, NULL
);
344 RtlInitializeCriticalSection (&detail
->waiters_count_lock
);
346 if (InterlockedCompareExchangePointer((void**)&(((wine_cond
)cond
)->cond
), detail
, NULL
) != NULL
)
348 /* too late, some other thread already did it */
349 P_OUTPUT("FIXME:pthread_cond_init:expect troubles...\n");
350 CloseHandle(detail
->sema
);
351 RtlDeleteCriticalSection(&detail
->waiters_count_lock
);
352 CloseHandle(detail
->waiters_done
);
353 HeapFree(GetProcessHeap(), 0, detail
);
357 static int wine_pthread_cond_init(pthread_cond_t
*cond
, const pthread_condattr_t
*cond_attr
)
359 /* The same as for wine_pthread_mutex_init, we postpone initialization
360 until condition is really used.*/
361 ((wine_cond
)cond
)->cond
= NULL
;
365 static int wine_pthread_cond_destroy(pthread_cond_t
*cond
)
367 wine_cond_detail
*detail
= ((wine_cond
)cond
)->cond
;
369 if (!detail
) return 0;
370 CloseHandle(detail
->sema
);
371 RtlDeleteCriticalSection(&detail
->waiters_count_lock
);
372 CloseHandle(detail
->waiters_done
);
373 HeapFree(GetProcessHeap(), 0, detail
);
374 ((wine_cond
)cond
)->cond
= NULL
;
378 static int wine_pthread_cond_signal(pthread_cond_t
*cond
)
381 wine_cond_detail
*detail
;
383 if ( !((wine_cond
)cond
)->cond
) wine_cond_real_init(cond
);
384 detail
= ((wine_cond
)cond
)->cond
;
386 RtlEnterCriticalSection (&detail
->waiters_count_lock
);
387 have_waiters
= detail
->waiters_count
> 0;
388 RtlLeaveCriticalSection (&detail
->waiters_count_lock
);
390 /* If there aren't any waiters, then this is a no-op. */
392 ReleaseSemaphore(detail
->sema
, 1, NULL
);
397 static int wine_pthread_cond_broadcast(pthread_cond_t
*cond
)
399 int have_waiters
= 0;
400 wine_cond_detail
*detail
;
402 if ( !((wine_cond
)cond
)->cond
) wine_cond_real_init(cond
);
403 detail
= ((wine_cond
)cond
)->cond
;
406 * This is needed to ensure that <waiters_count> and <was_broadcast> are
407 * consistent relative to each other.
409 RtlEnterCriticalSection (&detail
->waiters_count_lock
);
411 if (detail
->waiters_count
> 0) {
413 * We are broadcasting, even if there is just one waiter...
414 * Record that we are broadcasting, which helps optimize
415 * <pthread_cond_wait> for the non-broadcast case.
417 detail
->was_broadcast
= 1;
422 /* Wake up all the waiters atomically. */
423 ReleaseSemaphore(detail
->sema
, detail
->waiters_count
, NULL
);
425 RtlLeaveCriticalSection (&detail
->waiters_count_lock
);
427 /* Wait for all the awakened threads to acquire the counting semaphore. */
428 WaitForSingleObject (detail
->waiters_done
, INFINITE
);
431 * This assignment is okay, even without the <waiters_count_lock> held
432 * because no other waiter threads can wake up to access it.
434 detail
->was_broadcast
= 0;
437 RtlLeaveCriticalSection (&detail
->waiters_count_lock
);
441 static int wine_pthread_cond_wait(pthread_cond_t
*cond
, pthread_mutex_t
*mutex
)
443 wine_cond_detail
*detail
;
446 if ( !((wine_cond
)cond
)->cond
) wine_cond_real_init(cond
);
447 detail
= ((wine_cond
)cond
)->cond
;
449 /* Avoid race conditions. */
450 RtlEnterCriticalSection (&detail
->waiters_count_lock
);
451 detail
->waiters_count
++;
452 RtlLeaveCriticalSection (&detail
->waiters_count_lock
);
454 RtlLeaveCriticalSection ( ((wine_mutex
)mutex
)->critsect
);
455 WaitForSingleObject(detail
->sema
, INFINITE
);
457 /* Reacquire lock to avoid race conditions. */
458 RtlEnterCriticalSection (&detail
->waiters_count_lock
);
460 /* We're no longer waiting... */
461 detail
->waiters_count
--;
463 /* Check to see if we're the last waiter after <pthread_cond_broadcast>. */
464 last_waiter
= detail
->was_broadcast
&& detail
->waiters_count
== 0;
466 RtlLeaveCriticalSection (&detail
->waiters_count_lock
);
469 * If we're the last waiter thread during this particular broadcast
470 * then let all the other threads proceed.
472 if (last_waiter
) SetEvent(detail
->waiters_done
);
473 RtlEnterCriticalSection (((wine_mutex
)mutex
)->critsect
);
477 static int wine_pthread_cond_timedwait(pthread_cond_t
*cond
, pthread_mutex_t
*mutex
,
478 const struct timespec
*abstime
)
480 DWORD ms
= abstime
->tv_sec
* 1000 + abstime
->tv_nsec
/ 1000000;
482 wine_cond_detail
*detail
;
484 if ( !((wine_cond
)cond
)->cond
) wine_cond_real_init(cond
);
485 detail
= ((wine_cond
)cond
)->cond
;
487 /* Avoid race conditions. */
488 RtlEnterCriticalSection (&detail
->waiters_count_lock
);
489 detail
->waiters_count
++;
490 RtlLeaveCriticalSection (&detail
->waiters_count_lock
);
492 RtlLeaveCriticalSection (((wine_mutex
)mutex
)->critsect
);
493 WaitForSingleObject (detail
->sema
, ms
);
495 /* Reacquire lock to avoid race conditions. */
496 RtlEnterCriticalSection (&detail
->waiters_count_lock
);
498 /* We're no longer waiting... */
499 detail
->waiters_count
--;
501 /* Check to see if we're the last waiter after <pthread_cond_broadcast>. */
502 last_waiter
= detail
->was_broadcast
&& detail
->waiters_count
== 0;
504 RtlLeaveCriticalSection (&detail
->waiters_count_lock
);
507 * If we're the last waiter thread during this particular broadcast
508 * then let all the other threads proceed.
510 if (last_waiter
) SetEvent (detail
->waiters_done
);
511 RtlEnterCriticalSection (((wine_mutex
)mutex
)->critsect
);
517 static pthread_t
wine_pthread_self(void)
519 return (pthread_t
)GetCurrentThreadId();
522 static int wine_pthread_equal(pthread_t thread1
, pthread_t thread2
)
524 return (DWORD
)thread1
== (DWORD
)thread2
;
527 static void wine_pthread_exit(void *retval
, char *currentframe
)
529 ExitThread((DWORD_PTR
)retval
);
532 static void *wine_get_thread_data(void)
534 return kernel_get_thread_data()->pthread_data
;
537 static void wine_set_thread_data( void *data
)
539 kernel_get_thread_data()->pthread_data
= data
;
542 static const struct wine_pthread_callbacks callbacks
=
544 wine_get_thread_data
, /* ptr_get_thread_data */
545 wine_set_thread_data
, /* ptr_set_thread_data */
546 wine_pthread_self
, /* ptr_pthread_self */
547 wine_pthread_equal
, /* ptr_pthread_equal */
548 wine_pthread_create
, /* ptr_pthread_create */
549 wine_pthread_cancel
, /* ptr_pthread_cancel */
550 wine_pthread_join
, /* ptr_pthread_join */
551 wine_pthread_detach
, /* ptr_pthread_detach */
552 wine_pthread_exit
, /* ptr_pthread_exit */
553 wine_pthread_mutex_init
, /* ptr_pthread_mutex_init */
554 wine_pthread_mutex_lock
, /* ptr_pthread_mutex_lock */
555 wine_pthread_mutex_trylock
, /* ptr_pthread_mutex_trylock */
556 wine_pthread_mutex_unlock
, /* ptr_pthread_mutex_unlock */
557 wine_pthread_mutex_destroy
, /* ptr_pthread_mutex_destroy */
558 wine_pthread_rwlock_init
, /* ptr_pthread_rwlock_init */
559 wine_pthread_rwlock_destroy
, /* ptr_pthread_rwlock_destroy */
560 wine_pthread_rwlock_rdlock
, /* ptr_pthread_rwlock_rdlock */
561 wine_pthread_rwlock_tryrdlock
, /* ptr_pthread_rwlock_tryrdlock */
562 wine_pthread_rwlock_wrlock
, /* ptr_pthread_rwlock_wrlock */
563 wine_pthread_rwlock_trywrlock
, /* ptr_pthread_rwlock_trywrlock */
564 wine_pthread_rwlock_unlock
, /* ptr_pthread_rwlock_unlock */
565 wine_pthread_cond_init
, /* ptr_pthread_cond_init */
566 wine_pthread_cond_destroy
, /* ptr_pthread_cond_destroy */
567 wine_pthread_cond_signal
, /* ptr_pthread_cond_signal */
568 wine_pthread_cond_broadcast
, /* ptr_pthread_cond_broadcast */
569 wine_pthread_cond_wait
, /* ptr_pthread_cond_wait */
570 wine_pthread_cond_timedwait
/* ptr_pthread_cond_timedwait */
573 static struct wine_pthread_functions pthread_functions
;
575 void PTHREAD_Init(void)
577 wine_pthread_get_functions( &pthread_functions
, sizeof(pthread_functions
) );
578 pthread_functions
.init_process( &callbacks
, sizeof(callbacks
) );
581 #endif /* HAVE_PTHREAD_H */