Changelog:
Eric Frias <efrias@syncad.com>, Juraj Hercek <juraj@syncad.com>
* scheduler/pthread.c:
Implemented missing pthread_cond_*() functions.
Juraj Hercek <juraj@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.
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 *****/
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;
}
;
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;