aboutsummaryrefslogtreecommitdiff
path: root/devel/linuxthreads
diff options
context:
space:
mode:
authorTor Egge <tegge@FreeBSD.org>2006-01-24 00:56:27 +0000
committerTor Egge <tegge@FreeBSD.org>2006-01-24 00:56:27 +0000
commit156af82b837bb2acef5adb8438ede53853899367 (patch)
tree8e009cb8107c33580e5d8b3ae3df1bee6f17137a /devel/linuxthreads
parent18ad5ce26ed5534dc584696bfd13635c1b73410d (diff)
downloadports-156af82b837bb2acef5adb8438ede53853899367.tar.gz
ports-156af82b837bb2acef5adb8438ede53853899367.zip
Fix timeout/cond signal race causing extra restart signal to be generated
but not consumed.
Notes
Notes: svn path=/head/; revision=154300
Diffstat (limited to 'devel/linuxthreads')
-rw-r--r--devel/linuxthreads/files/condwait-patch155
1 files changed, 109 insertions, 46 deletions
diff --git a/devel/linuxthreads/files/condwait-patch b/devel/linuxthreads/files/condwait-patch
index cbd6cefb81c9..5e9c45a2392a 100644
--- a/devel/linuxthreads/files/condwait-patch
+++ b/devel/linuxthreads/files/condwait-patch
@@ -1,16 +1,19 @@
-diff -ru ../../work.orig/linuxthreads-2.2.3_1/condvar.c ./condvar.c
---- ../../work.orig/linuxthreads-2.2.3_1/condvar.c Thu Apr 12 21:02:02 2001
-+++ ./condvar.c Wed Jul 18 13:30:47 2001
-@@ -55,6 +55,8 @@
+diff -ru ../../work.nc/linuxthreads-2.2.3_19/condvar.c ./condvar.c
+--- ../../work.nc/linuxthreads-2.2.3_19/condvar.c Thu Apr 12 23:02:02 2001
++++ ./condvar.c Tue Jan 10 18:14:20 2006
+@@ -55,6 +55,11 @@
return did_remove;
}
+extern int __pthread_mutex_condwait_completelock(pthread_mutex_t *mutex);
+
++#define CVA_AVAIL 1
++#define CVA_EXTRA_RESTART 2
++
int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
{
volatile pthread_descr self = thread_self();
-@@ -74,6 +76,7 @@
+@@ -74,6 +79,7 @@
/* Register extrication interface */
THREAD_SETMEM(self, p_condvar_avail, 0);
@@ -18,13 +21,30 @@ diff -ru ../../work.orig/linuxthreads-2.2.3_1/condvar.c ./condvar.c
__pthread_set_own_extricate_if(self, &extr);
/* Atomically enqueue thread for waiting, but only if it is not
-@@ -121,15 +124,35 @@
+@@ -102,10 +108,15 @@
+ while (1)
+ {
+ suspend(self);
+- if (THREAD_GETMEM(self, p_condvar_avail) == 0
++ if ((THREAD_GETMEM(self, p_condvar_avail) & CVA_AVAIL) == 0
+ && (THREAD_GETMEM(self, p_woken_by_cancel) == 0
+ || THREAD_GETMEM(self, p_cancelstate) != PTHREAD_CANCEL_ENABLE))
+ {
++ if ((THREAD_GETMEM(self, p_condvar_avail) &
++ CVA_EXTRA_RESTART) == 0 &&
++ !__compare_and_swap(&self->p_condvar_avail,
++ 0, CVA_EXTRA_RESTART))
++ break; /* CVA_AVAIL set by other thread */
+ /* Count resumes that don't belong to us. */
+ spurious_wakeup_count++;
+ continue;
+@@ -121,15 +132,35 @@
if (THREAD_GETMEM(self, p_woken_by_cancel)
&& THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE) {
THREAD_SETMEM(self, p_woken_by_cancel, 0);
- pthread_mutex_lock(mutex);
+ if (THREAD_GETMEM(self, p_condwait_mutex) == NULL) {
-+ if (THREAD_GETMEM(self, p_condwait_extra_restart) != 0) {
++ if ((THREAD_GETMEM(self, p_condvar_avail) & CVA_EXTRA_RESTART) != 0) {
+ if (spurious_wakeup_count > 0)
+ spurious_wakeup_count--;
+ else
@@ -37,7 +57,7 @@ diff -ru ../../work.orig/linuxthreads-2.2.3_1/condvar.c ./condvar.c
}
+ if (THREAD_GETMEM(self, p_condwait_mutex) == NULL &&
-+ THREAD_GETMEM(self, p_condwait_extra_restart) != 0) {
++ (THREAD_GETMEM(self, p_condvar_avail) & CVA_EXTRA_RESTART) != 0) {
+ if (spurious_wakeup_count > 0)
+ spurious_wakeup_count--;
+ else
@@ -56,7 +76,7 @@ diff -ru ../../work.orig/linuxthreads-2.2.3_1/condvar.c ./condvar.c
return 0;
}
-@@ -155,6 +178,7 @@
+@@ -155,6 +186,7 @@
/* Register extrication interface */
THREAD_SETMEM(self, p_condvar_avail, 0);
@@ -64,13 +84,30 @@ diff -ru ../../work.orig/linuxthreads-2.2.3_1/condvar.c ./condvar.c
__pthread_set_own_extricate_if(self, &extr);
/* Enqueue to wait on the condition and check for cancellation. */
-@@ -215,15 +239,35 @@
+@@ -196,10 +228,15 @@
+ suspend(self);
+ }
+
+- if (THREAD_GETMEM(self, p_condvar_avail) == 0
++ if ((THREAD_GETMEM(self, p_condvar_avail) & CVA_AVAIL) == 0
+ && (THREAD_GETMEM(self, p_woken_by_cancel) == 0
+ || THREAD_GETMEM(self, p_cancelstate) != PTHREAD_CANCEL_ENABLE))
+ {
++ if ((THREAD_GETMEM(self, p_condvar_avail) &
++ CVA_EXTRA_RESTART) == 0 &&
++ !__compare_and_swap(&self->p_condvar_avail,
++ 0, CVA_EXTRA_RESTART))
++ break; /* CVA_AVAIL set by other thread */
+ /* Count resumes that don't belong to us. */
+ spurious_wakeup_count++;
+ continue;
+@@ -215,15 +252,35 @@
if (THREAD_GETMEM(self, p_woken_by_cancel)
&& THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE) {
THREAD_SETMEM(self, p_woken_by_cancel, 0);
- pthread_mutex_lock(mutex);
+ if (THREAD_GETMEM(self, p_condwait_mutex) == NULL) {
-+ if (THREAD_GETMEM(self, p_condwait_extra_restart) != 0) {
++ if ((THREAD_GETMEM(self, p_condvar_avail) & CVA_EXTRA_RESTART) != 0) {
+ if (spurious_wakeup_count > 0)
+ spurious_wakeup_count--;
+ else
@@ -83,7 +120,7 @@ diff -ru ../../work.orig/linuxthreads-2.2.3_1/condvar.c ./condvar.c
}
+ if (THREAD_GETMEM(self, p_condwait_mutex) == NULL &&
-+ THREAD_GETMEM(self, p_condwait_extra_restart) != 0) {
++ (THREAD_GETMEM(self, p_condvar_avail) & CVA_EXTRA_RESTART) != 0) {
+ if (spurious_wakeup_count > 0)
+ spurious_wakeup_count--;
+ else
@@ -102,7 +139,13 @@ diff -ru ../../work.orig/linuxthreads-2.2.3_1/condvar.c ./condvar.c
return 0;
}
-@@ -242,9 +286,27 @@
+@@ -237,14 +294,34 @@
+ int pthread_cond_signal(pthread_cond_t *cond)
+ {
+ pthread_descr th;
++ long oldcva;
+
+ __pthread_lock(&cond->__c_lock, NULL);
th = dequeue(&cond->__c_waiting);
__pthread_unlock(&cond->__c_lock);
if (th != NULL) {
@@ -110,30 +153,39 @@ diff -ru ../../work.orig/linuxthreads-2.2.3_1/condvar.c ./condvar.c
- WRITE_MEMORY_BARRIER();
- restart(th);
+ pthread_mutex_t *mutex = th->p_condwait_mutex;
-+ if (th->p_condvar_avail == 0 &&
++ if ((th->p_condvar_avail & CVA_AVAIL) == 0 &&
+ mutex != NULL &&
+ (mutex->__m_kind == PTHREAD_MUTEX_ERRORCHECK_NP ||
+ mutex->__m_kind == PTHREAD_MUTEX_TIMED_NP) &&
+ __pthread_alt_condwait_queuelock(&mutex->__m_lock, th) == 0) {
+ th->p_condwait_mutex = NULL;
-+ th->p_condwait_extra_restart = 0;
+ WRITE_MEMORY_BARRIER();
-+ th->p_condvar_avail = 1;
++ do {
++ READ_MEMORY_BARRIER();
++ oldcva = th->p_condvar_avail;
++ } while (!__compare_and_swap(&th->p_condvar_avail,
++ oldcva,
++ oldcva | CVA_AVAIL));
+ WRITE_MEMORY_BARRIER();
-+ if (th->p_condwait_waitnode.abandoned) {
-+ th->p_condwait_extra_restart = 1;
-+ WRITE_MEMORY_BARRIER();
++ if ((th->p_condvar_avail & CVA_EXTRA_RESTART) != 0)
+ restart(th);
-+ }
+ } else {
-+ th->p_condvar_avail = 1;
++ th->p_condvar_avail = CVA_AVAIL;
+ WRITE_MEMORY_BARRIER();
+ restart(th);
+ }
}
return 0;
}
-@@ -260,9 +322,27 @@
+@@ -252,6 +329,7 @@
+ int pthread_cond_broadcast(pthread_cond_t *cond)
+ {
+ pthread_descr tosignal, th;
++ long oldcva;
+
+ __pthread_lock(&cond->__c_lock, NULL);
+ /* Copy the current state of the waiting queue and empty it */
+@@ -260,9 +338,28 @@
__pthread_unlock(&cond->__c_lock);
/* Now signal each process in the queue */
while ((th = dequeue(&tosignal)) != NULL) {
@@ -141,32 +193,34 @@ diff -ru ../../work.orig/linuxthreads-2.2.3_1/condvar.c ./condvar.c
- WRITE_MEMORY_BARRIER();
- restart(th);
+ pthread_mutex_t *mutex = th->p_condwait_mutex;
-+ if (th->p_condvar_avail == 0 &&
++ if ((th->p_condvar_avail & CVA_AVAIL) == 0 &&
+ mutex != NULL &&
+ (mutex->__m_kind == PTHREAD_MUTEX_ERRORCHECK_NP ||
+ mutex->__m_kind == PTHREAD_MUTEX_TIMED_NP) &&
+ __pthread_alt_condwait_queuelock(&mutex->__m_lock, th) == 0) {
+ th->p_condwait_mutex = NULL;
-+ th->p_condwait_extra_restart = 0;
+ WRITE_MEMORY_BARRIER();
-+ th->p_condvar_avail = 1;
++ do {
++ READ_MEMORY_BARRIER();
++ oldcva = th->p_condvar_avail;
++ } while (!__compare_and_swap(&th->p_condvar_avail,
++ oldcva,
++ oldcva | CVA_AVAIL));
+ WRITE_MEMORY_BARRIER();
-+ if (th->p_condwait_waitnode.abandoned) {
-+ th->p_condwait_extra_restart = 1;
-+ WRITE_MEMORY_BARRIER();
++ if ((th->p_condvar_avail & CVA_EXTRA_RESTART) != 0)
+ restart(th);
-+ }
+ } else {
-+ th->p_condvar_avail = 1;
++ th->p_condvar_avail = CVA_AVAIL;
+ WRITE_MEMORY_BARRIER();
+ restart(th);
+ }
}
return 0;
}
-diff -ru ../../work.orig/linuxthreads-2.2.3_1/internals.h ./internals.h
---- ../../work.orig/linuxthreads-2.2.3_1/internals.h Wed Jul 18 07:25:04 2001
-+++ ./internals.h Wed Jul 18 10:55:57 2001
+Only in .: condvar.c~
+diff -ru ../../work.nc/linuxthreads-2.2.3_19/internals.h ./internals.h
+--- ../../work.nc/linuxthreads-2.2.3_19/internals.h Tue Jan 10 17:13:14 2006
++++ ./internals.h Tue Jan 10 17:33:30 2006
@@ -125,6 +125,13 @@
int pr_lock_count;
} pthread_readlock_info;
@@ -181,19 +235,28 @@ diff -ru ../../work.orig/linuxthreads-2.2.3_1/internals.h ./internals.h
struct _pthread_descr_struct {
union {
struct {
-@@ -189,6 +196,9 @@
+@@ -176,7 +183,7 @@
+ struct pthread_atomic p_resume_count; /* number of times restart() was
+ called on thread */
+ char p_woken_by_cancel; /* cancellation performed wakeup */
+- char p_condvar_avail; /* flag if conditional variable became avail */
++ long p_condvar_avail; /* flag if conditional variable became avail */
+ char p_sem_avail; /* flag if semaphore became available */
+ pthread_extricate_if *p_extricate; /* See above */
+ pthread_readlock_info *p_readlock_list; /* List of readlock info structs */
+@@ -189,6 +196,8 @@
hp_timing_t p_cpuclock_offset; /* Initial CPU clock for thread. */
#endif
/* New elements must be added at the end. */
+ pthread_mutex_t *p_condwait_mutex;
+ struct wait_node p_condwait_waitnode;
-+ char p_condwait_extra_restart;
} __attribute__ ((aligned(32))); /* We need to align the structure so that
doubles are aligned properly. This is 8
bytes on MIPS and 16 bytes on MIPS64.
-diff -ru ../../work.orig/linuxthreads-2.2.3_1/mutex.c ./mutex.c
---- ../../work.orig/linuxthreads-2.2.3_1/mutex.c Sun Jan 7 04:35:20 2001
-+++ ./mutex.c Wed Jul 18 09:09:13 2001
+Only in .: internals.h~
+diff -ru ../../work.nc/linuxthreads-2.2.3_19/mutex.c ./mutex.c
+--- ../../work.nc/linuxthreads-2.2.3_19/mutex.c Sun Jan 7 05:35:20 2001
++++ ./mutex.c Tue Jan 10 17:13:46 2006
@@ -92,6 +92,24 @@
}
strong_alias (__pthread_mutex_trylock, pthread_mutex_trylock)
@@ -219,10 +282,10 @@ diff -ru ../../work.orig/linuxthreads-2.2.3_1/mutex.c ./mutex.c
int __pthread_mutex_lock(pthread_mutex_t * mutex)
{
pthread_descr self;
-diff -ru ../../work.orig/linuxthreads-2.2.3_1/spinlock.c ./spinlock.c
---- ../../work.orig/linuxthreads-2.2.3_1/spinlock.c Wed Jul 18 07:25:04 2001
-+++ ./spinlock.c Wed Jul 18 10:56:34 2001
-@@ -232,12 +232,6 @@
+diff -ru ../../work.nc/linuxthreads-2.2.3_19/spinlock.c ./spinlock.c
+--- ../../work.nc/linuxthreads-2.2.3_19/spinlock.c Tue Jan 10 17:13:14 2006
++++ ./spinlock.c Tue Jan 10 17:13:46 2006
+@@ -231,12 +231,6 @@
*/
@@ -235,7 +298,7 @@ diff -ru ../../work.orig/linuxthreads-2.2.3_1/spinlock.c ./spinlock.c
static long wait_node_free_list;
#if !defined HAS_COMPARE_AND_SWAP || defined TEST_FOR_COMPARE_AND_SWAP
static int wait_node_free_list_spinlock;
-@@ -360,6 +354,55 @@
+@@ -359,6 +353,55 @@
}
#endif
@@ -291,9 +354,9 @@ diff -ru ../../work.orig/linuxthreads-2.2.3_1/spinlock.c ./spinlock.c
void __pthread_alt_lock(struct _pthread_fastlock * lock,
pthread_descr self)
-diff -ru ../../work.orig/linuxthreads-2.2.3_1/spinlock.h ./spinlock.h
---- ../../work.orig/linuxthreads-2.2.3_1/spinlock.h Wed Jul 18 07:25:04 2001
-+++ ./spinlock.h Wed Jul 18 09:14:58 2001
+diff -ru ../../work.nc/linuxthreads-2.2.3_19/spinlock.h ./spinlock.h
+--- ../../work.nc/linuxthreads-2.2.3_19/spinlock.h Tue Jan 10 17:13:14 2006
++++ ./spinlock.h Tue Jan 10 17:13:46 2006
@@ -130,6 +130,9 @@
timed-out waits. Warning: do not mix these operations with the above ones
over the same lock object! */