2 chronyd/chronyc - Programs for keeping computer clocks accurate.
4 **********************************************************************
5 * Copyright (C) Richard P. Curnow 1997-2003
6 * Copyright (C) Miroslav Lichvar 2011, 2013-2016
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of version 2 of the GNU General Public License as
10 * published by the Free Software Foundation.
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
17 * You should have received a copy of the GNU General Public License along
18 * with this program; if not, write to the Free Software Foundation, Inc.,
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21 **********************************************************************
23 =======================================================================
25 This file contains the scheduling loop and the timeout queue.
40 /* ================================================== */
42 /* Flag indicating that we are initialised */
43 static int initialised
= 0;
45 /* ================================================== */
47 /* One more than the highest file descriptor that is registered */
48 static unsigned int one_highest_fd
;
51 /* If FD_SETSIZE is not defined, assume that fd_set is implemented
52 as a fixed size array of bits, possibly embedded inside a record */
53 #define FD_SETSIZE (sizeof(fd_set) * 8)
57 SCH_FileHandler handler
;
58 SCH_ArbitraryArgument arg
;
62 static ARR_Instance file_handlers
;
64 /* Timestamp when last select() returned */
65 static struct timespec last_select_ts
, last_select_ts_raw
;
66 static double last_select_ts_err
;
68 #define TS_MONO_PRECISION_NS 10000000U
70 /* Monotonic low-precision timestamp measuring interval since the start */
71 static double last_select_ts_mono
;
72 static uint32_t last_select_ts_mono_ns
;
74 /* ================================================== */
76 /* Variables to handler the timer queue */
78 typedef struct _TimerQueueEntry
80 struct _TimerQueueEntry
*next
; /* Forward and back links in the list */
81 struct _TimerQueueEntry
*prev
;
82 struct timespec ts
; /* Local system time at which the
83 timeout is to expire. Clearly this
84 must be in terms of what the
85 operating system thinks of as
86 system time, because it will be an
87 argument to select(). Therefore,
88 any fudges etc that our local time
89 driver module would apply to time
90 that we pass to clients etc doesn't
92 SCH_TimeoutID id
; /* ID to allow client to delete
94 SCH_TimeoutClass
class; /* The class that the epoch is in */
95 SCH_TimeoutHandler handler
; /* The handler routine to use */
96 SCH_ArbitraryArgument arg
; /* The argument to pass to the handler */
100 /* The timer queue. We only use the next and prev entries of this
101 record, these chain to the real entries. */
102 static TimerQueueEntry timer_queue
;
103 static unsigned long n_timer_queue_entries
;
104 static SCH_TimeoutID next_tqe_id
;
106 /* Pointer to head of free list */
107 static TimerQueueEntry
*tqe_free_list
= NULL
;
109 /* Timestamp when was last timeout dispatched for each class */
110 static struct timespec last_class_dispatch
[SCH_NumberOfClasses
];
112 /* ================================================== */
114 static int need_to_exit
;
116 /* ================================================== */
119 handle_slew(struct timespec
*raw
,
120 struct timespec
*cooked
,
123 LCL_ChangeType change_type
,
126 /* ================================================== */
131 file_handlers
= ARR_CreateInstance(sizeof (FileHandlerEntry
));
133 n_timer_queue_entries
= 0;
136 timer_queue
.next
= &timer_queue
;
137 timer_queue
.prev
= &timer_queue
;
141 LCL_AddParameterChangeHandler(handle_slew
, NULL
);
143 LCL_ReadRawTime(&last_select_ts_raw
);
144 last_select_ts
= last_select_ts_raw
;
145 last_select_ts_mono
= 0.0;
146 last_select_ts_mono_ns
= 0;
152 /* ================================================== */
156 ARR_DestroyInstance(file_handlers
);
158 LCL_RemoveParameterChangeHandler(handle_slew
, NULL
);
163 /* ================================================== */
167 (int fd
, int events
, SCH_FileHandler handler
, SCH_ArbitraryArgument arg
)
169 FileHandlerEntry
*ptr
;
175 if (fd
>= FD_SETSIZE
)
176 LOG_FATAL("Too many file descriptors");
178 /* Resize the array if the descriptor is highest so far */
179 while (ARR_GetSize(file_handlers
) <= fd
) {
180 ptr
= ARR_GetNewElement(file_handlers
);
186 ptr
= ARR_GetElement(file_handlers
, fd
);
188 /* Don't want to allow the same fd to register a handler more than
189 once without deleting a previous association - this suggests
190 a bug somewhere else in the program. */
191 assert(!ptr
->handler
);
193 ptr
->handler
= handler
;
195 ptr
->events
= events
;
197 if (one_highest_fd
< fd
+ 1)
198 one_highest_fd
= fd
+ 1;
202 /* ================================================== */
205 SCH_RemoveFileHandler(int fd
)
207 FileHandlerEntry
*ptr
;
211 ptr
= ARR_GetElement(file_handlers
, fd
);
213 /* Check that a handler was registered for the fd in question */
214 assert(ptr
->handler
);
220 /* Find new highest file descriptor */
221 while (one_highest_fd
> 0) {
222 ptr
= ARR_GetElement(file_handlers
, one_highest_fd
- 1);
229 /* ================================================== */
232 SCH_SetFileHandlerEvent(int fd
, int event
, int enable
)
234 FileHandlerEntry
*ptr
;
236 ptr
= ARR_GetElement(file_handlers
, fd
);
239 ptr
->events
|= event
;
241 ptr
->events
&= ~event
;
244 /* ================================================== */
247 SCH_GetLastEventTime(struct timespec
*cooked
, double *err
, struct timespec
*raw
)
250 *cooked
= last_select_ts
;
252 *err
= last_select_ts_err
;
255 *raw
= last_select_ts_raw
;
258 /* ================================================== */
261 SCH_GetLastEventMonoTime(void)
263 return last_select_ts_mono
;
266 /* ================================================== */
268 #define TQE_ALLOC_QUANTUM 32
270 static TimerQueueEntry
*
273 TimerQueueEntry
*new_block
;
274 TimerQueueEntry
*result
;
276 if (tqe_free_list
== NULL
) {
277 new_block
= MallocArray(TimerQueueEntry
, TQE_ALLOC_QUANTUM
);
278 for (i
=1; i
<TQE_ALLOC_QUANTUM
; i
++) {
279 new_block
[i
].next
= &(new_block
[i
-1]);
281 new_block
[0].next
= NULL
;
282 tqe_free_list
= &(new_block
[TQE_ALLOC_QUANTUM
- 1]);
285 result
= tqe_free_list
;
286 tqe_free_list
= tqe_free_list
->next
;
290 /* ================================================== */
293 release_tqe(TimerQueueEntry
*node
)
295 node
->next
= tqe_free_list
;
296 tqe_free_list
= node
;
299 /* ================================================== */
304 TimerQueueEntry
*ptr
;
311 /* Make sure the ID isn't already used */
312 for (ptr
= timer_queue
.next
; ptr
!= &timer_queue
; ptr
= ptr
->next
)
313 if (ptr
->id
== next_tqe_id
)
319 /* ================================================== */
322 SCH_AddTimeout(struct timespec
*ts
, SCH_TimeoutHandler handler
, SCH_ArbitraryArgument arg
)
324 TimerQueueEntry
*new_tqe
;
325 TimerQueueEntry
*ptr
;
329 new_tqe
= allocate_tqe();
331 new_tqe
->id
= get_new_tqe_id();
332 new_tqe
->handler
= handler
;
335 new_tqe
->class = SCH_ReservedTimeoutValue
;
337 /* Now work out where to insert the new entry in the list */
338 for (ptr
= timer_queue
.next
; ptr
!= &timer_queue
; ptr
= ptr
->next
) {
339 if (UTI_CompareTimespecs(&new_tqe
->ts
, &ptr
->ts
) == -1) {
340 /* If the new entry comes before the current pointer location in
341 the list, we want to insert the new entry just before ptr. */
346 /* At this stage, we want to insert the new entry immediately before
347 the entry identified by 'ptr' */
350 new_tqe
->prev
= ptr
->prev
;
351 ptr
->prev
->next
= new_tqe
;
354 n_timer_queue_entries
++;
359 /* ================================================== */
360 /* This queues a timeout to elapse at a given delta time relative to
361 the current (raw) time */
364 SCH_AddTimeoutByDelay(double delay
, SCH_TimeoutHandler handler
, SCH_ArbitraryArgument arg
)
366 struct timespec now
, then
;
369 assert(delay
>= 0.0);
371 LCL_ReadRawTime(&now
);
372 UTI_AddDoubleToTimespec(&now
, delay
, &then
);
373 if (UTI_CompareTimespecs(&now
, &then
) > 0) {
374 LOG_FATAL("Timeout overflow");
377 return SCH_AddTimeout(&then
, handler
, arg
);
381 /* ================================================== */
384 SCH_AddTimeoutInClass(double min_delay
, double separation
, double randomness
,
385 SCH_TimeoutClass
class,
386 SCH_TimeoutHandler handler
, SCH_ArbitraryArgument arg
)
388 TimerQueueEntry
*new_tqe
;
389 TimerQueueEntry
*ptr
;
392 double new_min_delay
;
395 assert(min_delay
>= 0.0);
396 assert(class < SCH_NumberOfClasses
);
398 if (randomness
> 0.0) {
401 UTI_GetRandomBytes(&rnd
, sizeof (rnd
));
402 r
= rnd
* (randomness
/ (uint32_t)-1) + 1.0;
407 LCL_ReadRawTime(&now
);
408 new_min_delay
= min_delay
;
410 /* Check the separation from the last dispatched timeout */
411 diff
= UTI_DiffTimespecsToDouble(&now
, &last_class_dispatch
[class]);
412 if (diff
< separation
&& diff
>= 0.0 && diff
+ new_min_delay
< separation
) {
413 new_min_delay
= separation
- diff
;
416 /* Scan through list for entries in the same class and increase min_delay
417 if necessary to keep at least the separation away */
418 for (ptr
= timer_queue
.next
; ptr
!= &timer_queue
; ptr
= ptr
->next
) {
419 if (ptr
->class == class) {
420 diff
= UTI_DiffTimespecsToDouble(&ptr
->ts
, &now
);
421 if (new_min_delay
> diff
) {
422 if (new_min_delay
- diff
< separation
) {
423 new_min_delay
= diff
+ separation
;
426 if (diff
- new_min_delay
< separation
) {
427 new_min_delay
= diff
+ separation
;
433 for (ptr
= timer_queue
.next
; ptr
!= &timer_queue
; ptr
= ptr
->next
) {
434 diff
= UTI_DiffTimespecsToDouble(&ptr
->ts
, &now
);
435 if (diff
> new_min_delay
) {
440 /* We have located the insertion point */
441 new_tqe
= allocate_tqe();
443 new_tqe
->id
= get_new_tqe_id();
444 new_tqe
->handler
= handler
;
446 UTI_AddDoubleToTimespec(&now
, new_min_delay
, &new_tqe
->ts
);
447 new_tqe
->class = class;
450 new_tqe
->prev
= ptr
->prev
;
451 ptr
->prev
->next
= new_tqe
;
453 n_timer_queue_entries
++;
458 /* ================================================== */
461 SCH_RemoveTimeout(SCH_TimeoutID id
)
463 TimerQueueEntry
*ptr
;
470 for (ptr
= timer_queue
.next
; ptr
!= &timer_queue
; ptr
= ptr
->next
) {
473 /* Found the required entry */
475 /* Unlink from the queue */
476 ptr
->next
->prev
= ptr
->prev
;
477 ptr
->prev
->next
= ptr
->next
;
479 /* Decrement entry count */
480 --n_timer_queue_entries
;
482 /* Release memory back to the operating system */
489 /* Catch calls with invalid non-zero ID */
493 /* ================================================== */
498 while (n_timer_queue_entries
> 0)
499 SCH_RemoveTimeout(timer_queue
.next
->id
);
501 while (one_highest_fd
> 0) {
502 close(one_highest_fd
- 1);
503 SCH_RemoveFileHandler(one_highest_fd
- 1);
507 /* ================================================== */
508 /* Try to dispatch any timeouts that have already gone by, and
509 keep going until all are done. (The earlier ones may take so
510 long to do that the later ones come around by the time they are
514 dispatch_timeouts(struct timespec
*now
) {
515 TimerQueueEntry
*ptr
;
516 SCH_TimeoutHandler handler
;
517 SCH_ArbitraryArgument arg
;
518 int n_done
= 0, n_entries_on_start
= n_timer_queue_entries
;
521 LCL_ReadRawTime(now
);
523 if (!(n_timer_queue_entries
> 0 &&
524 UTI_CompareTimespecs(now
, &timer_queue
.next
->ts
) >= 0)) {
528 ptr
= timer_queue
.next
;
530 last_class_dispatch
[ptr
->class] = *now
;
532 handler
= ptr
->handler
;
535 SCH_RemoveTimeout(ptr
->id
);
537 /* Dispatch the handler */
540 /* Increment count of timeouts handled */
543 /* If more timeouts were handled than there were in the timer queue on
544 start and there are now, assume some code is scheduling timeouts with
545 negative delays and abort. Make the actual limit higher in case the
546 machine is temporarily overloaded and dispatching the handlers takes
547 more time than was delay of a scheduled timeout. */
548 if (n_done
> n_timer_queue_entries
* 4 &&
549 n_done
> n_entries_on_start
* 4) {
550 LOG_FATAL("Possible infinite loop in scheduling");
555 /* ================================================== */
557 /* nfd is the number of bits set in all fd_sets */
560 dispatch_filehandlers(int nfd
, fd_set
*read_fds
, fd_set
*write_fds
, fd_set
*except_fds
)
562 FileHandlerEntry
*ptr
;
565 for (fd
= 0; nfd
&& fd
< one_highest_fd
; fd
++) {
566 if (except_fds
&& FD_ISSET(fd
, except_fds
)) {
567 /* This descriptor has an exception, dispatch its handler */
568 ptr
= (FileHandlerEntry
*)ARR_GetElement(file_handlers
, fd
);
570 (ptr
->handler
)(fd
, SCH_FILE_EXCEPTION
, ptr
->arg
);
573 /* Don't try to read from it now */
574 if (read_fds
&& FD_ISSET(fd
, read_fds
)) {
575 FD_CLR(fd
, read_fds
);
580 if (read_fds
&& FD_ISSET(fd
, read_fds
)) {
581 /* This descriptor can be read from, dispatch its handler */
582 ptr
= (FileHandlerEntry
*)ARR_GetElement(file_handlers
, fd
);
584 (ptr
->handler
)(fd
, SCH_FILE_INPUT
, ptr
->arg
);
588 if (write_fds
&& FD_ISSET(fd
, write_fds
)) {
589 /* This descriptor can be written to, dispatch its handler */
590 ptr
= (FileHandlerEntry
*)ARR_GetElement(file_handlers
, fd
);
592 (ptr
->handler
)(fd
, SCH_FILE_OUTPUT
, ptr
->arg
);
598 /* ================================================== */
601 handle_slew(struct timespec
*raw
,
602 struct timespec
*cooked
,
605 LCL_ChangeType change_type
,
608 TimerQueueEntry
*ptr
;
612 if (change_type
!= LCL_ChangeAdjust
) {
613 /* Make sure this handler is invoked first in order to not shift new timers
614 added from other handlers */
615 assert(LCL_IsFirstParameterChangeHandler(handle_slew
));
617 /* If a step change occurs, just shift all raw time stamps by the offset */
619 for (ptr
= timer_queue
.next
; ptr
!= &timer_queue
; ptr
= ptr
->next
) {
620 UTI_AddDoubleToTimespec(&ptr
->ts
, -doffset
, &ptr
->ts
);
623 for (i
= 0; i
< SCH_NumberOfClasses
; i
++) {
624 UTI_AddDoubleToTimespec(&last_class_dispatch
[i
], -doffset
, &last_class_dispatch
[i
]);
627 UTI_AddDoubleToTimespec(&last_select_ts_raw
, -doffset
, &last_select_ts_raw
);
630 UTI_AdjustTimespec(&last_select_ts
, cooked
, &last_select_ts
, &delta
, dfreq
, doffset
);
633 /* ================================================== */
636 fill_fd_sets(fd_set
**read_fds
, fd_set
**write_fds
, fd_set
**except_fds
)
638 FileHandlerEntry
*handlers
;
639 fd_set
*rd
, *wr
, *ex
;
642 n
= ARR_GetSize(file_handlers
);
643 handlers
= ARR_GetElements(file_handlers
);
646 for (i
= 0; i
< n
; i
++) {
647 events
= handlers
[i
].events
;
652 if (events
& SCH_FILE_INPUT
) {
660 if (events
& SCH_FILE_OUTPUT
) {
668 if (events
& SCH_FILE_EXCEPTION
) {
685 /* ================================================== */
687 #define JUMP_DETECT_THRESHOLD 10
690 check_current_time(struct timespec
*prev_raw
, struct timespec
*raw
, int timeout
,
691 struct timeval
*orig_select_tv
,
692 struct timeval
*rem_select_tv
)
694 struct timespec elapsed_min
, elapsed_max
, orig_select_ts
, rem_select_ts
;
695 double step
, elapsed
;
697 UTI_TimevalToTimespec(orig_select_tv
, &orig_select_ts
);
699 /* Get an estimate of the time spent waiting in the select() call. On some
700 systems (e.g. Linux) the timeout timeval is modified to return the
701 remaining time, use that information. */
703 elapsed_max
= elapsed_min
= orig_select_ts
;
704 } else if (rem_select_tv
&& rem_select_tv
->tv_sec
>= 0 &&
705 rem_select_tv
->tv_sec
<= orig_select_tv
->tv_sec
&&
706 (rem_select_tv
->tv_sec
!= orig_select_tv
->tv_sec
||
707 rem_select_tv
->tv_usec
!= orig_select_tv
->tv_usec
)) {
708 UTI_TimevalToTimespec(rem_select_tv
, &rem_select_ts
);
709 UTI_DiffTimespecs(&elapsed_min
, &orig_select_ts
, &rem_select_ts
);
710 elapsed_max
= elapsed_min
;
713 elapsed_max
= orig_select_ts
;
715 UTI_DiffTimespecs(&elapsed_max
, raw
, prev_raw
);
716 UTI_ZeroTimespec(&elapsed_min
);
719 if (last_select_ts_raw
.tv_sec
+ elapsed_min
.tv_sec
>
720 raw
->tv_sec
+ JUMP_DETECT_THRESHOLD
) {
721 LOG(LOGS_WARN
, "Backward time jump detected!");
722 } else if (prev_raw
->tv_sec
+ elapsed_max
.tv_sec
+ JUMP_DETECT_THRESHOLD
<
724 LOG(LOGS_WARN
, "Forward time jump detected!");
729 step
= UTI_DiffTimespecsToDouble(&last_select_ts_raw
, raw
);
730 elapsed
= UTI_TimespecToDouble(&elapsed_min
);
733 /* Cooked time may no longer be valid after dispatching the handlers */
734 LCL_NotifyExternalTimeStep(raw
, raw
, step
, fabs(step
));
739 /* ================================================== */
742 update_monotonic_time(struct timespec
*now
, struct timespec
*before
)
744 struct timespec diff
;
746 /* Avoid frequent floating-point operations and handle small
747 increments to a large value */
749 UTI_DiffTimespecs(&diff
, now
, before
);
750 if (diff
.tv_sec
== 0) {
751 last_select_ts_mono_ns
+= diff
.tv_nsec
;
753 last_select_ts_mono
+= fabs(UTI_TimespecToDouble(&diff
) +
754 last_select_ts_mono_ns
/ 1.0e9
);
755 last_select_ts_mono_ns
= 0;
758 if (last_select_ts_mono_ns
> TS_MONO_PRECISION_NS
) {
759 last_select_ts_mono
+= last_select_ts_mono_ns
/ 1.0e9
;
760 last_select_ts_mono_ns
= 0;
764 /* ================================================== */
769 fd_set read_fds
, write_fds
, except_fds
;
770 fd_set
*p_read_fds
, *p_write_fds
, *p_except_fds
;
772 struct timeval tv
, saved_tv
, *ptv
;
773 struct timespec ts
, now
, saved_now
, cooked
;
778 while (!need_to_exit
) {
779 /* Dispatch timeouts and fill now with current raw time */
780 dispatch_timeouts(&now
);
783 /* The timeout handlers may request quit */
787 /* Check whether there is a timeout and set it up */
788 if (n_timer_queue_entries
> 0) {
789 UTI_DiffTimespecs(&ts
, &timer_queue
.next
->ts
, &now
);
790 assert(ts
.tv_sec
> 0 || ts
.tv_nsec
> 0);
792 UTI_TimespecToTimeval(&ts
, &tv
);
797 saved_tv
.tv_sec
= saved_tv
.tv_usec
= 0;
800 p_read_fds
= &read_fds
;
801 p_write_fds
= &write_fds
;
802 p_except_fds
= &except_fds
;
803 fill_fd_sets(&p_read_fds
, &p_write_fds
, &p_except_fds
);
805 /* if there are no file descriptors being waited on and no
806 timeout set, this is clearly ridiculous, so stop the run */
807 if (!ptv
&& !p_read_fds
&& !p_write_fds
)
808 LOG_FATAL("Nothing to do");
810 status
= select(one_highest_fd
, p_read_fds
, p_write_fds
, p_except_fds
, ptv
);
813 LCL_ReadRawTime(&now
);
814 LCL_CookTime(&now
, &cooked
, &err
);
816 /* Check if the time didn't jump unexpectedly */
817 if (!check_current_time(&saved_now
, &now
, status
== 0, &saved_tv
, ptv
)) {
818 /* Cook the time again after handling the step */
819 LCL_CookTime(&now
, &cooked
, &err
);
822 update_monotonic_time(&cooked
, &last_select_ts
);
824 last_select_ts_raw
= now
;
825 last_select_ts
= cooked
;
826 last_select_ts_err
= err
;
829 if (!need_to_exit
&& errsv
!= EINTR
) {
830 LOG_FATAL("select() failed : %s", strerror(errsv
));
832 } else if (status
> 0) {
833 /* A file descriptor is ready for input or output */
834 dispatch_filehandlers(status
, p_read_fds
, p_write_fds
, p_except_fds
);
836 /* No descriptors readable, timeout must have elapsed.
837 Therefore, tv must be non-null */
840 /* There's nothing to do here, since the timeouts
841 will be dispatched at the top of the next loop
848 /* ================================================== */
851 SCH_QuitProgram(void)
856 /* ================================================== */