author | Wan-Teh Chang <wtc@google.com> |
Wed, 27 Feb 2013 12:51:25 -0800 | |
changeset 123209 | ae360bf4bc473dffe40da66400d9d8f9dcee0756 |
parent 123208 | 1444bada530a0122cb0e68bb862a8e4516726fae |
child 123210 | 3d20e0577cbf7d5bcdf7b29affb64b41d1dbab55 |
push id | 24373 |
push user | ryanvm@gmail.com |
push date | Thu, 28 Feb 2013 01:36:21 +0000 |
treeherder | mozilla-central@8cb9d6981978 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
bugs | 841651 |
milestone | 22.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/nsprpub/config/prdepend.h +++ b/nsprpub/config/prdepend.h @@ -5,8 +5,9 @@ /* * A dummy header file that is a dependency for all the object files. * Used to force a full recompilation of NSPR in Mozilla's Tinderbox * depend builds. See comments in rules.mk. */ #error "Do not include this header file." +
--- a/nsprpub/configure +++ b/nsprpub/configure @@ -5616,17 +5616,17 @@ fi echo "$ac_t""$ac_cv_prog_gcc_traditional" 1>&6 if test $ac_cv_prog_gcc_traditional = yes; then CC="$CC -traditional" fi fi _SAVE_LIBS="$LIBS" LIBS="$LIBS $OS_LIBS" -for ac_func in lchown strerror dladdr +for ac_func in dladdr gettid lchown setpriority strerror syscall do echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 echo "configure:5628: checking for $ac_func" >&5 if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF #line 5633 "configure"
--- a/nsprpub/configure.in +++ b/nsprpub/configure.in @@ -2583,17 +2583,17 @@ dnl AC_HEADER_TIME dnl AC_STRUCT_TM dnl ======================================================== dnl Checks for library functions. dnl ======================================================== AC_PROG_GCC_TRADITIONAL _SAVE_LIBS="$LIBS" LIBS="$LIBS $OS_LIBS" -AC_CHECK_FUNCS(lchown strerror dladdr) +AC_CHECK_FUNCS(dladdr gettid lchown setpriority strerror syscall) LIBS="$_SAVE_LIBS" dnl AC_FUNC_MEMCMP dnl AC_FUNC_MMAP dnl AC_FUNC_SETVBUF_REVERSED dnl AC_FUNC_STRCOLL dnl AC_FUNC_STRFTIME dnl AC_FUNC_UTIME_NULL
new file mode 100644 --- /dev/null +++ b/nsprpub/patches/README @@ -0,0 +1,5 @@ +This directory contains patches that were added locally +on top of the NSPR release. + +* linux-setpriority.patch: Bug 841651 - Implement PR_SetThreadPriority() + on Linux-based platforms using per-thread nice values.
new file mode 100644 --- /dev/null +++ b/nsprpub/patches/linux-setpriority.patch @@ -0,0 +1,278 @@ +diff --git a/nsprpub/configure.in b/nsprpub/configure.in +--- a/nsprpub/configure.in ++++ b/nsprpub/configure.in +@@ -2583,17 +2583,17 @@ dnl AC_HEADER_TIME + dnl AC_STRUCT_TM + + dnl ======================================================== + dnl Checks for library functions. + dnl ======================================================== + AC_PROG_GCC_TRADITIONAL + _SAVE_LIBS="$LIBS" + LIBS="$LIBS $OS_LIBS" +-AC_CHECK_FUNCS(lchown strerror dladdr) ++AC_CHECK_FUNCS(dladdr gettid lchown setpriority strerror syscall) + LIBS="$_SAVE_LIBS" + + dnl AC_FUNC_MEMCMP + dnl AC_FUNC_MMAP + dnl AC_FUNC_SETVBUF_REVERSED + dnl AC_FUNC_STRCOLL + dnl AC_FUNC_STRFTIME + dnl AC_FUNC_UTIME_NULL +diff --git a/nsprpub/pr/include/private/primpl.h b/nsprpub/pr/include/private/primpl.h +--- a/nsprpub/pr/include/private/primpl.h ++++ b/nsprpub/pr/include/private/primpl.h +@@ -45,16 +45,20 @@ typedef struct PRSegment PRSegment; + #include "obsolete/probslet.h" + + #ifdef _PR_HAVE_POSIX_SEMAPHORES + #include <semaphore.h> + #elif defined(_PR_HAVE_SYSV_SEMAPHORES) + #include <sys/sem.h> + #endif + ++#ifdef HAVE_SYSCALL ++#include <sys/syscall.h> ++#endif ++ + /************************************************************************* + ***** A Word about Model Dependent Function Naming Convention *********** + *************************************************************************/ + + /* + NSPR 2.0 must implement its function across a range of platforms + including: MAC, Windows/16, Windows/95, Windows/NT, and several + variants of Unix. Each implementation shares common code as well +@@ -181,16 +185,27 @@ typedef struct PTDebug + PRUintn cvars_created, cvars_destroyed; + PRUintn cvars_notified, delayed_cv_deletes; + } PTDebug; + + #endif /* defined(DEBUG) */ + + NSPR_API(void) PT_FPrintStats(PRFileDesc *fd, const char *msg); + ++/* ++ * On Linux and its derivatives POSIX priority scheduling works only for ++ * real-time threads. On those platforms we set thread's nice values ++ * instead which requires us to track kernel thread IDs for each POSIX ++ * thread we create. ++ */ ++#if defined(LINUX) && defined(HAVE_SETPRIORITY) && \ ++ ((defined(HAVE_SYSCALL) && defined(SYS_gettid)) || defined(HAVE_GETTID)) ++#define _PR_NICE_PRIORITY_SCHEDULING ++#endif ++ + #else /* defined(_PR_PTHREADS) */ + + NSPR_API(void) PT_FPrintStats(PRFileDesc *fd, const char *msg); + + /* + ** This section is contains those parts needed to implement NSPR on + ** platforms in general. One would assume that the pthreads implementation + ** included lots of the same types, at least conceptually. +@@ -1535,16 +1550,19 @@ struct PRThread { + PRInt32 osErrorCode; /* mapping of errorCode | zero */ + PRIntn errorStringLength; /* textLength from last call to PR_SetErrorText() */ + PRInt32 errorStringSize; /* malloc()'d size of buffer | zero */ + char *errorString; /* current error string | NULL */ + char *name; /* thread's name */ + + #if defined(_PR_PTHREADS) + pthread_t id; /* pthread identifier for the thread */ ++#ifdef _PR_NICE_PRIORITY_SCHEDULING ++ pid_t tid; /* Linux-specific kernel thread ID */ ++#endif + PRBool okToDelete; /* ok to delete the PRThread struct? */ + PRCondVar *waiting; /* where the thread is waiting | NULL */ + void *sp; /* recorded sp for garbage collection */ + PRThread *next, *prev; /* simple linked list of all threads */ + PRUint32 suspend; /* used to store suspend and resume flags */ + #ifdef PT_NO_SIGTIMEDWAIT + pthread_mutex_t suspendResumeMutex; + pthread_cond_t suspendResumeCV; +diff --git a/nsprpub/pr/src/pthreads/ptthread.c b/nsprpub/pr/src/pthreads/ptthread.c +--- a/nsprpub/pr/src/pthreads/ptthread.c ++++ b/nsprpub/pr/src/pthreads/ptthread.c +@@ -23,16 +23,24 @@ + + #ifdef SYMBIAN + /* In Open C sched_get_priority_min/max do not work properly, so we undefine + * _POSIX_THREAD_PRIORITY_SCHEDULING here. + */ + #undef _POSIX_THREAD_PRIORITY_SCHEDULING + #endif + ++#ifdef _PR_NICE_PRIORITY_SCHEDULING ++#undef _POSIX_THREAD_PRIORITY_SCHEDULING ++#include <sys/resource.h> ++#ifndef HAVE_GETTID ++#define gettid() (syscall(SYS_gettid)) ++#endif ++#endif ++ + /* + * Record whether or not we have the privilege to set the scheduling + * policy and priority of threads. 0 means that privilege is available. + * EPERM means that privilege is not available. + */ + + static PRIntn pt_schedpriv = 0; + extern PRLock *_pr_sleeplock; +@@ -49,26 +57,35 @@ static struct _PT_Bookeeping + PRInt32 minPrio, maxPrio; /* range of scheduling priorities */ + #endif + } pt_book = {0}; + + static void _pt_thread_death(void *arg); + static void _pt_thread_death_internal(void *arg, PRBool callDestructors); + static void init_pthread_gc_support(void); + +-#if defined(_PR_DCETHREADS) || defined(_POSIX_THREAD_PRIORITY_SCHEDULING) ++#if defined(_PR_DCETHREADS) || \ ++ defined(_POSIX_THREAD_PRIORITY_SCHEDULING) || \ ++ defined(_PR_NICE_PRIORITY_SCHEDULING) + static PRIntn pt_PriorityMap(PRThreadPriority pri) + { + #ifdef NTO + /* This priority algorithm causes lots of problems on Neutrino + * for now I have just hard coded everything to run at priority 10 + * until I can come up with a new algorithm. + * Jerry.Kirk@Nexwarecorp.com + */ + return 10; ++#elif defined(_PR_NICE_PRIORITY_SCHEDULING) ++ /* This maps high priorities to low nice values: ++ * PR_PRIORITY_LOW 1 ++ * PR_PRIORITY_NORMAL 0 ++ * PR_PRIORITY_HIGH -1 ++ * PR_PRIORITY_URGENT -2 */ ++ return 1 - pri; + #else + return pt_book.minPrio + + pri * (pt_book.maxPrio - pt_book.minPrio) / PR_PRIORITY_LAST; + #endif + } + #endif + + /* +@@ -93,28 +110,46 @@ static void _PR_InitializeStack(PRThread + } + } + + static void *_pt_root(void *arg) + { + PRIntn rv; + PRThread *thred = (PRThread*)arg; + PRBool detached = (thred->state & PT_THREAD_DETACHED) ? PR_TRUE : PR_FALSE; ++#ifdef _PR_NICE_PRIORITY_SCHEDULING ++ pid_t tid; ++#endif + + /* + * Both the parent thread and this new thread set thred->id. + * The new thread must ensure that thred->id is set before + * it executes its startFunc. The parent thread must ensure + * that thred->id is set before PR_CreateThread() returns. + * Both threads set thred->id without holding a lock. Since + * they are writing the same value, this unprotected double + * write should be safe. + */ + thred->id = pthread_self(); + ++#ifdef _PR_NICE_PRIORITY_SCHEDULING ++ /* ++ * We need to know the kernel thread ID of each thread in order to ++ * set its priority hence we do it here instead of at creation time. ++ */ ++ tid = gettid(); ++ ++ rv = setpriority(PRIO_PROCESS, tid, pt_PriorityMap(thred->priority)); ++ ++ PR_Lock(pt_book.ml); ++ thred->tid = tid; ++ PR_NotifyAllCondVar(pt_book.cv); ++ PR_Unlock(pt_book.ml); ++#endif ++ + /* + ** DCE Threads can't detach during creation, so do it late. + ** I would like to do it only here, but that doesn't seem + ** to work. + */ + #if defined(_PR_DCETHREADS) + if (detached) + { +@@ -219,16 +254,19 @@ static PRThread* pt_AttachThread(void) + /* PR_NEWZAP must not call PR_GetCurrentThread() */ + thred = PR_NEWZAP(PRThread); + if (NULL != thred) + { + int rv; + + thred->priority = PR_PRIORITY_NORMAL; + thred->id = pthread_self(); ++#ifdef _PR_NICE_PRIORITY_SCHEDULING ++ thred->tid = gettid(); ++#endif + rv = pthread_setspecific(pt_book.key, thred); + PR_ASSERT(0 == rv); + + thred->state = PT_THREAD_GLOBAL | PT_THREAD_FOREIGN; + PR_Lock(pt_book.ml); + + /* then put it into the list */ + thred->prev = pt_book.last; +@@ -639,16 +677,31 @@ PR_IMPLEMENT(void) PR_SetThreadPriority( + pt_schedpriv = EPERM; + PR_LOG(_pr_thread_lm, PR_LOG_MIN, + ("PR_SetThreadPriority: no thread scheduling privilege")); + } + } + if (rv != 0) + rv = -1; + } ++#elif defined(_PR_NICE_PRIORITY_SCHEDULING) ++ PR_Lock(pt_book.ml); ++ while (thred->tid == 0) ++ PR_WaitCondVar(pt_book.cv, PR_INTERVAL_NO_TIMEOUT); ++ PR_Unlock(pt_book.ml); ++ ++ rv = setpriority(PRIO_PROCESS, thred->tid, pt_PriorityMap(newPri)); ++ ++ if (rv == -1 && errno == EPERM) ++ { ++ /* We don't set pt_schedpriv to EPERM because adjusting the nice ++ * value might be permitted for certain ranges but not others */ ++ PR_LOG(_pr_thread_lm, PR_LOG_MIN, ++ ("PR_SetThreadPriority: no thread scheduling privilege")); ++ } + #endif + + thred->priority = newPri; + } /* PR_SetThreadPriority */ + + PR_IMPLEMENT(PRStatus) PR_Interrupt(PRThread *thred) + { + /* +@@ -857,16 +910,19 @@ void _PR_InitThreads( + pt_book.cv = PR_NewCondVar(pt_book.ml); + PR_ASSERT(NULL != pt_book.cv); + thred = PR_NEWZAP(PRThread); + PR_ASSERT(NULL != thred); + thred->arg = NULL; + thred->startFunc = NULL; + thred->priority = priority; + thred->id = pthread_self(); ++#ifdef _PR_NICE_PRIORITY_SCHEDULING ++ thred->tid = gettid(); ++#endif + + thred->state = (PT_THREAD_DETACHED | PT_THREAD_PRIMORD); + if (PR_SYSTEM_THREAD == type) + { + thred->state |= PT_THREAD_SYSTEM; + pt_book.system += 1; + pt_book.this_many = 0; + }
--- a/nsprpub/pr/include/private/primpl.h +++ b/nsprpub/pr/include/private/primpl.h @@ -45,16 +45,20 @@ typedef struct PRSegment PRSegment; #include "obsolete/probslet.h" #ifdef _PR_HAVE_POSIX_SEMAPHORES #include <semaphore.h> #elif defined(_PR_HAVE_SYSV_SEMAPHORES) #include <sys/sem.h> #endif +#ifdef HAVE_SYSCALL +#include <sys/syscall.h> +#endif + /************************************************************************* ***** A Word about Model Dependent Function Naming Convention *********** *************************************************************************/ /* NSPR 2.0 must implement its function across a range of platforms including: MAC, Windows/16, Windows/95, Windows/NT, and several variants of Unix. Each implementation shares common code as well @@ -181,16 +185,27 @@ typedef struct PTDebug PRUintn cvars_created, cvars_destroyed; PRUintn cvars_notified, delayed_cv_deletes; } PTDebug; #endif /* defined(DEBUG) */ NSPR_API(void) PT_FPrintStats(PRFileDesc *fd, const char *msg); +/* + * On Linux and its derivatives POSIX priority scheduling works only for + * real-time threads. On those platforms we set thread's nice values + * instead which requires us to track kernel thread IDs for each POSIX + * thread we create. + */ +#if defined(LINUX) && defined(HAVE_SETPRIORITY) && \ + ((defined(HAVE_SYSCALL) && defined(SYS_gettid)) || defined(HAVE_GETTID)) +#define _PR_NICE_PRIORITY_SCHEDULING +#endif + #else /* defined(_PR_PTHREADS) */ NSPR_API(void) PT_FPrintStats(PRFileDesc *fd, const char *msg); /* ** This section is contains those parts needed to implement NSPR on ** platforms in general. One would assume that the pthreads implementation ** included lots of the same types, at least conceptually. @@ -1535,16 +1550,19 @@ struct PRThread { PRInt32 osErrorCode; /* mapping of errorCode | zero */ PRIntn errorStringLength; /* textLength from last call to PR_SetErrorText() */ PRInt32 errorStringSize; /* malloc()'d size of buffer | zero */ char *errorString; /* current error string | NULL */ char *name; /* thread's name */ #if defined(_PR_PTHREADS) pthread_t id; /* pthread identifier for the thread */ +#ifdef _PR_NICE_PRIORITY_SCHEDULING + pid_t tid; /* Linux-specific kernel thread ID */ +#endif PRBool okToDelete; /* ok to delete the PRThread struct? */ PRCondVar *waiting; /* where the thread is waiting | NULL */ void *sp; /* recorded sp for garbage collection */ PRThread *next, *prev; /* simple linked list of all threads */ PRUint32 suspend; /* used to store suspend and resume flags */ #ifdef PT_NO_SIGTIMEDWAIT pthread_mutex_t suspendResumeMutex; pthread_cond_t suspendResumeCV;
--- a/nsprpub/pr/src/pthreads/ptthread.c +++ b/nsprpub/pr/src/pthreads/ptthread.c @@ -23,16 +23,24 @@ #ifdef SYMBIAN /* In Open C sched_get_priority_min/max do not work properly, so we undefine * _POSIX_THREAD_PRIORITY_SCHEDULING here. */ #undef _POSIX_THREAD_PRIORITY_SCHEDULING #endif +#ifdef _PR_NICE_PRIORITY_SCHEDULING +#undef _POSIX_THREAD_PRIORITY_SCHEDULING +#include <sys/resource.h> +#ifndef HAVE_GETTID +#define gettid() (syscall(SYS_gettid)) +#endif +#endif + /* * Record whether or not we have the privilege to set the scheduling * policy and priority of threads. 0 means that privilege is available. * EPERM means that privilege is not available. */ static PRIntn pt_schedpriv = 0; extern PRLock *_pr_sleeplock; @@ -49,26 +57,35 @@ static struct _PT_Bookeeping PRInt32 minPrio, maxPrio; /* range of scheduling priorities */ #endif } pt_book = {0}; static void _pt_thread_death(void *arg); static void _pt_thread_death_internal(void *arg, PRBool callDestructors); static void init_pthread_gc_support(void); -#if defined(_PR_DCETHREADS) || defined(_POSIX_THREAD_PRIORITY_SCHEDULING) +#if defined(_PR_DCETHREADS) || \ + defined(_POSIX_THREAD_PRIORITY_SCHEDULING) || \ + defined(_PR_NICE_PRIORITY_SCHEDULING) static PRIntn pt_PriorityMap(PRThreadPriority pri) { #ifdef NTO /* This priority algorithm causes lots of problems on Neutrino * for now I have just hard coded everything to run at priority 10 * until I can come up with a new algorithm. * Jerry.Kirk@Nexwarecorp.com */ return 10; +#elif defined(_PR_NICE_PRIORITY_SCHEDULING) + /* This maps high priorities to low nice values: + * PR_PRIORITY_LOW 1 + * PR_PRIORITY_NORMAL 0 + * PR_PRIORITY_HIGH -1 + * PR_PRIORITY_URGENT -2 */ + return 1 - pri; #else return pt_book.minPrio + pri * (pt_book.maxPrio - pt_book.minPrio) / PR_PRIORITY_LAST; #endif } #endif /* @@ -93,28 +110,46 @@ static void _PR_InitializeStack(PRThread } } static void *_pt_root(void *arg) { PRIntn rv; PRThread *thred = (PRThread*)arg; PRBool detached = (thred->state & PT_THREAD_DETACHED) ? PR_TRUE : PR_FALSE; +#ifdef _PR_NICE_PRIORITY_SCHEDULING + pid_t tid; +#endif /* * Both the parent thread and this new thread set thred->id. * The new thread must ensure that thred->id is set before * it executes its startFunc. The parent thread must ensure * that thred->id is set before PR_CreateThread() returns. * Both threads set thred->id without holding a lock. Since * they are writing the same value, this unprotected double * write should be safe. */ thred->id = pthread_self(); +#ifdef _PR_NICE_PRIORITY_SCHEDULING + /* + * We need to know the kernel thread ID of each thread in order to + * set its priority hence we do it here instead of at creation time. + */ + tid = gettid(); + + rv = setpriority(PRIO_PROCESS, tid, pt_PriorityMap(thred->priority)); + + PR_Lock(pt_book.ml); + thred->tid = tid; + PR_NotifyAllCondVar(pt_book.cv); + PR_Unlock(pt_book.ml); +#endif + /* ** DCE Threads can't detach during creation, so do it late. ** I would like to do it only here, but that doesn't seem ** to work. */ #if defined(_PR_DCETHREADS) if (detached) { @@ -219,16 +254,19 @@ static PRThread* pt_AttachThread(void) /* PR_NEWZAP must not call PR_GetCurrentThread() */ thred = PR_NEWZAP(PRThread); if (NULL != thred) { int rv; thred->priority = PR_PRIORITY_NORMAL; thred->id = pthread_self(); +#ifdef _PR_NICE_PRIORITY_SCHEDULING + thred->tid = gettid(); +#endif rv = pthread_setspecific(pt_book.key, thred); PR_ASSERT(0 == rv); thred->state = PT_THREAD_GLOBAL | PT_THREAD_FOREIGN; PR_Lock(pt_book.ml); /* then put it into the list */ thred->prev = pt_book.last; @@ -639,16 +677,31 @@ PR_IMPLEMENT(void) PR_SetThreadPriority( pt_schedpriv = EPERM; PR_LOG(_pr_thread_lm, PR_LOG_MIN, ("PR_SetThreadPriority: no thread scheduling privilege")); } } if (rv != 0) rv = -1; } +#elif defined(_PR_NICE_PRIORITY_SCHEDULING) + PR_Lock(pt_book.ml); + while (thred->tid == 0) + PR_WaitCondVar(pt_book.cv, PR_INTERVAL_NO_TIMEOUT); + PR_Unlock(pt_book.ml); + + rv = setpriority(PRIO_PROCESS, thred->tid, pt_PriorityMap(newPri)); + + if (rv == -1 && errno == EPERM) + { + /* We don't set pt_schedpriv to EPERM because adjusting the nice + * value might be permitted for certain ranges but not others */ + PR_LOG(_pr_thread_lm, PR_LOG_MIN, + ("PR_SetThreadPriority: no thread scheduling privilege")); + } #endif thred->priority = newPri; } /* PR_SetThreadPriority */ PR_IMPLEMENT(PRStatus) PR_Interrupt(PRThread *thred) { /* @@ -857,16 +910,19 @@ void _PR_InitThreads( pt_book.cv = PR_NewCondVar(pt_book.ml); PR_ASSERT(NULL != pt_book.cv); thred = PR_NEWZAP(PRThread); PR_ASSERT(NULL != thred); thred->arg = NULL; thred->startFunc = NULL; thred->priority = priority; thred->id = pthread_self(); +#ifdef _PR_NICE_PRIORITY_SCHEDULING + thred->tid = gettid(); +#endif thred->state = (PT_THREAD_DETACHED | PT_THREAD_PRIMORD); if (PR_SYSTEM_THREAD == type) { thred->state |= PT_THREAD_SYSTEM; pt_book.system += 1; pt_book.this_many = 0; }