Skip to content

Commit

Permalink
Merge pull request #853 from leapmotion/ref-setthreadpriority
Browse files Browse the repository at this point in the history
Make `SetThreadPriority` protected
  • Loading branch information
hham committed Feb 27, 2016
2 parents 70dcf56 + 59fef82 commit e4bce73
Show file tree
Hide file tree
Showing 5 changed files with 71 additions and 52 deletions.
92 changes: 47 additions & 45 deletions src/autowiring/BasicThread.h
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,48 @@ class BasicThread:
BasicThread(const char* pName = nullptr);
virtual ~BasicThread(void);

/// \internal Only implemented on Windows (as of 0.4.1).
/// <summary>
/// Boosts thread priority while an instance of this type exists.
/// </summary>
/// <remarks>
/// The thread priority is changed when the requested priority is higher than the
/// current priority. The destructor automatically restores the previous priority.
/// This class cannot be moved or copied, in order to guarantee proper RAII.
/// </remarks>
class ElevatePriority {
public:
/// Creating an ElevatePriority object as a member of a BasicThread instance
/// elevates the priority of the thread if the specified priority is higher
/// then the current thread priority. Destroy this ElevatePriority instance
/// to restore the normal thread priority.
ElevatePriority(ElevatePriority&) = delete;

/// Elevates the priority of a BasicThread instance if the specified priority is higher
/// then the current thread priority. Destroy this ElevatePriority instance
/// to restore the normal thread priority.
ElevatePriority(BasicThread& thread, ThreadPriority priority) :
m_oldPriority(thread.m_priority),
m_thread(thread)
{
// Elevate if the new level is higher than the old level:
if (priority > m_oldPriority)
m_thread.SetThreadPriority(priority);
}

/// Destroying this object returns the thread to its previous priority
/// level.
~ElevatePriority(void) {
// Delevate if the old level is lower than the current level:
if (m_thread.m_priority > m_oldPriority)
m_thread.SetThreadPriority(m_oldPriority);
}

private:
ThreadPriority m_oldPriority;
BasicThread& m_thread;
};

protected:
// Internally held thread status block. This has to be a shared pointer because we need to signal
// the held state condition after releasing all shared pointers to ourselves, and this could mean
Expand Down Expand Up @@ -97,8 +139,6 @@ class BasicThread:
/// </remarks>
void SetCurrentThreadName(void) const;

private:
/// Only implemented on Windows (as of version 0.4.1).
/// <summary>
/// Sets the thread priority of this thread
/// </summary>
Expand All @@ -108,7 +148,6 @@ class BasicThread:
/// </remarks>
void SetThreadPriority(ThreadPriority threadPriority);

protected:
/// <summary>
/// Recovers a general lock used to synchronize entities in this thread internally.
/// </summary>
Expand All @@ -135,48 +174,6 @@ class BasicThread:
/// <param name="refTracker">A reference tracker held for as long as the cleanup operation is incomplete</param>
virtual void DoRunLoopCleanup(std::shared_ptr<CoreContext>&& ctxt, std::shared_ptr<CoreObject>&& refTracker);

/// \internal Only implemented on Windows (as of 0.4.1).
/// <summary>
/// Boosts thread priority while an instance of this type exists.
/// </summary>
/// <remarks>
/// The thread priority is changed when the requested priority is higher than the
/// current priority. The destructor automatically restores the previous priority.
/// This class cannot be moved or copied, in order to guarantee proper RAII.
/// </remarks>
class ElevatePriority {
public:
/// Creating an ElevatePriority object as a member of a BasicThread instance
/// elevates the priority of the thread if the specified priority is higher
/// then the current thread priority. Destroy this ElevatePriority instance
/// to restore the normal thread priority.
ElevatePriority(ElevatePriority&) = delete;

/// Elevates the priority of a BasicThread instance if the specified priority is higher
/// then the current thread priority. Destroy this ElevatePriority instance
/// to restore the normal thread priority.
ElevatePriority(BasicThread& thread, ThreadPriority priority) :
m_oldPriority(thread.m_priority),
m_thread(thread)
{
// Elevate if the new level is higher than the old level:
if(priority > m_oldPriority)
m_thread.SetThreadPriority(priority);
}

/// Destroying this object returns the thread to its previous priority
/// level.
~ElevatePriority(void) {
// Delevate if the old level is lower than the current level:
if(m_thread.m_priority > m_oldPriority)
m_thread.SetThreadPriority(m_oldPriority);
}

private:
ThreadPriority m_oldPriority;
BasicThread& m_thread;
};

/// <summary>
/// Waits until the specified lambda function returns true or the thread shuts down.
/// </summary>
Expand Down Expand Up @@ -208,6 +205,11 @@ class BasicThread:
bool DoAdditionalWait(std::chrono::nanoseconds timeout) override;

public:
/// <returns>
/// The current thread priority
/// </returns>
ThreadPriority GetThreadPriority(void) const { return m_priority; }

