Implemented pthread_cond_*, adjusted wrc parser and exception error output

Juraj Hercek juraj at syncad.com
Fri Jul 4 05:03:55 CDT 2003


Changelog:

Eric Frias <efrias at syncad.com>, Juraj Hercek <juraj at syncad.com>
* scheduler/pthread.c:
  Implemented missing pthread_cond_*() functions.

Juraj Hercek <juraj at syncad.com>
* tools/wrc/parser.y:
  Adjusted grammar to accept also help-ids for dialogex controls.
* win32/except.c:
  Modified unhandled exception message to contain also thread identifier.
-------------- next part --------------
Index: ./scheduler/pthread.c
===================================================================
RCS file: /home/wine/wine/scheduler/pthread.c,v
retrieving revision 1.33
diff -u -r1.33 pthread.c
--- ./scheduler/pthread.c	23 Jun 2003 18:12:28 -0000	1.33
+++ ./scheduler/pthread.c	4 Jul 2003 09:19:36 -0000
@@ -5,6 +5,8 @@
  * that want pthreads use Wine's own threading instead...
  *
  * Copyright 1999 Ove Kåven
+ * Copyright 2003 Eric Frias
+ * Copyright 2003 Juraj Hercek
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -74,6 +76,7 @@
     if (!libc_sigaction) libc_sigaction = dlsym( RTLD_NEXT, "sigaction" );
 }
 
+#define P_OUTPUT(stuff) write(2,stuff,strlen(stuff))
 
 /* NOTE: This is a truly extremely incredibly ugly hack!
  * But it does seem to work... */
@@ -87,6 +90,45 @@
   CRITICAL_SECTION *critsect;
 } *wine_mutex;
 
+/* 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;
+
 /* see wine_mutex above for comments */
 typedef struct {
   RTL_RWLOCK *lock;
@@ -102,8 +144,6 @@
 #define FIRST_KEY 0
 #define MAX_KEYS 16 /* libc6 doesn't use that many, but... */
 
-#define P_OUTPUT(stuff) write(2,stuff,strlen(stuff))
-
 void __pthread_initialize(void)
 {
 }
@@ -276,6 +316,18 @@
 
 /***** MUTEXES *****/
 
+static void mutex_real_init( pthread_mutex_t *mutex )
+{
+  CRITICAL_SECTION *critsect = HeapAlloc(GetProcessHeap(), 0, sizeof(CRITICAL_SECTION));
+  RtlInitializeCriticalSection(critsect);
+
+  if (InterlockedCompareExchangePointer((void**)&(((wine_mutex)mutex)->critsect),critsect,NULL) != NULL) {
+    /* too late, some other thread already did it */
+    RtlDeleteCriticalSection(critsect);
+    HeapFree(GetProcessHeap(), 0, critsect);
+  }
+}
+
 int __pthread_mutex_init(pthread_mutex_t *mutex,
                         const pthread_mutexattr_t *mutexattr)
 {
@@ -290,18 +342,6 @@
 }
 strong_alias(__pthread_mutex_init, pthread_mutex_init);
 
-static void mutex_real_init( pthread_mutex_t *mutex )
-{
-  CRITICAL_SECTION *critsect = HeapAlloc(GetProcessHeap(), 0, sizeof(CRITICAL_SECTION));
-  RtlInitializeCriticalSection(critsect);
-
-  if (InterlockedCompareExchangePointer((void**)&(((wine_mutex)mutex)->critsect),critsect,NULL) != NULL) {
-    /* too late, some other thread already did it */
-    RtlDeleteCriticalSection(critsect);
-    HeapFree(GetProcessHeap(), 0, critsect);
-  }
-}
-
 int __pthread_mutex_lock(pthread_mutex_t *mutex)
 {
   if (!init_done) return 0;
@@ -458,56 +498,198 @@
 
 
 /***** CONDITIONS *****/
-/* not implemented right now */
+/*See note above definition of wine_cond_detail at the begining of this file*/
+
+static void 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 */
+    CloseHandle(detail->sema_);
+    RtlDeleteCriticalSection(&detail->waiters_count_lock_);
+    CloseHandle(detail->waiters_done_);
+    HeapFree(GetProcessHeap(), 0, detail);
+  }
+}  
 
-int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *cond_attr)
+int __pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *cond_attr)
 {
-  P_OUTPUT("FIXME:pthread_cond_init\n");
+  /* The same as for __pthread_mutex_init, we postpone initialization
+     until condition is really used.*/
+  ((wine_cond)cond)->cond = NULL;
   return 0;
 }
+strong_alias(__pthread_cond_init, pthread_cond_init);
 
-int pthread_cond_destroy(pthread_cond_t *cond)
+
+int __pthread_cond_destroy(pthread_cond_t *cond)
 {
-  P_OUTPUT("FIXME:pthread_cond_destroy\n");
+  if ( !((wine_cond)cond)->cond )
+    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;
 }
