diff options
author | Tor Egge <tegge@FreeBSD.org> | 2001-09-09 01:12:47 +0000 |
---|---|---|
committer | Tor Egge <tegge@FreeBSD.org> | 2001-09-09 01:12:47 +0000 |
commit | 60032d4ed757d713b448d48056a9a09308af99cf (patch) | |
tree | 4d3c1ed7e63ae0cd8efbb2656bb417b212e5afcb /devel/linuxthreads | |
parent | 97c49bb4118e6dd997da26d8ff48ed99b96ab2dd (diff) | |
download | ports-60032d4ed757d713b448d48056a9a09308af99cf.tar.gz ports-60032d4ed757d713b448d48056a9a09308af99cf.zip |
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/linuxthreads')
-rw-r--r-- | devel/linuxthreads/Makefile | 21 | ||||
-rw-r--r-- | devel/linuxthreads/files/condwait-patch | 306 |
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); + |