static int signal_handler(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata) { sd_event_source *p = NULL; sigset_t ss; pid_t pid; assert_se(s); assert_se(si); log_info("got signal on %c", PTR_TO_INT(userdata)); assert_se(userdata == INT_TO_PTR('e')); assert_se(sigemptyset(&ss) >= 0); assert_se(sigaddset(&ss, SIGCHLD) >= 0); assert_se(sigprocmask(SIG_BLOCK, &ss, NULL) >= 0); pid = fork(); assert_se(pid >= 0); if (pid == 0) _exit(0); assert_se(sd_event_add_child(sd_event_source_get_event(s), &p, pid, WEXITED, child_handler, INT_TO_PTR('f')) >= 0); assert_se(sd_event_source_set_enabled(p, SD_EVENT_ONESHOT) >= 0); sd_event_source_unref(s); return 1; }
static int sntp_arm_timer(SNTPContext *sntp, usec_t next) { sd_event *e; int r; assert(sntp); assert(sntp->event_receive); if (next == 0) { sntp->event_timer = sd_event_source_unref(sntp->event_timer); return 0; } if (sntp->event_timer) { r = sd_event_source_set_time(sntp->event_timer, now(CLOCK_MONOTONIC) + next); if (r < 0) return r; return sd_event_source_set_enabled(sntp->event_timer, SD_EVENT_ONESHOT); } e = sd_event_source_get_event(sntp->event_receive); r = sd_event_add_time( e, &sntp->event_timer, CLOCK_MONOTONIC, now(CLOCK_MONOTONIC) + next, 0, sntp_timer, sntp); if (r < 0) return r; return 0; }
static int on_lldp_timer(sd_event_source *s, usec_t t, void *userdata) { Link *link = userdata; usec_t current, delay, next; int r; assert(s); assert(userdata); log_link_debug(link, "Sending LLDP packet..."); r = link_send_lldp(link); if (r < 0) log_link_debug_errno(link, r, "Failed to send LLDP packet, ignoring: %m"); if (link->lldp_tx_fast > 0) link->lldp_tx_fast--; assert_se(sd_event_now(sd_event_source_get_event(s), clock_boottime_or_monotonic(), ¤t) >= 0); delay = link->lldp_tx_fast > 0 ? LLDP_FAST_TX_USEC : LLDP_TX_INTERVAL_USEC; next = usec_add(usec_add(current, delay), (usec_t) random_u64() % LLDP_JITTER_USEC); r = sd_event_source_set_time(s, next); if (r < 0) return log_link_error_errno(link, r, "Failed to restart LLDP timer: %m"); r = sd_event_source_set_enabled(s, SD_EVENT_ONESHOT); if (r < 0) return log_link_error_errno(link, r, "Failed to enable LLDP timer: %m"); return 0; }
static int timerfd_handler(sd_event_source *s, int fd, uint32_t revents, void *userdata) { ClockState *sp = userdata; return clock_state_update(sp, sd_event_source_get_event(s)); }
static int child_handler(sd_event_source *s, const siginfo_t *si, void *userdata) { assert_se(s); assert_se(si); log_info("got child on %c", PTR_TO_INT(userdata)); assert_se(userdata == INT_TO_PTR('f')); assert_se(sd_event_exit(sd_event_source_get_event(s), 0) >= 0); sd_event_source_unref(s); return 1; }
static int time_handler(sd_event_source *s, uint64_t usec, void *userdata) { log_info("got timer on %c", PTR_TO_INT(userdata)); if (userdata == INT_TO_PTR('c')) { if (do_quit) { sd_event_source *p; assert_se(sd_event_add_defer(sd_event_source_get_event(s), &p, defer_handler, INT_TO_PTR('d')) >= 0); assert_se(sd_event_source_set_enabled(p, SD_EVENT_ONESHOT) >= 0); } else { assert_se(!got_c); got_c = true; } } else assert_not_reached("Huh?"); return 2; }
static int defer_handler(sd_event_source *s, void *userdata) { sd_event_source *p = NULL; assert_se(s); log_info("got defer on %c", PTR_TO_INT(userdata)); assert_se(userdata == INT_TO_PTR('d')); assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGUSR1, -1) >= 0); assert_se(sd_event_add_signal(sd_event_source_get_event(s), &p, SIGUSR1, signal_handler, INT_TO_PTR('e')) >= 0); assert_se(sd_event_source_set_enabled(p, SD_EVENT_ONESHOT) >= 0); raise(SIGUSR1); sd_event_source_unref(s); return 1; }
static int inotify_handler(sd_event_source *s, int fd, uint32_t revents, void *userdata) { sd_event *event = sd_event_source_get_event(s); ClockState *sp = userdata; union inotify_event_buffer buffer; struct inotify_event *e; ssize_t l; l = read(fd, &buffer, sizeof(buffer)); if (l < 0) { if (IN_SET(errno, EAGAIN, EINTR)) return 0; return log_warning_errno(errno, "Lost access to inotify: %m"); } FOREACH_INOTIFY_EVENT(e, buffer, l) process_inotify_event(event, sp, e); return 0; }
/* wake up when the system time changes underneath us */ static int sntp_clock_watch_setup(SNTPContext *sntp) { struct itimerspec its = { .it_value.tv_sec = TIME_T_MAX }; _cleanup_close_ int fd = -1; sd_event *e; sd_event_source *source; int r; assert(sntp); assert(sntp->event_receive); fd = timerfd_create(CLOCK_REALTIME, TFD_NONBLOCK|TFD_CLOEXEC); if (fd < 0) { log_error("Failed to create timerfd: %m"); return -errno; } if (timerfd_settime(fd, TFD_TIMER_ABSTIME|TFD_TIMER_CANCEL_ON_SET, &its, NULL) < 0) { log_error("Failed to set up timerfd: %m"); return -errno; } e = sd_event_source_get_event(sntp->event_receive); r = sd_event_add_io(e, &source, fd, EPOLLIN, sntp_clock_watch, sntp); if (r < 0) { log_error("Failed to create clock watch event source: %s", strerror(-r)); return r; } sd_event_source_unref(sntp->event_clock_watch); sntp->event_clock_watch = source; if (sntp->clock_watch_fd >= 0) close(sntp->clock_watch_fd); sntp->clock_watch_fd = fd; fd = -1; return 0; } static int sntp_adjust_clock(SNTPContext *sntp, double offset, int leap_sec) { struct timex tmx = {}; int r; /* * For small deltas, tell the kernel to gradually adjust the system * clock to the NTP time, larger deltas are just directly set. * * Clear STA_UNSYNC, it will enable the kernel's 11-minute mode, which * syncs the system time periodically to the hardware clock. */ if (offset < NTP_MAX_ADJUST && offset > -NTP_MAX_ADJUST) { tmx.modes |= ADJ_STATUS | ADJ_OFFSET | ADJ_TIMECONST | ADJ_MAXERROR | ADJ_ESTERROR; tmx.status = STA_PLL; tmx.offset = offset * 1000 * 1000; tmx.constant = log2i(sntp->poll_interval_usec / USEC_PER_SEC) - 6; tmx.maxerror = 0; tmx.esterror = 0; log_debug(" adjust (slew): %+f sec\n", (double)tmx.offset / USEC_PER_SEC); } else { tmx.modes = ADJ_SETOFFSET; d_to_tv(offset, &tmx.time); sntp->jumped = true; log_debug(" adjust (jump): %+f sec\n", tv_to_d(&tmx.time)); } switch (leap_sec) { case 1: tmx.status |= STA_INS; break; case -1: tmx.status |= STA_DEL; break; } r = clock_adjtime(CLOCK_REALTIME, &tmx); if (r < 0) return r; log_debug(" status : %04i %s\n" " time now : %li.%06li\n" " constant : %li\n" " offset : %+f sec\n" " freq offset : %+li (%+.3f ppm)\n", tmx.status, tmx.status & STA_UNSYNC ? "" : "sync", tmx.time.tv_sec, tmx.time.tv_usec, tmx.constant, (double)tmx.offset / USEC_PER_SEC, tmx.freq, (double)tmx.freq / 65536); return 0; } static bool sntp_sample_spike_detection(SNTPContext *sntp, double offset, double delay) { unsigned int i, idx_cur, idx_new, idx_min; double jitter; double j; /* store the current data in our samples array */ idx_cur = sntp->samples_idx; idx_new = (idx_cur + 1) % ELEMENTSOF(sntp->samples); sntp->samples_idx = idx_new; sntp->samples[idx_new].offset = offset; sntp->samples[idx_new].delay = delay; sntp->packet_count++; jitter = sntp->samples_jitter; /* calculate new jitter value from the RMS differences relative to the lowest delay sample */ for (idx_min = idx_cur, i = 0; i < ELEMENTSOF(sntp->samples); i++) if (sntp->samples[i].delay > 0 && sntp->samples[i].delay < sntp->samples[idx_min].delay) idx_min = i; j = 0; for (i = 0; i < ELEMENTSOF(sntp->samples); i++) j += square(sntp->samples[i].offset - sntp->samples[idx_min].offset); sntp->samples_jitter = sqrt(j / (ELEMENTSOF(sntp->samples) - 1)); /* ignore samples when resyncing */ if (sntp->poll_resync) return false; /* always accept offset if we are farther off than the round-trip delay */ if (fabs(offset) > delay) return false; /* we need a few samples before looking at them */ if (sntp->packet_count < 4) return false; /* do not accept anything worse than the maximum possible error of the best sample */ if (fabs(offset) > sntp->samples[idx_min].delay) return true; /* compare the difference between the current offset to the previous offset and jitter */ return fabs(offset - sntp->samples[idx_cur].offset) > 3 * jitter; }
static int interrupt_signal_handler(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata) { log_notice("Transfer aborted."); sd_event_exit(sd_event_source_get_event(s), EINTR); return 0; }