+strong_alias(__pthread_cond_destroy, pthread_cond_destroy);
 
-int pthread_cond_signal(pthread_cond_t *cond)
+int __pthread_cond_signal(pthread_cond_t *cond)
 {
-  P_OUTPUT("FIXME:pthread_cond_signal\n");
+  if ( !((wine_cond)cond)->cond )
+    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;
 }
+strong_alias(__pthread_cond_signal, pthread_cond_signal);
 
-int pthread_cond_broadcast(pthread_cond_t *cond)
+int __pthread_cond_broadcast(pthread_cond_t *cond)
 {
-  P_OUTPUT("FIXME:pthread_cond_broadcast\n");
+  if ( !((wine_cond)cond)->cond )
+    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;
 }
+strong_alias(__pthread_cond_broadcast, pthread_cond_broadcast);
 
-int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
+int __pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
 {
-  P_OUTPUT("FIXME:pthread_cond_wait\n");
+  if ( !((wine_cond)cond)->cond )
+    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;
 }
+strong_alias(__pthread_cond_wait, pthread_cond_wait);
 
-int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, const struct timespec *abstime)
+int __pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, const struct timespec *abstime)
 {
-  P_OUTPUT("FIXME:pthread_cond_timedwait\n");
+  if ( !((wine_cond)cond)->cond )
+    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;
 }
+strong_alias(__pthread_cond_timedwait, pthread_cond_timedwait);
 
 /**** CONDITION ATTRIBUTES *****/
 /* not implemented right now */
 
-int pthread_condattr_init(pthread_condattr_t *attr)
+int __pthread_condattr_init(pthread_condattr_t *attr)
 {
   return 0;
 }
+strong_alias(__pthread_condattr_init, pthread_condattr_init);
 
-int pthread_condattr_destroy(pthread_condattr_t *attr)
+int __pthread_condattr_destroy(pthread_condattr_t *attr)
 {
   return 0;
 }
+strong_alias(__pthread_condattr_destroy, pthread_condattr_destroy);
 
 #if (__GLIBC__ == 2) && (__GLIBC_MINOR__ >= 2)
 /***** READ-WRITE LOCKS *****/
-------------- next part --------------
Index: ./tools/wrc/parser.y
===================================================================
RCS file: /home/wine/wine/tools/wrc/parser.y,v
retrieving revision 1.37
diff -u -r1.37 parser.y
--- ./tools/wrc/parser.y	18 Jun 2003 03:30:39 -0000	1.37
+++ ./tools/wrc/parser.y	4 Jul 2003 09:20:55 -0000
@@ -1140,7 +1140,7 @@
 	;
 
 lab_exctrl
-	: tSTRING opt_comma expr ',' expr ',' expr ',' expr ',' expr optional_style_pair opt_data {
+	: tSTRING opt_comma expr ',' expr ',' expr ',' expr ',' expr optional_style_pair helpid opt_data {
 		$$=new_control();
 		$$->title = new_name_id();
 		$$->title->type = name_str;
@@ -1163,12 +1163,12 @@
 			free($12);
 		}
 
-		$$->extra = $13;
+		$$->extra = $14;
 		}
 	;
 
 exctrl_desc
-	: expr ',' expr ',' expr ',' expr ',' expr optional_style_pair opt_data {
+	: expr ',' expr ',' expr ',' expr ',' expr optional_style_pair helpid opt_data {
 		$$ = new_control();
 		$$->id = $1;
 		$$->x = $3;
@@ -1187,7 +1187,7 @@
 			}
 			free($10);
 		}
-		$$->extra = $11;
+		$$->extra = $12;
 		}
 	;
 
-------------- next part --------------
Index: ./win32/except.c
===================================================================
RCS file: /home/wine/wine/win32/except.c,v
retrieving revision 1.67
diff -u -r1.67 except.c
--- ./win32/except.c	27 Apr 2003 00:31:34 -0000	1.67
+++ ./win32/except.c	4 Jul 2003 09:32:55 -0000
@@ -233,7 +233,15 @@
     static const WCHAR DebuggerW[] = {'D','e','b','u','g','g','e','r',0};
     static const WCHAR AutoW[] = {'A','u','t','o',0};
 
-    MESSAGE("wine: Unhandled exception, starting debugger...\n");
+    {
+    char buffer[96];
+    sprintf(buffer, 
+            "%s%x%s",
+            "wine: Unhandled exception in thread 0x",
+            (unsigned int) GetCurrentThreadId(),
+            ", starting debugger...\n");
+    MESSAGE(buffer);
+    }
 
     attr.Length = sizeof(attr);
     attr.RootDirectory = 0;


More information about the wine-patches mailing list