PATCH: winuser.h & pthread conditions

Juraj Hercek juraj at syncad.com
Wed Sep 10 09:00:34 CDT 2003


Hello,

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 at syncad.com>
* include/winuser.h
  Added SS_ENDELLIPSIS define

Juraj Hercek <juraj at syncad.com>, Eric Frias <efrias at syncad.com>
* dlls/kernel/pthread.c
  include/wine/pthread.h
  scheduler/pthread.c
  Implemented pthread conditions

-------------- next part --------------
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);
 


More information about the wine-patches mailing list