diff --git a/chrony.texi.in b/chrony.texi.in index 50cccfc..30b429a 100644 --- a/chrony.texi.in +++ b/chrony.texi.in @@ -1039,9 +1039,11 @@ not correct the clock. This option displays @code{chronyd's} version number to the terminal and exits. @item -P -This option will select the SCHED_FIFO real-time scheduler at the -specified priority (which must be between 0 and 100). This mode is -supported only on Linux. +On Linux, this option will select the SCHED_FIFO real-time scheduler at the +specified priority (which must be between 0 and 100). On Mac OS X, this option +must have either a value of 0 (the default) to disable the thread time +constraint policy or 1 for the policy to be enabled. Other systems do not +support this option. @item -m This option will lock chronyd into RAM so that it will never be paged out. This mode is only supported on Linux. @@ -2910,13 +2912,15 @@ is used. @node sched_priority directive @subsection sched_priority -The @code{sched_priority} directive will select the SCHED_FIFO real-time -scheduler at the specified priority (which must be between 0 and 100). -This mode is supported only on Linux. +On Linux, the @code{sched_priority} directive will select the SCHED_FIFO +real-time scheduler at the specified priority (which must be between 0 and +100). On Mac OS X, this option must have either a value of 0 (the default) to +disable the thread time constraint policy or 1 for the policy to be enabled. +Other systems do not support this option. -This directive uses the Linux sched_setscheduler() system call to -instruct the kernel to use the SCHED_FIFO first-in, first-out -real-time scheduling policy for @code{chronyd} with the specified priority. +On Linux, this directive uses the sched_setscheduler() system call to instruct +the kernel to use the SCHED_FIFO first-in, first-out real-time scheduling +policy for @code{chronyd} with the specified priority. This means that whenever @code{chronyd} is ready to run it will run, interrupting whatever else is running unless it is a higher priority real-time process. This should not impact performance as @code{chronyd's} @@ -2924,6 +2928,10 @@ resource requirements are modest, but it should result in lower and more consistent latency since @code{chronyd} will not need to wait for the scheduler to get around to running it. You should not use this unless you really need it. The sched_setscheduler man page has more details. + +On Mac OS X, this directive uses the thread_policy_set() kernel call to specify +real-time scheduling. As noted for Linux, you should not use this directive +unless you really need it. @c }}} @c {{{ server @node server directive diff --git a/chronyd.8.in b/chronyd.8.in index 387ea21..954bfdd 100644 --- a/chronyd.8.in +++ b/chronyd.8.in @@ -40,9 +40,11 @@ A summary of the options supported by \fBchronyd\fR is included below. .TP \fB\-P\fR \fIpriority\fR -This option will select the SCHED_FIFO real-time scheduler at the specified -priority (which must be between 0 and 100). This mode is supported only on -Linux. +On Linux, this option will select the SCHED_FIFO real-time scheduler at the +specified priority (which must be between 0 and 100). On Mac OS X, this +option must have either a value of 0 (the default) to disable the thread +time constraint policy or 1 for the policy to be enabled. Other systems do not +support this option. .TP .B \-m This option will lock chronyd into RAM so that it will never be paged out. diff --git a/sys.c b/sys.c index 918db4b..94fc217 100644 --- a/sys.c +++ b/sys.c @@ -126,6 +126,8 @@ void SYS_SetScheduler(int SchedPriority) { #if defined(LINUX) && defined(HAVE_SCHED_SETSCHEDULER) SYS_Linux_SetScheduler(SchedPriority); +#elif defined(MACOSX) + SYS_MacOSX_SetScheduler(SchedPriority); #else LOG_FATAL(LOGF_Sys, "scheduler priority setting not supported"); #endif diff --git a/sys_macosx.c b/sys_macosx.c index 33da60d..503f8f1 100644 --- a/sys_macosx.c +++ b/sys_macosx.c @@ -42,6 +42,10 @@ #include #include +#include +#include +#include + #include "sys_macosx.h" #include "localp.h" #include "sched.h" @@ -85,6 +89,8 @@ static struct timeval Tdrift; /* minimum resolution of current_frequency */ #define FREQUENCY_RES (1.0e-9) +#define NANOS_PER_MSEC (1000000ULL) + /* ================================================== */ static void @@ -334,6 +340,53 @@ drift_removal_timeout(SCH_ArbitraryArgument not_used) drift_removal_id = SCH_AddTimeoutByDelay(drift_removal_interval, drift_removal_timeout, NULL); } +/* ================================================== */ +/* + Give chronyd real time priority so that time critical calculations + are not pre-empted by the kernel. +*/ + +static int +set_realtime(void) +{ + /* https://developer.apple.com/library/ios/technotes/tn2169/_index.html */ + + mach_timebase_info_data_t timebase_info; + double clock2abs; + thread_time_constraint_policy_data_t policy; + int kr; + + mach_timebase_info(&timebase_info); + clock2abs = ((double)timebase_info.denom / (double)timebase_info.numer) * NANOS_PER_MSEC; + + policy.period = 0; + policy.computation = (uint32_t)(5 * clock2abs); /* 5 ms of work */ + policy.constraint = (uint32_t)(10 * clock2abs); + policy.preemptible = 0; + + kr = thread_policy_set( + pthread_mach_thread_np(pthread_self()), + THREAD_TIME_CONSTRAINT_POLICY, + (thread_policy_t)&policy, + THREAD_TIME_CONSTRAINT_POLICY_COUNT); + + if (kr != KERN_SUCCESS) { + LOG(LOGS_WARN, LOGF_SysMacOSX, "Cannot set real-time priority: %d", kr); + return -1; + } + return 0; +} + +/* ================================================== */ + +void +SYS_MacOSX_SetScheduler(int SchedPriority) +{ + if (SchedPriority) { + set_realtime(); + } +} + /* ================================================== */ void diff --git a/sys_macosx.h b/sys_macosx.h index b579415..707700d 100644 --- a/sys_macosx.h +++ b/sys_macosx.h @@ -30,8 +30,8 @@ #ifndef GOT_SYS_MACOSX_H #define GOT_SYS_MACOSX_H +void SYS_MacOSX_SetScheduler(int SchedPriority); void SYS_MacOSX_Initialise(void); - void SYS_MacOSX_Finalise(void); #endif