to work well, it relies on @code{chronyd} having been able to determine
accurate statistics for the difference between the real time clock and
system clock last time the computer was on.
-
@item -u <user>
When this option is used, chronyd will drop root privileges to the specified
user. So far, it works only on Linux when compiled with capabilities support.
@item -v
This option displays @code{chronyd's} version number to the terminal and
exits.
+@item -P <priority>
+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.
+@item -m
+This option will lock chronyd into RAM so that it will never be paged
+out. This mode is only supported on Linux.
@end table
On systems that support an @file{/etc/rc.local} file for starting
* rtcfile directive:: Specify the file where real-time clock data is stored
* rtconutc directive:: Specify that the real time clock keeps UTC not local time
* server directive:: Specify an NTP server
+* sched_priority directive:: Require real-time scheduling and specify a priority for it.
+* lock_all directive:: Require that chronyd be locked into RAM.
+
@end menu
@c }}}
@c {{{ comments in config file
to keep UTC. The directive takes no arguments. It is equivalent to
specifying the @code{-u} switch to the Linux @file{/sbin/clock} program.
@c }}}
+@c {{{ sched_priority
+@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.
+
+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 Chronyd with the specified priority.
+This means that whenever 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 Chronyd's
+resource requirements are modest, but it should result in lower and
+more consistent latency since 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.
+@c }}}
+@c {{{ lock_all
+@node lock_all directive
+@subsection lock_all
+
+The @code{lock_all} directive will lock chronyd into RAM so that it
+will never be paged out. This mode is only supported on Linux. This
+directive uses the Linux mlockall() system call to prevent Chronyd
+from ever being swapped out. This should result in lower and more
+consistent latency. It should not have significant impact on
+performance as Chronyd's memory usage is modest. The mlockall man
+page has more details.
+@c }}}
@c {{{ server
@node server directive
@subsection server
chronyc's @code{online} (@pxref{online command}) command when the link has been
established, to enable measurements to start.)
+@item sched_priority
+This directive tells chronyd to use the real-time FIFO scheduler with the
+specified priority (which must be between 0 and 100). This should result
+in reduced latency. You don't need it unless you really have a requirement
+for extreme clock stability. Works only on Linux. Note that the "-P"
+command-line switch will override this.
+
+@item lock_all
+This directive tells chronyd to use the mlockall() syscall to lock itself
+into RAM so that it will never be paged out. This should result in reduced
+latency. You don't need it unless you really have a requirement
+for extreme clock stability. Works only on Linux. Note that the "-m"
+command-line switch will also enable this feature.
+
@end table
@c }}}
@c }}}
.SH OPTIONS
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.
+.TP
+.B \-m
+This option will lock chronyd into RAM so that it will never be paged out.
+This mode is only supported on Linux.
.TP
.B \-d
When run in this mode, the program will not detach itself from the
static void parse_linux_hz(const char *);
static void parse_linux_freq_scale(const char *);
+#if defined(HAVE_SCHED_SETSCHEDULER)
+static void parse_sched_priority(const char *);
+#endif
+
+#if defined(HAVE_MLOCKALL)
+static void parse_lockall(const char *);
+#endif
+
/* ================================================== */
/* Configuration variables */
{"broadcast", 9, parse_broadcast},
{"linux_hz", 8, parse_linux_hz},
{"linux_freq_scale", 16, parse_linux_freq_scale}
+#if defined(HAVE_SCHED_SETSCHEDULER)
+ ,{"sched_priority", 14, parse_sched_priority}
+#endif
+
+#if defined(HAVE_MLOCKALL)
+ ,{"lock_all", 8, parse_lockall}
+#endif
+
};
static int n_commands = (sizeof(commands) / sizeof(commands[0]));
/* ================================================== */
+#if defined(HAVE_SCHED_SETSCHEDULER)
+static void
+parse_sched_priority(const char *line)
+{
+ if (SchedPriority == 0) { /* Command-line switch must have priority */
+ sscanf(line, "%d", &SchedPriority);
+ }
+}
+#endif
+
+#if defined(HAVE_MLOCKALL)
+static void
+parse_lockall(const char *line)
+{
+ LockAll = 1;
+}
+#endif
+
+/* ================================================== */
+
static void
parse_server(const char *line)
{
extern void CNF_SetupAccessRestrictions(void);
+#if defined(HAVE_SCHED_SETSCHEDULER)
+extern int SchedPriority;
+#endif
+
+#if defined(HAVE_MLOCKALL)
+extern int LockAll;
+#endif
+
#endif /* GOT_CONF_H */
EXTRA_DEFS+=" -DFEAT_LINUXCAPS=1"
EXTRA_LIBS="-lcap"
fi
- SYSDEFS="-DLINUX"
+ SYSDEFS="-DLINUX -DHAVE_SCHED_SETSCHEDULER -DHAVE_MLOCKALL"
echo "Configuring for " $SYSTEM
if [ "${MACHINE}" = "alpha" ]; then
echo "Enabling -mieee"
! rtcdevice /dev/misc/rtc
#######################################################################
+### REAL TIME SCHEDULER
+# This directive tells chronyd to use the real-time FIFO scheduler with the
+# specified priority (which must be between 0 and 100). This should result
+# in reduced latency. You don't need it unless you really have a requirement
+# for extreme clock stability. Works only on Linux. Note that the "-P"
+# command-line switch will override this.
+
+! sched_priority 1
+
+#######################################################################
+### LOCKING CHRONYD INTO RAM
+# This directive tells chronyd to use the mlockall() syscall to lock itself
+# into RAM so that it will never be paged out. This should result in reduced
+# latency. You don't need it unless you really have a requirement
+# for extreme clock stability. Works only on Linux. Note that the "-m"
+# command-line switch will also enable this feature.
+
+! lock_all
=======================================================================
+2009-1-28 John G. Hasler <jhasler@debian.org>
+
+ Added real-time support (Linux only) using sched_setscheduler() and
+ mlockall(). Files affected: main.c, conf.c, sys.c, sys_linux.c,
+ conf.h, configure, chronyd.8, chrony.texi, and
+ examples/chrony.conf.example. The changes are licensed under
+ version 2 of the GPL as described above.
+
+ =======================================================================
+
The main program
*/
int do_init_rtc = 0;
int other_pid;
+#if defined(HAVE_SCHED_SETSCHEDULER)
+ int return_value = 0;
+#endif
+
LOG_Initialise();
/* Parse command line options */
if (!strcmp("-f", *argv)) {
++argv, --argc;
conf_file = *argv;
+
+#if defined(HAVE_SCHED_SETSCHEDULER)
+ /* Get real-time scheduler priority */
+ } else if (!strcmp("-P", *argv)) {
+ ++argv, --argc;
+ return_value = sscanf(*argv, "%d", &SchedPriority);
+ if (return_value != 1 || SchedPriority < 1 || SchedPriority > 99) {
+ SchedPriority = 0;
+ LOG(LOGS_WARN, LOGF_Main, "Bad scheduler priority: [%s]", *argv);
+ }
+#endif /* HAVE_SCHED_SETCHEDULER */
+
+#if defined(HAVE_MLOCKALL)
+ /* Detect lockall switch */
+ } else if (!strcmp("-m", *argv)) {
+ LockAll = 1;
+#endif /* HAVE_MLOCKALL */
+
} else if (!strcmp("-r", *argv)) {
reload = 1;
} else if (!strcmp("-u", *argv)) {
signal(SIGHUP, signal_cleanup);
#endif /* WINNT */
+#if defined(HAVE_SCHED_SETSCHEDULER)
+ if (SchedPriority > 0) {
+ SYS_SetScheduler(SchedPriority);
+ }
+#endif
+
+#if defined(HAVE_MLOCKALL)
+ if (LockAll == 1 ) {
+ SYS_MemLockAll(LockAll);
+ }
+#endif
+
/* The program normally runs under control of the main loop in
the scheduler. */
SCH_MainLoop();
}
/* ================================================== */
+
+void SYS_SetScheduler(int SchedPriority)
+{
+#if defined(LINUX) && defined(HAVE_SCHED_SETSCHEDULER)
+ SYS_Linux_SetScheduler(SchedPriority);
+#endif
+ ;;
+}
+
+void SYS_MemLockAll(int LockAll)
+{
+#if defined(LINUX) && defined(HAVE_MLOCKALL)
+ SYS_Linux_MemLockAll(LockAll);
+#endif
+ ;;
+}
+
/* ================================================== */
/* Drop root privileges to the specified user */
extern void SYS_DropRoot(char *user);
+extern void SYS_SetScheduler(int SchedPriority);
+extern void SYS_MemLockAll(int LockAll);
+
#endif /* GOT_SYS_H */
#include <assert.h>
#include <sys/utsname.h>
+#if defined(HAVE_SCHED_SETSCHEDULER)
+# include <sched.h>
+int SchedPriority = 0;
+#endif
+
+#if defined(HAVE_MLOCKALL)
+# include <sys/mman.h>
+#include <sys/resource.h>
+int LockAll = 0;
+#endif
+
#ifdef FEAT_LINUXCAPS
#include <sys/types.h>
#include <pwd.h>
/* ================================================== */
+#if defined(HAVE_SCHED_SETSCHEDULER)
+ /* Install SCHED_FIFO real-time scheduler with specified priority */
+void SYS_Linux_SetScheduler(int SchedPriority)
+{
+ int pmax, pmin;
+ struct sched_param sched;
+
+ if (SchedPriority > 0) {
+ sched.sched_priority = SchedPriority;
+ pmax = sched_get_priority_max(SCHED_FIFO);
+ pmin = sched_get_priority_min(SCHED_FIFO);
+ if ( SchedPriority > pmax ) {
+ sched.sched_priority = pmax;
+ }
+ else if ( SchedPriority < pmin ) {
+ sched.sched_priority = pmin;
+ }
+ if ( sched_setscheduler(0, SCHED_FIFO, &sched) == -1 ) {
+ LOG(LOGS_ERR, LOGF_SysLinux, "sched_setscheduler() failed");
+ }
+ else {
+ LOG(LOGS_INFO, LOGF_SysLinux, "Enabled SCHED_FIFO with priority %d", sched.sched_priority);
+ }
+ }
+}
+#endif /* HAVE_SCHED_SETSCHEDULER */
+
+#if defined(HAVE_MLOCKALL)
+/* Lock the process into RAM so that it will never be swapped out */
+void SYS_Linux_MemLockAll(int LockAll)
+{
+ struct rlimit rlim;
+ if (LockAll == 1 ) {
+ /* Make sure that we will be able to lock all the memory we need */
+ /* even after dropping privileges. This does not actually reaerve any memory */
+ rlim.rlim_max = RLIM_INFINITY;
+ rlim.rlim_cur = RLIM_INFINITY;
+ if (setrlimit(RLIMIT_MEMLOCK, &rlim) < 0) {
+ LOG(LOGS_ERR, LOGF_SysLinux, "setrlimit() failed: not locking into RAM");
+ }
+ else {
+ if (mlockall(MCL_CURRENT|MCL_FUTURE) < 0) {
+ LOG(LOGS_ERR, LOGF_SysLinux, "mlockall() failed");
+ }
+ else {
+ LOG(LOGS_INFO, LOGF_SysLinux, "Successfully locked into RAM");
+ }
+ }
+ }
+}
+#endif /* HAVE_MLOCKALL */
+
#endif /* LINUX */
/* vim:ts=8
extern void SYS_Linux_DropRoot(char *user);
+extern void SYS_Linux_MemLockAll(int LockAll);
+
+extern void SYS_linux_SetScheduler(int SchedPriority);
+
#endif /* GOT_SYS_LINUX_H */