/// <returns>
/// True if this thread has transitioned to a completed state
/// </returns>
Expand Down
9 changes: 6 additions & 3 deletions src/autowiring/CoreThreadLinux.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ void BasicThread::GetThreadTimes(std::chrono::milliseconds& kernelTime, std::chr

void BasicThread::SetThreadPriority(ThreadPriority threadPriority) {
struct sched_param param = { 0 };
int policy = SCHED_RR;
int policy = SCHED_OTHER;
int percent = 0;
int min_priority;

Expand All @@ -46,6 +46,7 @@ void BasicThread::SetThreadPriority(ThreadPriority threadPriority) {
case ThreadPriority::BelowNormal:
percent = 20;
break;
case ThreadPriority::Default:
case ThreadPriority::Normal:
percent = 50;
break;
Expand All @@ -56,13 +57,15 @@ void BasicThread::SetThreadPriority(ThreadPriority threadPriority) {
percent = 83;
break;
case ThreadPriority::TimeCritical:
case ThreadPriority::Multimedia:
percent = 100;
break;
default:
throw std::runtime_error("Attempted to assign an unrecognized thread priority");
throw std::invalid_argument("Attempted to assign an unrecognized thread priority");
}
min_priority = sched_get_priority_min(policy);
pthread_getschedparam(m_state->m_thisThread.native_handle(), &policy, &param);
param.sched_priority = min_priority + (percent * (sched_get_priority_max(policy) - min_priority) + 50) / 100;

pthread_setschedparam(m_state->m_thisThread.native_handle(), policy, &param);
m_priority = threadPriority;
}
9 changes: 6 additions & 3 deletions src/autowiring/CoreThreadMac.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ void BasicThread::GetThreadTimes(std::chrono::milliseconds& kernelTime, std::chr

void BasicThread::SetThreadPriority(ThreadPriority threadPriority) {
struct sched_param param = { 0 };
int policy = SCHED_RR;
int policy = SCHED_OTHER;
int percent = 0;

switch (threadPriority) {
Expand All @@ -68,6 +68,7 @@ void BasicThread::SetThreadPriority(ThreadPriority threadPriority) {
percent = 20;
break;
case ThreadPriority::Normal:
case ThreadPriority::Default:
percent = 50;
break;
case ThreadPriority::AboveNormal:
Expand All @@ -77,12 +78,14 @@ void BasicThread::SetThreadPriority(ThreadPriority threadPriority) {
percent = 83;
break;
case ThreadPriority::TimeCritical:
case ThreadPriority::Multimedia:
percent = 100;
break;
default:
throw std::runtime_error("Attempted to assign an unrecognized thread priority");
throw std::invalid_argument("Attempted to assign an unrecognized thread priority");
}
pthread_getschedparam(m_state->m_thisThread.native_handle(), &policy, &param);
param.sched_priority = PTHREAD_MIN_PRIORITY + (percent*(PTHREAD_MAX_PRIORITY - PTHREAD_MIN_PRIORITY) + 50) / 100;

pthread_setschedparam(m_state->m_thisThread.native_handle(), policy, &param);
m_priority = threadPriority;
}
4 changes: 3 additions & 1 deletion src/autowiring/CoreThreadWin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ void BasicThread::SetThreadPriority(ThreadPriority threadPriority) {
nPriority = THREAD_PRIORITY_BELOW_NORMAL;
break;
case ThreadPriority::Normal:
case ThreadPriority::Default:
nPriority = THREAD_PRIORITY_NORMAL;
break;
case ThreadPriority::AboveNormal:
Expand All @@ -93,13 +94,14 @@ void BasicThread::SetThreadPriority(ThreadPriority threadPriority) {
nPriority = THREAD_PRIORITY_TIME_CRITICAL;
break;
default:
throw std::runtime_error("Attempted to assign an unrecognized thread priority");
throw std::invalid_argument("Attempted to assign an unrecognized thread priority");
}

::SetThreadPriority(
m_state->m_thisThread.native_handle(),
nPriority
);
m_priority = threadPriority;
}

std::chrono::steady_clock::time_point BasicThread::GetCreationTime(void) {
Expand Down
9 changes: 9 additions & 0 deletions src/autowiring/test/CoreThreadTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -635,3 +635,12 @@ TEST_F(CoreThreadTest, LambdaHoldAfterTermination) {
}
ASSERT_TRUE(childWeak.expired()) << "Child context leaked due to lambda pending in teardown";
}

TEST_F(CoreThreadTest, CanElevateAnyPriority) {
AutoRequired<CoreThread> ct;

for (int i = (int)ThreadPriority::Default; i < (int)ThreadPriority::Multimedia; i++) {
BasicThread::ElevatePriority ep{ *ct, (ThreadPriority)i };
ASSERT_EQ((ThreadPriority)i, ct->GetThreadPriority());
}
}

0 comments on commit e4bce73

Please sign in to comment.