blob: 451c85dc0b6989f2d6a3603833ee2bbf840f20fd [file] [log] [blame]
// Copyright 2016 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "starboard/shared/pthread/thread_create_priority.h"
#include <sched.h>
#include <sys/resource.h>
#include "starboard/log.h"
namespace starboard {
namespace shared {
namespace pthread {
#if SB_HAS(THREAD_PRIORITY_SUPPORT)
// Note that use of sched_setscheduler() has been found to be more reliably
// supported than pthread_setschedparam(), so we are using that.
void SetIdleScheduler() {
struct sched_param thread_sched_param;
thread_sched_param.sched_priority = 0;
int result = sched_setscheduler(0, SCHED_IDLE, &thread_sched_param);
if (result != 0) {
SB_NOTREACHED();
}
}
void SetOtherScheduler() {
struct sched_param thread_sched_param;
thread_sched_param.sched_priority = 0;
int result = sched_setscheduler(0, SCHED_OTHER, &thread_sched_param);
if (result != 0) {
SB_NOTREACHED();
}
}
// Here |priority| is a number between >= 0, where the higher the number, the
// higher the priority. The actual real time priority setting will be:
//
// std::min(sched_get_priority_min(SCHED_RR) + priority,
// sched_get_priority_max(SCHED_RR))
//
// If the desired priority is not supported on this platform, we fall back to
// SCHED_OTHER.
void SetRoundRobinScheduler(int priority) {
// First determine what the system has setup for the min/max priorities.
int min_priority = sched_get_priority_min(SCHED_RR);
int max_priority = sched_get_priority_max(SCHED_RR);
struct rlimit rlimit_rtprio;
getrlimit(RLIMIT_RTPRIO, &rlimit_rtprio);
if (rlimit_rtprio.rlim_cur < min_priority) {
SB_LOG(WARNING) << "Unable to set real time round-robin thread priority "
<< "because `ulimit -r` is too low ("
<< rlimit_rtprio.rlim_cur << " < " << min_priority << ").";
// Fallback to SCHED_OTHER.
SetOtherScheduler();
} else {
struct sched_param thread_sched_param;
thread_sched_param.sched_priority =
std::min(min_priority + priority, max_priority);
int result = sched_setscheduler(0, SCHED_RR, &thread_sched_param);
if (result != 0) {
SB_NOTREACHED();
}
}
}
void ThreadSetPriority(SbThreadPriority priority) {
// Use different schedulers according to priority. This is preferred over
// using SCHED_RR for all threads because the scheduler time slice is too
// high (defaults to 100ms) for the desired threading behavior.
switch (priority) {
case kSbThreadPriorityLowest:
case kSbThreadPriorityLow:
SetIdleScheduler();
break;
case kSbThreadNoPriority:
case kSbThreadPriorityNormal:
SetOtherScheduler();
break;
case kSbThreadPriorityHigh:
SetRoundRobinScheduler(0);
break;
case kSbThreadPriorityHighest:
SetRoundRobinScheduler(1);
break;
case kSbThreadPriorityRealTime:
SetRoundRobinScheduler(2);
break;
default:
SB_NOTREACHED();
break;
}
}
#endif // SB_HAS(THREAD_PRIORITY_SUPPORT)
} // namespace pthread
} // namespace shared
} // namespace starboard