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