First, I've added define for SS_ENDELLIPSIS into winuser.h. Next, I'm resending again pthread patch for cond stuff. If pthread patch will not be accepted, please drop me a note explaining the reason.
Best regards, Juraj
ChangeLog:
Juraj Hercek <juraj@syncad.com> * include/winuser.h Added SS_ENDELLIPSIS define
Juraj Hercek <juraj@syncad.com>, Eric Frias <efrias@syncad.com> * dlls/kernel/pthread.c include/wine/pthread.h scheduler/pthread.c Implemented pthread conditions
Index: include/winuser.h =================================================================== RCS file: /home/wine/wine/include/winuser.h,v retrieving revision 1.167 diff -u -r1.167 winuser.h --- include/winuser.h 10 Sep 2003 03:56:47 -0000 1.167 +++ include/winuser.h 10 Sep 2003 13:16:25 -0000 @@ -2055,6 +2055,7 @@ #define SS_RIGHTJUST 0x00000400L #define SS_REALSIZEIMAGE 0x00000800L #define SS_SUNKEN 0x00001000L +#define SS_ENDELLIPSIS 0x00004000L /* Static Control Messages */ #define STM_SETICON 0x0170 Index: dlls/kernel/pthread.c =================================================================== RCS file: /home/wine/wine/dlls/kernel/pthread.c,v retrieving revision 1.2 diff -u -r1.2 pthread.c --- dlls/kernel/pthread.c 5 Sep 2003 23:08:36 -0000 1.2 +++ dlls/kernel/pthread.c 10 Sep 2003 13:16:23 -0000 @@ -304,6 +304,216 @@ return 0; } +/***** CONDITIONS *****/ + +/* The condition code is basically cut-and-pasted from Douglas + * Schmidt's paper: + * "Strategies for Implementing POSIX Condition Variables on Win32", + * at http://www.cs.wustl.edu/~schmidt/win32-cv-1.html and + * http://www.cs.wustl.edu/~schmidt/win32-cv-2.html. + * This paper formed the basis for the condition variable + * impementation used in the ACE library. + */ + +/* Possible problems with ACE: + * - unimplemented pthread_mutexattr_init + */ +typedef struct { + // Number of waiting threads. + int waiters_count_; + + // Serialize access to <waiters_count_>. + CRITICAL_SECTION waiters_count_lock_; + + // Semaphore used to queue up threads waiting for the condition to + // become signaled. + HANDLE sema_; + + // An auto-reset event used by the broadcast/signal thread to wait + // for all the waiting thread(s) to wake up and be released from the + // semaphore. + HANDLE waiters_done_; + + // Keeps track of whether we were broadcasting or signaling. This + // allows us to optimize the code if we're just signaling. + size_t was_broadcast_; +} wine_cond_detail; + +/* see wine_mutex above for comments */ +typedef struct { + wine_cond_detail *cond; +} *wine_cond; + +static void wine_cond_real_init(pthread_cond_t *cond) +{ + wine_cond_detail *detail = + (wine_cond_detail*)HeapAlloc(GetProcessHeap(), 0, + sizeof(wine_cond_detail)); + detail->waiters_count_ = 0; + detail->was_broadcast_ = 0; + NtCreateSemaphore(&detail->sema_, 0, 0, 0, 0x7fffffff); + + RtlInitializeCriticalSection (&detail->waiters_count_lock_); + NtCreateEvent(&detail->waiters_done_, 0, 0, FALSE, FALSE); + + if (InterlockedCompareExchangePointer((void**)&(((wine_cond)cond)->cond), detail, NULL) + != NULL) + { + /* too late, some other thread already did it */ + P_OUTPUT("FIXME:pthread_cond_init:expect troubles...\n"); + CloseHandle(detail->sema_); + RtlDeleteCriticalSection(&detail->waiters_count_lock_); + CloseHandle(detail->waiters_done_); + HeapFree(GetProcessHeap(), 0, detail); + } +} + +int wine_pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *cond_attr) +{ + /* The same as for wine_pthread_mutex_init, we postpone initialization + until condition is really used.*/ + ((wine_cond)cond)->cond = NULL; + return 0; +} + +int wine_pthread_cond_destroy(pthread_cond_t *cond) +{ + if ( !((wine_cond)cond)->cond ) + wine_cond_real_init(cond); + wine_cond_detail *detail = ((wine_cond)cond)->cond; + CloseHandle(detail->sema_); + RtlDeleteCriticalSection(&detail->waiters_count_lock_); + CloseHandle(detail->waiters_done_); + HeapFree(GetProcessHeap(), 0, detail); + return 0; +} + +int wine_pthread_cond_signal(pthread_cond_t *cond) +{ + if ( !((wine_cond)cond)->cond ) + wine_cond_real_init(cond); + int have_waiters; + wine_cond_detail *detail = ((wine_cond)cond)->cond; + + RtlEnterCriticalSection (&detail->waiters_count_lock_); + have_waiters = detail->waiters_count_ > 0; + RtlLeaveCriticalSection (&detail->waiters_count_lock_); + + // If there aren't any waiters, then this is a no-op. + if (have_waiters) + NtReleaseSemaphore(detail->sema_, 1, NULL); + + return 0; +} + +int wine_pthread_cond_broadcast(pthread_cond_t *cond) +{ + if ( !((wine_cond)cond)->cond ) + wine_cond_real_init(cond); + wine_cond_detail *detail = ((wine_cond)cond)->cond; + int have_waiters = 0; + // This is needed to ensure that <waiters_count_> and <was_broadcast_> are + // consistent relative to each other. + RtlEnterCriticalSection (&detail->waiters_count_lock_); + + if (detail->waiters_count_ > 0) { + // We are broadcasting, even if there is just one waiter... + // Record that we are broadcasting, which helps optimize + // <pthread_cond_wait> for the non-broadcast case. + detail->was_broadcast_ = 1; + have_waiters = 1; + } + + if (have_waiters) { + // Wake up all the waiters atomically. + //ReleaseSemaphore (detail->sema_, detail->waiters_count_, 0); + NtReleaseSemaphore(detail->sema_, detail->waiters_count_, NULL); + + RtlLeaveCriticalSection (&detail->waiters_count_lock_); + + // Wait for all the awakened threads to acquire the counting + // semaphore. + WaitForSingleObject (detail->waiters_done_, INFINITE); + // This assignment is okay, even without the <waiters_count_lock_> held + // because no other waiter threads can wake up to access it. + detail->was_broadcast_ = 0; + } + else + RtlLeaveCriticalSection (&detail->waiters_count_lock_); + return 0; +} + +int wine_pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex) +{ + if ( !((wine_cond)cond)->cond ) + wine_cond_real_init(cond); + wine_cond_detail *detail = ((wine_cond)cond)->cond; + int last_waiter; + + // Avoid race conditions. + RtlEnterCriticalSection (&detail->waiters_count_lock_); + detail->waiters_count_++; + RtlLeaveCriticalSection (&detail->waiters_count_lock_); + + RtlLeaveCriticalSection ( ((wine_mutex)mutex)->critsect ); + WaitForSingleObject(detail->sema_, INFINITE); + + // Reacquire lock to avoid race conditions. + RtlEnterCriticalSection (&detail->waiters_count_lock_); + + // We're no longer waiting... + detail->waiters_count_--; + + // Check to see if we're the last waiter after <pthread_cond_broadcast>. + last_waiter = detail->was_broadcast_ && detail->waiters_count_ == 0; + + RtlLeaveCriticalSection (&detail->waiters_count_lock_); + + // If we're the last waiter thread during this particular broadcast + // then let all the other threads proceed. + if (last_waiter) + NtSetEvent(detail->waiters_done_, NULL); + RtlEnterCriticalSection (((wine_mutex)mutex)->critsect); + + return 0; +} + +int wine_pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, const struct timespec *abstime) +{ + if ( !((wine_cond)cond)->cond ) + wine_cond_real_init(cond); + wine_cond_detail *detail = ((wine_cond)cond)->cond; + DWORD ms = abstime->tv_sec * 1000 + abstime->tv_nsec / 1000000; + int last_waiter; + + // Avoid race conditions. + RtlEnterCriticalSection (&detail->waiters_count_lock_); + detail->waiters_count_++; + RtlLeaveCriticalSection (&detail->waiters_count_lock_); + + RtlLeaveCriticalSection (((wine_mutex)mutex)->critsect); + WaitForSingleObject (detail->sema_, ms); + + // Reacquire lock to avoid race conditions. + RtlEnterCriticalSection (&detail->waiters_count_lock_); + + // We're no longer waiting... + detail->waiters_count_--; + + // Check to see if we're the last waiter after <pthread_cond_broadcast>. + last_waiter = detail->was_broadcast_ && detail->waiters_count_ == 0; + + RtlLeaveCriticalSection (&detail->waiters_count_lock_); + + // If we're the last waiter thread during this particular broadcast + // then let all the other threads proceed. + if (last_waiter) + NtSetEvent (detail->waiters_done_, NULL); + RtlEnterCriticalSection (((wine_mutex)mutex)->critsect); + + return 0; +} + /***** MISC *****/ static pthread_t wine_pthread_self(void) @@ -353,5 +563,11 @@ wine_pthread_rwlock_tryrdlock, /* ptr_pthread_rwlock_tryrdlock */ wine_pthread_rwlock_wrlock, /* ptr_pthread_rwlock_wrlock */ wine_pthread_rwlock_trywrlock, /* ptr_pthread_rwlock_trywrlock */ - wine_pthread_rwlock_unlock /* ptr_pthread_rwlock_unlock */ + wine_pthread_rwlock_unlock, /* ptr_pthread_rwlock_unlock */ + wine_pthread_cond_init, /* ptr_pthread_cond_init */ + wine_pthread_cond_destroy, /* ptr_pthread_cond_destroy */ + wine_pthread_cond_signal, /* ptr_pthread_cond_signal */ + wine_pthread_cond_broadcast, /* ptr_pthread_cond_broadcast */ + wine_pthread_cond_wait, /* ptr_pthread_cond_wait */ + wine_pthread_cond_timedwait /* ptr_pthread_cond_timedwait */ }; Index: include/wine/pthread.h =================================================================== RCS file: /home/wine/wine/include/wine/pthread.h,v retrieving revision 1.1 diff -u -r1.1 pthread.h --- include/wine/pthread.h 3 Sep 2003 00:26:08 -0000 1.1 +++ include/wine/pthread.h 10 Sep 2003 13:16:25 -0000 @@ -56,6 +56,13 @@ int (*ptr_pthread_rwlock_wrlock)(pthread_rwlock_t *rwlock); int (*ptr_pthread_rwlock_trywrlock)(pthread_rwlock_t *rwlock); int (*ptr_pthread_rwlock_unlock)(pthread_rwlock_t *rwlock); + int (*ptr_pthread_cond_init)(pthread_cond_t *cond, + const pthread_condattr_t *cond_attr); + int (*ptr_pthread_cond_destroy)(pthread_cond_t *cond); + int (*ptr_pthread_cond_signal)(pthread_cond_t *cond); + int (*ptr_pthread_cond_broadcast)(pthread_cond_t *cond); + int (*ptr_pthread_cond_wait)(pthread_cond_t *cond, pthread_mutex_t *mutex); + int (*ptr_pthread_cond_timedwait)(pthread_cond_t *cond, pthread_mutex_t *mutex, const struct timespec *abstime); }; extern void wine_pthread_init_process( const struct wine_pthread_functions *functions ); Index: scheduler/pthread.c =================================================================== RCS file: /home/wine/wine/scheduler/pthread.c,v retrieving revision 1.38 diff -u -r1.38 pthread.c --- scheduler/pthread.c 3 Sep 2003 00:26:08 -0000 1.38 +++ scheduler/pthread.c 10 Sep 2003 13:16:25 -0000 @@ -563,47 +563,52 @@ } /***** CONDITIONS *****/ -/* not implemented right now */ int __pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *cond_attr) { - P_OUTPUT("FIXME:pthread_cond_init\n"); - return 0; + if (!funcs.ptr_pthread_cond_init) + return 0; + return funcs.ptr_pthread_cond_init(cond, cond_attr); } strong_alias(__pthread_cond_init, pthread_cond_init); int __pthread_cond_destroy(pthread_cond_t *cond) { - P_OUTPUT("FIXME:pthread_cond_destroy\n"); - return 0; + if (!funcs.ptr_pthread_cond_destroy) + return 0; + return funcs.ptr_pthread_cond_destroy(cond); } strong_alias(__pthread_cond_destroy, pthread_cond_destroy); int __pthread_cond_signal(pthread_cond_t *cond) { - P_OUTPUT("FIXME:pthread_cond_signal\n"); - return 0; + if (!funcs.ptr_pthread_cond_signal) + return 0; + return funcs.ptr_pthread_cond_signal(cond); } strong_alias(__pthread_cond_signal, pthread_cond_signal); int __pthread_cond_broadcast(pthread_cond_t *cond) { - P_OUTPUT("FIXME:pthread_cond_broadcast\n"); - return 0; + if (!funcs.ptr_pthread_cond_broadcast) + return 0; + return funcs.ptr_pthread_cond_broadcast(cond); } strong_alias(__pthread_cond_broadcast, pthread_cond_broadcast); int __pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex) { - P_OUTPUT("FIXME:pthread_cond_wait\n"); - return 0; + if (!funcs.ptr_pthread_cond_wait) + return 0; + return funcs.ptr_pthread_cond_wait(cond, mutex); } strong_alias(__pthread_cond_wait, pthread_cond_wait); int __pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, const struct timespec *abstime) { - P_OUTPUT("FIXME:pthread_cond_timedwait\n"); - return 0; + if (!funcs.ptr_pthread_cond_timedwait) + return 0; + return funcs.ptr_pthread_cond_timedwait(cond, mutex, abstime); } strong_alias(__pthread_cond_timedwait, pthread_cond_timedwait);