Add support for display of dibs on MSB XServers.
[wine/wine-kai.git] / dlls / kernel / pthread.c
blob076925b42ec9e89d8cc672fbff50b251ced5c646
1 /*
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
22 #include "config.h"
23 #include "wine/port.h"
25 #ifdef HAVE_PTHREAD_H
27 #define _GNU_SOURCE /* we may need to override some GNU extensions */
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
46 #include "windef.h"
47 #include "winbase.h"
48 #include "thread.h"
49 #include "winternl.h"
50 #include "wine/pthread.h"
52 #define P_OUTPUT(stuff) write(2,stuff,strlen(stuff))
54 static const struct wine_pthread_functions functions;
56 DECL_GLOBAL_CONSTRUCTOR(pthread_init) { wine_pthread_init_process( &functions ); }
58 /* NOTE: This is a truly extremely incredibly ugly hack!
59 * But it does seem to work... */
61 /* assume that pthread_mutex_t has room for at least one pointer,
62 * and hope that the users of pthread_mutex_t considers it opaque
63 * (never checks what's in it)
64 * also: assume that static initializer sets pointer to NULL
66 typedef struct
68 #ifdef __GLIBC__
69 int reserved;
70 #endif
71 CRITICAL_SECTION *critsect;
72 } *wine_mutex;
74 /* see wine_mutex above for comments */
75 typedef struct {
76 RTL_RWLOCK *lock;
77 } *wine_rwlock;
79 struct pthread_thread_init
81 void* (*start_routine)(void*);
82 void* arg;
85 static DWORD CALLBACK pthread_thread_start(LPVOID data)
87 struct pthread_thread_init init = *(struct pthread_thread_init*)data;
88 HeapFree(GetProcessHeap(),0,data);
89 return (DWORD)init.start_routine(init.arg);
92 static int wine_pthread_create(pthread_t* thread, const pthread_attr_t* attr, void*
93 (*start_routine)(void *), void* arg)
95 HANDLE hThread;
96 struct pthread_thread_init* idata = HeapAlloc(GetProcessHeap(), 0, sizeof(struct pthread_thread_init));
98 idata->start_routine = start_routine;
99 idata->arg = arg;
100 hThread = CreateThread( NULL, 0, pthread_thread_start, idata, 0, (LPDWORD)thread);
102 if(hThread)
103 CloseHandle(hThread);
104 else
106 HeapFree(GetProcessHeap(),0,idata); /* free idata struct on failure */
107 return EAGAIN;
110 return 0;
113 static int wine_pthread_cancel(pthread_t thread)
115 HANDLE hThread = OpenThread(THREAD_ALL_ACCESS, FALSE, (DWORD)thread);
117 if(!TerminateThread(hThread, 0))
119 CloseHandle(hThread);
120 return EINVAL; /* return error */
123 CloseHandle(hThread);
125 return 0; /* return success */
128 static int wine_pthread_join(pthread_t thread, void **value_ptr)
130 HANDLE hThread = OpenThread(THREAD_ALL_ACCESS, FALSE, (DWORD)thread);
132 WaitForSingleObject(hThread, INFINITE);
133 if(!GetExitCodeThread(hThread, (LPDWORD)value_ptr))
135 CloseHandle(hThread);
136 return EINVAL; /* FIXME: make this more correctly match */
137 } /* windows errors */
139 CloseHandle(hThread);
140 return 0;
143 /*FIXME: not sure what to do with this one... */
144 static int wine_pthread_detach(pthread_t thread)
146 P_OUTPUT("FIXME:pthread_detach\n");
147 return 0;
150 /***** MUTEXES *****/
152 static int wine_pthread_mutex_init(pthread_mutex_t *mutex,
153 const pthread_mutexattr_t *mutexattr)
155 /* glibc has a tendency to initialize mutexes very often, even
156 in situations where they are not really used later on.
158 As for us, initializing a mutex is very expensive, we postpone
159 the real initialization until the time the mutex is first used. */
161 ((wine_mutex)mutex)->critsect = NULL;
162 return 0;
165 static void mutex_real_init( pthread_mutex_t *mutex )
167 CRITICAL_SECTION *critsect = HeapAlloc(GetProcessHeap(), 0, sizeof(CRITICAL_SECTION));
168 RtlInitializeCriticalSection(critsect);
170 if (InterlockedCompareExchangePointer((void**)&(((wine_mutex)mutex)->critsect),critsect,NULL) != NULL) {
171 /* too late, some other thread already did it */
172 RtlDeleteCriticalSection(critsect);
173 HeapFree(GetProcessHeap(), 0, critsect);
177 static int wine_pthread_mutex_lock(pthread_mutex_t *mutex)
179 if (!((wine_mutex)mutex)->critsect)
180 mutex_real_init( mutex );
182 RtlEnterCriticalSection(((wine_mutex)mutex)->critsect);
183 return 0;
186 static int wine_pthread_mutex_trylock(pthread_mutex_t *mutex)
188 if (!((wine_mutex)mutex)->critsect)
189 mutex_real_init( mutex );
191 if (!RtlTryEnterCriticalSection(((wine_mutex)mutex)->critsect)) {
192 errno = EBUSY;
193 return -1;
195 return 0;
198 static int wine_pthread_mutex_unlock(pthread_mutex_t *mutex)
200 if (!((wine_mutex)mutex)->critsect) return 0;
201 RtlLeaveCriticalSection(((wine_mutex)mutex)->critsect);
202 return 0;
205 static int wine_pthread_mutex_destroy(pthread_mutex_t *mutex)
207 if (!((wine_mutex)mutex)->critsect) return 0;
208 if (((wine_mutex)mutex)->critsect->RecursionCount) {
209 #if 0 /* there seems to be a bug in libc6 that makes this a bad idea */
210 return EBUSY;
211 #else
212 while (((wine_mutex)mutex)->critsect->RecursionCount)
213 RtlLeaveCriticalSection(((wine_mutex)mutex)->critsect);
214 #endif
216 RtlDeleteCriticalSection(((wine_mutex)mutex)->critsect);
217 HeapFree(GetProcessHeap(), 0, ((wine_mutex)mutex)->critsect);
218 ((wine_mutex)mutex)->critsect = NULL;
219 return 0;
222 /***** READ-WRITE LOCKS *****/
224 static void rwlock_real_init(pthread_rwlock_t *rwlock)
226 RTL_RWLOCK *lock = HeapAlloc(GetProcessHeap(), 0, sizeof(RTL_RWLOCK));
227 RtlInitializeResource(lock);
229 if (InterlockedCompareExchangePointer((void**)&(((wine_rwlock)rwlock)->lock),lock,NULL) != NULL) {
230 /* too late, some other thread already did it */
231 RtlDeleteResource(lock);
232 HeapFree(GetProcessHeap(), 0, lock);
236 static int wine_pthread_rwlock_init(pthread_rwlock_t *rwlock, const pthread_rwlockattr_t *rwlock_attr)
238 ((wine_rwlock)rwlock)->lock = NULL;
239 return 0;
242 static int wine_pthread_rwlock_destroy(pthread_rwlock_t *rwlock)
244 if (!((wine_rwlock)rwlock)->lock) return 0;
245 RtlDeleteResource(((wine_rwlock)rwlock)->lock);
246 HeapFree(GetProcessHeap(), 0, ((wine_rwlock)rwlock)->lock);
247 return 0;
250 static int wine_pthread_rwlock_rdlock(pthread_rwlock_t *rwlock)
252 if (!((wine_rwlock)rwlock)->lock)
253 rwlock_real_init( rwlock );
255 while(TRUE)
256 if (RtlAcquireResourceShared(((wine_rwlock)rwlock)->lock, TRUE))
257 return 0;
260 static int wine_pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock)
262 if (!((wine_rwlock)rwlock)->lock)
263 rwlock_real_init( rwlock );
265 if (!RtlAcquireResourceShared(((wine_rwlock)rwlock)->lock, FALSE)) {
266 errno = EBUSY;
267 return -1;
269 return 0;
272 static int wine_pthread_rwlock_wrlock(pthread_rwlock_t *rwlock)
274 if (!((wine_rwlock)rwlock)->lock)
275 rwlock_real_init( rwlock );
277 while(TRUE)
278 if (RtlAcquireResourceExclusive(((wine_rwlock)rwlock)->lock, TRUE))
279 return 0;
282 static int wine_pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock)
284 if (!((wine_rwlock)rwlock)->lock)
285 rwlock_real_init( rwlock );
287 if (!RtlAcquireResourceExclusive(((wine_rwlock)rwlock)->lock, FALSE)) {
288 errno = EBUSY;
289 return -1;
291 return 0;
294 static int wine_pthread_rwlock_unlock(pthread_rwlock_t *rwlock)
296 if (!((wine_rwlock)rwlock)->lock) return 0;
297 RtlReleaseResource( ((wine_rwlock)rwlock)->lock );
298 return 0;
301 /***** CONDITIONS *****/
303 /* The condition code is basically cut-and-pasted from Douglas
304 * Schmidt's paper:
305 * "Strategies for Implementing POSIX Condition Variables on Win32",
306 * at http://www.cs.wustl.edu/~schmidt/win32-cv-1.html and
307 * http://www.cs.wustl.edu/~schmidt/win32-cv-2.html.
308 * This paper formed the basis for the condition variable
309 * impementation used in the ACE library.
312 /* Possible problems with ACE:
313 * - unimplemented pthread_mutexattr_init
315 typedef struct {
316 /* Number of waiting threads. */
317 int waiters_count;
319 /* Serialize access to <waiters_count>. */
320 CRITICAL_SECTION waiters_count_lock;
323 * Semaphore used to queue up threads waiting for the condition to
324 * become signaled.
326 HANDLE sema;
329 * An auto-reset event used by the broadcast/signal thread to wait
330 * for all the waiting thread(s) to wake up and be released from the
331 * semaphore.
333 HANDLE waiters_done;
336 * Keeps track of whether we were broadcasting or signaling. This
337 * allows us to optimize the code if we're just signaling.
339 size_t was_broadcast;
340 } wine_cond_detail;
342 /* see wine_mutex above for comments */
343 typedef struct {
344 wine_cond_detail *cond;
345 } *wine_cond;
347 static void wine_cond_real_init(pthread_cond_t *cond)
349 wine_cond_detail *detail = HeapAlloc(GetProcessHeap(), 0, sizeof(wine_cond_detail));
350 detail->waiters_count = 0;
351 detail->was_broadcast = 0;
352 detail->sema = CreateSemaphoreW( NULL, 0, 0x7fffffff, NULL );
353 detail->waiters_done = CreateEventW( NULL, FALSE, FALSE, NULL );
354 RtlInitializeCriticalSection (&detail->waiters_count_lock);
356 if (InterlockedCompareExchangePointer((void**)&(((wine_cond)cond)->cond), detail, NULL) != NULL)
358 /* too late, some other thread already did it */
359 P_OUTPUT("FIXME:pthread_cond_init:expect troubles...\n");
360 CloseHandle(detail->sema);
361 RtlDeleteCriticalSection(&detail->waiters_count_lock);
362 CloseHandle(detail->waiters_done);
363 HeapFree(GetProcessHeap(), 0, detail);
367 int wine_pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *cond_attr)
369 /* The same as for wine_pthread_mutex_init, we postpone initialization
370 until condition is really used.*/
371 ((wine_cond)cond)->cond = NULL;
372 return 0;
375 int wine_pthread_cond_destroy(pthread_cond_t *cond)
377 wine_cond_detail *detail = ((wine_cond)cond)->cond;
379 if (!detail) return 0;
380 CloseHandle(detail->sema);
381 RtlDeleteCriticalSection(&detail->waiters_count_lock);
382 CloseHandle(detail->waiters_done);
383 HeapFree(GetProcessHeap(), 0, detail);
384 ((wine_cond)cond)->cond = NULL;
385 return 0;
388 int wine_pthread_cond_signal(pthread_cond_t *cond)
390 int have_waiters;
391 wine_cond_detail *detail;
393 if ( !((wine_cond)cond)->cond ) wine_cond_real_init(cond);
394 detail = ((wine_cond)cond)->cond;
396 RtlEnterCriticalSection (&detail->waiters_count_lock);
397 have_waiters = detail->waiters_count > 0;
398 RtlLeaveCriticalSection (&detail->waiters_count_lock);
400 /* If there aren't any waiters, then this is a no-op. */
401 if (have_waiters)
402 ReleaseSemaphore(detail->sema, 1, NULL);
404 return 0;
407 int wine_pthread_cond_broadcast(pthread_cond_t *cond)
409 int have_waiters = 0;
410 wine_cond_detail *detail;
412 if ( !((wine_cond)cond)->cond ) wine_cond_real_init(cond);
413 detail = ((wine_cond)cond)->cond;
416 * This is needed to ensure that <waiters_count> and <was_broadcast> are
417 * consistent relative to each other.
419 RtlEnterCriticalSection (&detail->waiters_count_lock);
421 if (detail->waiters_count > 0) {
423 * We are broadcasting, even if there is just one waiter...
424 * Record that we are broadcasting, which helps optimize
425 * <pthread_cond_wait> for the non-broadcast case.
427 detail->was_broadcast = 1;
428 have_waiters = 1;
431 if (have_waiters) {
432 /* Wake up all the waiters atomically. */
433 ReleaseSemaphore(detail->sema, detail->waiters_count, NULL);
435 RtlLeaveCriticalSection (&detail->waiters_count_lock);
437 /* Wait for all the awakened threads to acquire the counting semaphore. */
438 WaitForSingleObject (detail->waiters_done, INFINITE);
441 * This assignment is okay, even without the <waiters_count_lock> held
442 * because no other waiter threads can wake up to access it.
444 detail->was_broadcast = 0;
446 else
447 RtlLeaveCriticalSection (&detail->waiters_count_lock);
448 return 0;
451 int wine_pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
453 wine_cond_detail *detail;
454 int last_waiter;
456 if ( !((wine_cond)cond)->cond ) wine_cond_real_init(cond);
457 detail = ((wine_cond)cond)->cond;
459 /* Avoid race conditions. */
460 RtlEnterCriticalSection (&detail->waiters_count_lock);
461 detail->waiters_count++;
462 RtlLeaveCriticalSection (&detail->waiters_count_lock);
464 RtlLeaveCriticalSection ( ((wine_mutex)mutex)->critsect );
465 WaitForSingleObject(detail->sema, INFINITE);
467 /* Reacquire lock to avoid race conditions. */
468 RtlEnterCriticalSection (&detail->waiters_count_lock);
470 /* We're no longer waiting... */
471 detail->waiters_count--;
473 /* Check to see if we're the last waiter after <pthread_cond_broadcast>. */
474 last_waiter = detail->was_broadcast && detail->waiters_count == 0;
476 RtlLeaveCriticalSection (&detail->waiters_count_lock);
479 * If we're the last waiter thread during this particular broadcast
480 * then let all the other threads proceed.
482 if (last_waiter) SetEvent(detail->waiters_done);
483 RtlEnterCriticalSection (((wine_mutex)mutex)->critsect);
484 return 0;
487 int wine_pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex,
488 const struct timespec *abstime)
490 DWORD ms = abstime->tv_sec * 1000 + abstime->tv_nsec / 1000000;
491 int last_waiter;
492 wine_cond_detail *detail;
494 if ( !((wine_cond)cond)->cond ) wine_cond_real_init(cond);
495 detail = ((wine_cond)cond)->cond;
497 /* Avoid race conditions. */
498 RtlEnterCriticalSection (&detail->waiters_count_lock);
499 detail->waiters_count++;
500 RtlLeaveCriticalSection (&detail->waiters_count_lock);
502 RtlLeaveCriticalSection (((wine_mutex)mutex)->critsect);
503 WaitForSingleObject (detail->sema, ms);
505 /* Reacquire lock to avoid race conditions. */
506 RtlEnterCriticalSection (&detail->waiters_count_lock);
508 /* We're no longer waiting... */
509 detail->waiters_count--;
511 /* Check to see if we're the last waiter after <pthread_cond_broadcast>. */
512 last_waiter = detail->was_broadcast && detail->waiters_count == 0;
514 RtlLeaveCriticalSection (&detail->waiters_count_lock);
517 * If we're the last waiter thread during this particular broadcast
518 * then let all the other threads proceed.
520 if (last_waiter) SetEvent (detail->waiters_done);
521 RtlEnterCriticalSection (((wine_mutex)mutex)->critsect);
522 return 0;
525 /***** MISC *****/
527 static pthread_t wine_pthread_self(void)
529 return (pthread_t)GetCurrentThreadId();
532 static int wine_pthread_equal(pthread_t thread1, pthread_t thread2)
534 return (DWORD)thread1 == (DWORD)thread2;
537 static void wine_pthread_exit(void *retval, char *currentframe)
539 ExitThread((DWORD)retval);
542 static void *wine_get_thread_data(void)
544 return NtCurrentTeb()->pthread_data;
547 static void wine_set_thread_data( void *data )
549 NtCurrentTeb()->pthread_data = data;
552 static const struct wine_pthread_functions functions =
554 sizeof(functions), /* size */
555 wine_get_thread_data, /* ptr_get_thread_data */
556 wine_set_thread_data, /* ptr_set_thread_data */
557 wine_pthread_self, /* ptr_pthread_self */
558 wine_pthread_equal, /* ptr_pthread_equal */
559 wine_pthread_create, /* ptr_pthread_create */
560 wine_pthread_cancel, /* ptr_pthread_cancel */
561 wine_pthread_join, /* ptr_pthread_join */
562 wine_pthread_detach, /* ptr_pthread_detach */
563 wine_pthread_exit, /* ptr_pthread_exit */
564 wine_pthread_mutex_init, /* ptr_pthread_mutex_init */
565 wine_pthread_mutex_lock, /* ptr_pthread_mutex_lock */
566 wine_pthread_mutex_trylock, /* ptr_pthread_mutex_trylock */
567 wine_pthread_mutex_unlock, /* ptr_pthread_mutex_unlock */
568 wine_pthread_mutex_destroy, /* ptr_pthread_mutex_destroy */
569 wine_pthread_rwlock_init, /* ptr_pthread_rwlock_init */
570 wine_pthread_rwlock_destroy, /* ptr_pthread_rwlock_destroy */
571 wine_pthread_rwlock_rdlock, /* ptr_pthread_rwlock_rdlock */
572 wine_pthread_rwlock_tryrdlock, /* ptr_pthread_rwlock_tryrdlock */
573 wine_pthread_rwlock_wrlock, /* ptr_pthread_rwlock_wrlock */
574 wine_pthread_rwlock_trywrlock, /* ptr_pthread_rwlock_trywrlock */
575 wine_pthread_rwlock_unlock, /* ptr_pthread_rwlock_unlock */
576 wine_pthread_cond_init, /* ptr_pthread_cond_init */
577 wine_pthread_cond_destroy, /* ptr_pthread_cond_destroy */
578 wine_pthread_cond_signal, /* ptr_pthread_cond_signal */
579 wine_pthread_cond_broadcast, /* ptr_pthread_cond_broadcast */
580 wine_pthread_cond_wait, /* ptr_pthread_cond_wait */
581 wine_pthread_cond_timedwait /* ptr_pthread_cond_timedwait */
584 #endif /* HAVE_PTHREAD_H */