From 9a61ced717e675fd2b5f016186008538bcb1c25f Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Tue, 11 Mar 2014 16:04:17 +0000 Subject: [PATCH] Correct wxThread::SetPriority() under Unix to hopefully work. The old implementation was completely broken, the new should hopefully work if pthread_setschedparam() behaviour really corresponds to its documentation. Mapping of our priorities in 0..100 range to pthread 1..99 range remains ugly but this seems to be unavoidable, unfortunately. Closes #14985. git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@76116 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- docs/changes.txt | 1 + src/unix/threadpsx.cpp | 75 +++++++++++++++++++++++++++++------------- 2 files changed, 54 insertions(+), 22 deletions(-) diff --git a/docs/changes.txt b/docs/changes.txt index fe1da269a2..f4e8151c9e 100644 --- a/docs/changes.txt +++ b/docs/changes.txt @@ -23,6 +23,7 @@ All: - Allow iterating over wxCmdLineParser arguments in order (Armel Asselin). - Add wxScopedArray ctor taking the number of elements to allocate. - Add wxDynamicLibrary::GetModuleFromAddress() (Luca Bacci). +- Implement wxThread::SetPriority() for pthreads (Luca Bacci). All (GUI): diff --git a/src/unix/threadpsx.cpp b/src/unix/threadpsx.cpp index 643acef269..509cc78c00 100644 --- a/src/unix/threadpsx.cpp +++ b/src/unix/threadpsx.cpp @@ -1364,36 +1364,67 @@ void wxThread::SetPriority(unsigned int prio) case STATE_RUNNING: case STATE_PAUSED: + { #ifdef HAVE_THREAD_PRIORITY_FUNCTIONS -#if defined(__LINUX__) - // On Linux, pthread_setschedparam with SCHED_OTHER does not allow - // a priority other than 0. Instead, we use the BSD setpriority - // which alllows us to set a 'nice' value between 20 to -20. Only - // super user can set a value less than zero (more negative yields - // higher priority). setpriority set the static priority of a - // process, but this is OK since Linux is configured as a thread - // per process. - // - // FIXME this is not true for 2.6!! + // We map our priority values to pthreads scheduling params as + // follows: + // 0..20 to SCHED_IDLE + // 21..40 to SCHED_BATCH + // 41..60 to SCHED_OTHER + // 61..80 to SCHED_RR + // 81..100 to SCHED_FIFO + // + // For the last two, we can also use the additional priority + // parameter which must be in 1..99 range under Linux (TODO: + // what should be used for the other systems?). + struct sched_param sparam = { 0 }; - // map wx priorites 0..100 to Unix priorities 20..-20 - if ( setpriority(PRIO_PROCESS, 0, -(2*(int)prio)/5 + 20) == -1 ) - { - wxLogError(_("Failed to set thread priority %d."), prio); - } -#else // __LINUX__ - { - struct sched_param sparam; - sparam.sched_priority = prio; + // The only scheduling policy guaranteed to be supported + // everywhere is this one. + int policy = SCHED_OTHER; +#ifdef SCHED_IDLE + if ( prio <= 20 ) + policy = SCHED_IDLE; +#endif +#ifdef SCHED_BATCH + if ( 20 < prio && prio <= 40 ) + policy = SCHED_BATCH; +#endif +#ifdef SCHED_RR + if ( 60 < prio && prio <= 80 ) + policy = SCHED_RR; +#endif +#ifdef SCHED_FIFO + if ( 80 < prio ) + policy = SCHED_FIFO; +#endif + + // This test is not redundant as it takes care of the systems + // where neither SCHED_RR nor SCHED_FIFO are defined. + if ( prio > 60 && policy != SCHED_OTHER ) + { + // There is no good way to map our 20 possible priorities + // (61..80 or 81..100) to the 99 pthread priorities, so we + // do the best that we can and ensure that the extremes of + // our range are mapped to the pthread extremes and all the + // rest fall in between. + + // This gets us to 1..96 range. + sparam.sched_priority = ((prio - 61) % 20)*5 + 1; + + // And we artificially increase our highest priority to the + // highest pthread one. + if ( sparam.sched_priority == 96 ) + sparam.sched_priority = 99; + } if ( pthread_setschedparam(m_internal->GetId(), - SCHED_OTHER, &sparam) != 0 ) + policy, &sparam) != 0 ) { wxLogError(_("Failed to set thread priority %d."), prio); } - } -#endif // __LINUX__ #endif // HAVE_THREAD_PRIORITY_FUNCTIONS + } break; case STATE_EXITED: