summaryrefslogtreecommitdiff
path: root/devel
diff options
context:
space:
mode:
authorTor Egge <tegge@FreeBSD.org>2001-09-09 01:12:47 +0000
committerTor Egge <tegge@FreeBSD.org>2001-09-09 01:12:47 +0000
commit60032d4ed757d713b448d48056a9a09308af99cf (patch)
tree4d3c1ed7e63ae0cd8efbb2656bb417b212e5afcb /devel
parentUpdate WWW: tag (diff)
Add an optional experimental patch that reduce the number of context
switches on UP systems when the thread waiting on a condition has a higher priority than the thread signalling the condition. Bump port revision.
Notes
Notes: svn path=/head/; revision=47555
Diffstat (limited to 'devel')
-rw-r--r--devel/linuxthreads/Makefile21
-rw-r--r--devel/linuxthreads/files/condwait-patch306
2 files changed, 326 insertions, 1 deletions
diff --git a/devel/linuxthreads/Makefile b/devel/linuxthreads/Makefile
index d46d45acab50..0c09a9dc6c61 100644
--- a/devel/linuxthreads/Makefile
+++ b/devel/linuxthreads/Makefile
@@ -7,7 +7,7 @@
PORTNAME= linuxthreads
PORTVERSION= 2.2.3
-PORTREVISION= 1
+PORTREVISION= 2
CATEGORIES= devel
MASTER_SITES= ${MASTER_SITE_GNU}
MASTER_SITE_SUBDIR= glibc
@@ -33,6 +33,14 @@ WRKSRC= ${WRKDIR}/${PKGNAME}
SRC_BASE= /usr/src
LIBSRC_BASE= ${SRC_BASE}/lib
+.if !defined(WITH_CONDWAIT_PATCH)
+pre-fetch:
+ @${ECHO}
+ @${ECHO} You can use an experimental patch to reduce the number of
+ @${ECHO} condition variable triggered context switches by defining
+ @${ECHO} WITH_CONDWAIT_PATCH
+.endif
+
post-extract:
@mv ${WRKDIR}/linuxthreads ${WRKSRC}
@mv ${WRKDIR}/linuxthreads_db ${WRKSRC}
@@ -46,6 +54,17 @@ post-extract:
@test -f ${WRKSRC}/libgcc_r/Makefile || \
${LN} -s ${FILESDIR}/Makefile.libgcc_r ${WRKSRC}/libgcc_r/Makefile
+.if defined(WITH_CONDWAIT_PATCH)
+post-patch:
+ @${ECHO_MSG} "===> Applying experimental patch condwait-patch"
+ @if ${PATCH} ${PATCH_ARGS} < ${PATCHDIR}/condwait-patch; then \
+ ${ECHO_MSG} "===> Patch condwait-patch applied successfully"; \
+ else \
+ ${ECHO_MSG} ">>Patch condwait-patch failed to apply cleanly"; \
+ false ; \
+ fi
+.endif
+
pre-build:
@cd ${WRKSRC}/libgcc_r ; \
${MAKE}
diff --git a/devel/linuxthreads/files/condwait-patch b/devel/linuxthreads/files/condwait-patch
new file mode 100644
index 000000000000..cbd6cefb81c9
--- /dev/null
+++ b/devel/linuxthreads/files/condwait-patch
@@ -0,0 +1,306 @@
+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 @@
+ return did_remove;
+ }
+
++extern int __pthread_mutex_condwait_completelock(pthread_mutex_t *mutex);
++
+ int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
+ {
+ volatile pthread_descr self = thread_self();
+@@ -74,6 +76,7 @@
+
+ /* Register extrication interface */
+ THREAD_SETMEM(self, p_condvar_avail, 0);
++ THREAD_SETMEM(self, p_condwait_mutex, mutex);
+ __pthread_set_own_extricate_if(self, &extr);
+
+ /* Atomically enqueue thread for waiting, but only if it is not
+@@ -121,15 +124,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 (spurious_wakeup_count > 0)
++ spurious_wakeup_count--;
++ else
++ suspend(self);
++ }
++ __pthread_mutex_condwait_completelock(mutex);
++ } else
++ pthread_mutex_lock(mutex);
+ __pthread_do_exit(PTHREAD_CANCELED, CURRENT_STACK_FRAME);
+ }
+
++ if (THREAD_GETMEM(self, p_condwait_mutex) == NULL &&
++ THREAD_GETMEM(self, p_condwait_extra_restart) != 0) {
++ if (spurious_wakeup_count > 0)
++ spurious_wakeup_count--;
++ else
++ suspend(self);
++ }
++
+ /* Put back any resumes we caught that don't belong to us. */
+ while (spurious_wakeup_count--)
+ restart(self);
+
+- pthread_mutex_lock(mutex);
++ if (THREAD_GETMEM(self, p_condwait_mutex) == NULL)
++ __pthread_mutex_condwait_completelock(mutex);
++ else
++ pthread_mutex_lock(mutex);
+ return 0;
+ }
+
+@@ -155,6 +178,7 @@
+
+ /* Register extrication interface */
+ THREAD_SETMEM(self, p_condvar_avail, 0);
++ THREAD_SETMEM(self, p_condwait_mutex, mutex);
+ __pthread_set_own_extricate_if(self, &extr);
+
+ /* Enqueue to wait on the condition and check for cancellation. */
+@@ -215,15 +239,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 (spurious_wakeup_count > 0)
++ spurious_wakeup_count--;
++ else
++ suspend(self);
++ }
++ __pthread_mutex_condwait_completelock(mutex);
++ } else
++ pthread_mutex_lock(mutex);
+ __pthread_do_exit(PTHREAD_CANCELED, CURRENT_STACK_FRAME);
+ }
+
++ if (THREAD_GETMEM(self, p_condwait_mutex) == NULL &&
++ THREAD_GETMEM(self, p_condwait_extra_restart) != 0) {
++ if (spurious_wakeup_count > 0)
++ spurious_wakeup_count--;
++ else
++ suspend(self);
++ }
++
+ /* Put back any resumes we caught that don't belong to us. */
+ while (spurious_wakeup_count--)
+ restart(self);
+
+- pthread_mutex_lock(mutex);
++ if (THREAD_GETMEM(self, p_condwait_mutex) == NULL)
++ __pthread_mutex_condwait_completelock(mutex);
++ else
++ pthread_mutex_lock(mutex);
+ return 0;
+ }
+
+@@ -242,9 +286,27 @@
+ th = dequeue(&cond->__c_waiting);
+ __pthread_unlock(&cond->__c_lock);
+ if (th != NULL) {
+- th->p_condvar_avail = 1;
+- WRITE_MEMORY_BARRIER();
+- restart(th);
++ pthread_mutex_t *mutex = th->p_condwait_mutex;
++ if (th->p_condvar_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;
++ WRITE_MEMORY_BARRIER();
++ if (th->p_condwait_waitnode.abandoned) {
++ th->p_condwait_extra_restart = 1;
++ WRITE_MEMORY_BARRIER();
++ restart(th);
++ }
++ } else {
++ th->p_condvar_avail = 1;
++ WRITE_MEMORY_BARRIER();
++ restart(th);
++ }
+ }
+ return 0;
+ }
+@@ -260,9 +322,27 @@
+ __pthread_unlock(&cond->__c_lock);
+ /* Now signal each process in the queue */
+ while ((th = dequeue(&tosignal)) != NULL) {
+- th->p_condvar_avail = 1;
+- WRITE_MEMORY_BARRIER();
+- restart(th);
++ pthread_mutex_t *mutex = th->p_condwait_mutex;
++ if (th->p_condvar_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;
++ WRITE_MEMORY_BARRIER();
++ if (th->p_condwait_waitnode.abandoned) {
++ th->p_condwait_extra_restart = 1;
++ WRITE_MEMORY_BARRIER();
++ restart(th);
++ }
++ } else {
++ th->p_condvar_avail = 1;
++ 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
+@@ -125,6 +125,13 @@
+ int pr_lock_count;
+ } pthread_readlock_info;
+
++
++struct wait_node {
++ struct wait_node *next; /* Next node in null terminated linked list */
++ pthread_descr thr; /* The thread waiting with this node */
++ int abandoned; /* Atomic flag */
++};
++
+ struct _pthread_descr_struct {
+ union {
+ struct {
+@@ -189,6 +196,9 @@
+ 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
+@@ -92,6 +92,24 @@
+ }
+ strong_alias (__pthread_mutex_trylock, pthread_mutex_trylock)
+
++int __pthread_mutex_condwait_completelock(pthread_mutex_t *mutex)
++{
++ pthread_descr self;
++
++ switch(mutex->__m_kind) {
++ case PTHREAD_MUTEX_ERRORCHECK_NP:
++ self = thread_self();
++ if (mutex->__m_owner == self) return EDEADLK;
++ mutex->__m_owner = self;
++ return 0;
++ case PTHREAD_MUTEX_TIMED_NP:
++ return 0;
++ default:
++ return EINVAL;
++ }
++}
++
++
+ 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 @@
+ */
+
+
+-struct wait_node {
+- struct wait_node *next; /* Next node in null terminated linked list */
+- pthread_descr thr; /* The thread waiting with this node */
+- int abandoned; /* Atomic flag */
+-};
+-
+ 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 @@
+ }
+
+ #endif
++
++int __pthread_alt_condwait_queuelock(struct _pthread_fastlock * lock,
++ pthread_descr th)
++{
++#if defined HAS_COMPARE_AND_SWAP
++ long oldstatus, newstatus;
++#endif
++
++#if defined TEST_FOR_COMPARE_AND_SWAP
++ if (!__pthread_has_cas)
++#endif
++#if !defined HAS_COMPARE_AND_SWAP || defined TEST_FOR_COMPARE_AND_SWAP
++ {
++ __pthread_acquire(&lock->__spinlock);
++
++ if (lock->__status == 0) {
++ WRITE_MEMORY_BARRIER();
++ lock->__spinlock = __LT_SPINLOCK_INIT;
++ return 1;
++ }
++ th->p_condwait_waitnode.abandoned = 0;
++ th->p_condwait_waitnode.next = (struct wait_node *) lock->__status;
++ th->p_condwait_waitnode.thr = th;
++ lock->__status = (long) &th->p_condwait_waitnode;
++
++ WRITE_MEMORY_BARRIER();
++ lock->__spinlock = __LT_SPINLOCK_INIT;
++ return 0;
++ }
++#endif
++
++#if defined HAS_COMPARE_AND_SWAP
++ do {
++ oldstatus = lock->__status;
++ if (oldstatus == 0) {
++ return 1;
++ }
++ th->p_condwait_waitnode.thr = th;
++ newstatus = (long) &th->p_condwait_waitnode;
++ th->p_condwait_waitnode.abandoned = 0;
++ th->p_condwait_waitnode.next = (struct wait_node *) oldstatus;
++ /* Make sure the store in wait_node.next completes before performing
++ the compare-and-swap */
++ MEMORY_BARRIER();
++ } while(! __compare_and_swap(&lock->__status, oldstatus, newstatus));
++ return 0;
++#endif
++}
++
+
+ 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
+@@ -130,6 +130,9 @@
+ timed-out waits. Warning: do not mix these operations with the above ones
+ over the same lock object! */
+
++extern int __pthread_alt_condwait_queuelock(struct _pthread_fastlock * lock,
++ pthread_descr th);
++
+ extern void __pthread_alt_lock(struct _pthread_fastlock * lock,
+ pthread_descr self);
+