sd-event.c revision ec202eae8e84a4c99f054f771cb832046cb8769f
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering/***
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering This file is part of systemd.
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering Copyright 2013 Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering systemd is free software; you can redistribute it and/or modify it
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering under the terms of the GNU Lesser General Public License as published by
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering the Free Software Foundation; either version 2.1 of the License, or
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering (at your option) any later version.
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering systemd is distributed in the hope that it will be useful, but
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering Lesser General Public License for more details.
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering You should have received a copy of the GNU Lesser General Public License
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering***/
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering#include <sys/epoll.h>
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering#include <sys/timerfd.h>
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering#include <sys/wait.h>
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
adacb9575a09981fcf11279f2f661e3fc21e58ffLennart Poettering#include "sd-id128.h"
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering#include "sd-daemon.h"
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering#include "macro.h"
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering#include "prioq.h"
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering#include "hashmap.h"
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering#include "util.h"
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering#include "time-util.h"
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering#include "missing.h"
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering#include "sd-event.h"
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering#define EPOLL_QUEUE_MAX 512U
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering#define DEFAULT_ACCURACY_USEC (250 * USEC_PER_MSEC)
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
718db96199eb307751264e4163555662c9a389faLennart Poetteringtypedef enum EventSourceType {
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering SOURCE_IO,
23c80348e656a4e6fd9ba8f17523a65b6fa349a0Kay Sievers SOURCE_MONOTONIC,
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering SOURCE_REALTIME,
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering SOURCE_SIGNAL,
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering SOURCE_CHILD,
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering SOURCE_DEFER,
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering SOURCE_EXIT,
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering SOURCE_WATCHDOG
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering} EventSourceType;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poetteringstruct sd_event_source {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering unsigned n_ref;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering sd_event *event;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering void *userdata;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering sd_event_handler_t prepare;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering EventSourceType type:4;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering int enabled:3;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering bool pending:1;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering bool dispatching:1;
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering int priority;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering unsigned pending_index;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering unsigned prepare_index;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering unsigned pending_iteration;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering unsigned prepare_iteration;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering union {
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering struct {
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering sd_event_io_handler_t callback;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering int fd;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering uint32_t events;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering uint32_t revents;
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering bool registered:1;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering } io;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering struct {
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering sd_event_time_handler_t callback;
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering usec_t next, accuracy;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering unsigned earliest_index;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering unsigned latest_index;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering } time;
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering struct {
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering sd_event_signal_handler_t callback;
df2d202e6ed4001a21c6512c244acad5d4706c87Lennart Poettering struct signalfd_siginfo siginfo;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering int sig;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering } signal;
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering struct {
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering sd_event_child_handler_t callback;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering siginfo_t siginfo;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering pid_t pid;
4e724d9c5ab76c3f8327945317463ef706011082Lennart Poettering int options;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering } child;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering struct {
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering sd_event_handler_t callback;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering } defer;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering struct {
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering sd_event_handler_t callback;
4e724d9c5ab76c3f8327945317463ef706011082Lennart Poettering unsigned prioq_index;
4e724d9c5ab76c3f8327945317463ef706011082Lennart Poettering } exit;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering };
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering};
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poetteringstruct sd_event {
4e724d9c5ab76c3f8327945317463ef706011082Lennart Poettering unsigned n_ref;
5b12334d35eadf1f45cc3d631fd1a2e72ffaea0aLennart Poettering
5b12334d35eadf1f45cc3d631fd1a2e72ffaea0aLennart Poettering int epoll_fd;
5b12334d35eadf1f45cc3d631fd1a2e72ffaea0aLennart Poettering int signal_fd;
5b12334d35eadf1f45cc3d631fd1a2e72ffaea0aLennart Poettering int realtime_fd;
5b12334d35eadf1f45cc3d631fd1a2e72ffaea0aLennart Poettering int monotonic_fd;
5b12334d35eadf1f45cc3d631fd1a2e72ffaea0aLennart Poettering int watchdog_fd;
5b12334d35eadf1f45cc3d631fd1a2e72ffaea0aLennart Poettering
4e724d9c5ab76c3f8327945317463ef706011082Lennart Poettering Prioq *pending;
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering Prioq *prepare;
4e724d9c5ab76c3f8327945317463ef706011082Lennart Poettering
4e724d9c5ab76c3f8327945317463ef706011082Lennart Poettering /* For both clocks we maintain two priority queues each, one
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering * ordered for the earliest times the events may be
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering * dispatched, and one ordered by the latest times they must
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering * have been dispatched. The range between the top entries in
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering * the two prioqs is the time window we can freely schedule
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering * wakeups in */
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering Prioq *monotonic_earliest;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering Prioq *monotonic_latest;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering Prioq *realtime_earliest;
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering Prioq *realtime_latest;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
df2d202e6ed4001a21c6512c244acad5d4706c87Lennart Poettering usec_t realtime_next, monotonic_next;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering usec_t perturb;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering sigset_t sigset;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering sd_event_source **signal_sources;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering Hashmap *child_sources;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering unsigned n_enabled_child_sources;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering Prioq *exit;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering pid_t original_pid;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering unsigned iteration;
df2d202e6ed4001a21c6512c244acad5d4706c87Lennart Poettering dual_timestamp timestamp;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering int state;
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering bool exit_requested:1;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering bool need_process_child:1;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering bool watchdog:1;
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering int exit_code;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering pid_t tid;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering sd_event **default_event_ptr;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering usec_t watchdog_last, watchdog_period;
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering unsigned n_sources;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering};
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poetteringstatic int pending_prioq_compare(const void *a, const void *b) {
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering const sd_event_source *x = a, *y = b;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering assert(x->pending);
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering assert(y->pending);
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering /* Enabled ones first */
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering if (x->enabled != SD_EVENT_OFF && y->enabled == SD_EVENT_OFF)
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering return -1;
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering if (x->enabled == SD_EVENT_OFF && y->enabled != SD_EVENT_OFF)
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering return 1;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering /* Lower priority values first */
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering if (x->priority < y->priority)
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering return -1;
8aec412ff697bc14995746953912ca6fdf2c9ba8Lennart Poettering if (x->priority > y->priority)
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering return 1;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering /* Older entries first */
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (x->pending_iteration < y->pending_iteration)
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering return -1;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (x->pending_iteration > y->pending_iteration)
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering return 1;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering /* Stability for the rest */
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering if (x < y)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return -1;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering if (x > y)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return 1;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering return 0;
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering}
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poetteringstatic int prepare_prioq_compare(const void *a, const void *b) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering const sd_event_source *x = a, *y = b;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering assert(x->prepare);
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering assert(y->prepare);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering /* Move most recently prepared ones last, so that we can stop
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering * preparing as soon as we hit one that has already been
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering * prepared in the current iteration */
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (x->prepare_iteration < y->prepare_iteration)
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering return -1;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (x->prepare_iteration > y->prepare_iteration)
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering return 1;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering /* Enabled ones first */
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (x->enabled != SD_EVENT_OFF && y->enabled == SD_EVENT_OFF)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return -1;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (x->enabled == SD_EVENT_OFF && y->enabled != SD_EVENT_OFF)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return 1;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering /* Lower priority values first */
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering if (x->priority < y->priority)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return -1;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (x->priority > y->priority)
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering return 1;
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering /* Stability for the rest */
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering if (x < y)
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering return -1;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (x > y)
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering return 1;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering return 0;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering}
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
5b12334d35eadf1f45cc3d631fd1a2e72ffaea0aLennart Poetteringstatic int earliest_time_prioq_compare(const void *a, const void *b) {
5b12334d35eadf1f45cc3d631fd1a2e72ffaea0aLennart Poettering const sd_event_source *x = a, *y = b;
5b12334d35eadf1f45cc3d631fd1a2e72ffaea0aLennart Poettering
5b12334d35eadf1f45cc3d631fd1a2e72ffaea0aLennart Poettering assert(x->type == SOURCE_MONOTONIC || x->type == SOURCE_REALTIME);
5b12334d35eadf1f45cc3d631fd1a2e72ffaea0aLennart Poettering assert(y->type == SOURCE_MONOTONIC || y->type == SOURCE_REALTIME);
5b12334d35eadf1f45cc3d631fd1a2e72ffaea0aLennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering /* Enabled ones first */
554604b3073467af75dc94fac9e2343148603289Lennart Poettering if (x->enabled != SD_EVENT_OFF && y->enabled == SD_EVENT_OFF)
5b12334d35eadf1f45cc3d631fd1a2e72ffaea0aLennart Poettering return -1;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering if (x->enabled == SD_EVENT_OFF && y->enabled != SD_EVENT_OFF)
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering return 1;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
554604b3073467af75dc94fac9e2343148603289Lennart Poettering /* Move the pending ones to the end */
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (!x->pending && y->pending)
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering return -1;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (x->pending && !y->pending)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return 1;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering /* Order by time */
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (x->time.next < y->time.next)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return -1;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (x->time.next > y->time.next)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return 1;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering /* Stability for the rest */
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (x < y)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return -1;
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering if (x > y)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return 1;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return 0;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering}
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poetteringstatic int latest_time_prioq_compare(const void *a, const void *b) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering const sd_event_source *x = a, *y = b;
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering assert((x->type == SOURCE_MONOTONIC && y->type == SOURCE_MONOTONIC) ||
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering (x->type == SOURCE_REALTIME && y->type == SOURCE_REALTIME));
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering /* Enabled ones first */
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering if (x->enabled != SD_EVENT_OFF && y->enabled == SD_EVENT_OFF)
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering return -1;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (x->enabled == SD_EVENT_OFF && y->enabled != SD_EVENT_OFF)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return 1;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering /* Move the pending ones to the end */
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering if (!x->pending && y->pending)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return -1;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (x->pending && !y->pending)
a3e7f417d72ba3251fd6b3a228a2721a4b725a03Zbigniew Jędrzejewski-Szmek return 1;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering /* Order by time */
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (x->time.next + x->time.accuracy < y->time.next + y->time.accuracy)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return -1;
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering if (x->time.next + x->time.accuracy > y->time.next + y->time.accuracy)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return 1;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering /* Stability for the rest */
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (x < y)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return -1;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering if (x > y)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return 1;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return 0;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering}
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poetteringstatic int exit_prioq_compare(const void *a, const void *b) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering const sd_event_source *x = a, *y = b;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering assert(x->type == SOURCE_EXIT);
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering assert(y->type == SOURCE_EXIT);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering /* Enabled ones first */
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering if (x->enabled != SD_EVENT_OFF && y->enabled == SD_EVENT_OFF)
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering return -1;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (x->enabled == SD_EVENT_OFF && y->enabled != SD_EVENT_OFF)
df2d202e6ed4001a21c6512c244acad5d4706c87Lennart Poettering return 1;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering /* Lower priority values first */
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering if (x->priority < y->priority)
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering return -1;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering if (x->priority > y->priority)
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering return 1;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering /* Stability for the rest */
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering if (x < y)
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering return -1;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (x > y)
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering return 1;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering return 0;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering}
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poetteringstatic void event_free(sd_event *e) {
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering assert(e);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering assert(e->n_sources == 0);
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering if (e->default_event_ptr)
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering *(e->default_event_ptr) = NULL;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering if (e->epoll_fd >= 0)
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering close_nointr_nofail(e->epoll_fd);
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (e->signal_fd >= 0)
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering close_nointr_nofail(e->signal_fd);
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (e->realtime_fd >= 0)
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering close_nointr_nofail(e->realtime_fd);
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering if (e->monotonic_fd >= 0)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering close_nointr_nofail(e->monotonic_fd);
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering if (e->watchdog_fd >= 0)
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering close_nointr_nofail(e->watchdog_fd);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
df2d202e6ed4001a21c6512c244acad5d4706c87Lennart Poettering prioq_free(e->pending);
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering prioq_free(e->prepare);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering prioq_free(e->monotonic_earliest);
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering prioq_free(e->monotonic_latest);
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering prioq_free(e->realtime_earliest);
adacb9575a09981fcf11279f2f661e3fc21e58ffLennart Poettering prioq_free(e->realtime_latest);
adacb9575a09981fcf11279f2f661e3fc21e58ffLennart Poettering prioq_free(e->exit);
adacb9575a09981fcf11279f2f661e3fc21e58ffLennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering free(e->signal_sources);
adacb9575a09981fcf11279f2f661e3fc21e58ffLennart Poettering
adacb9575a09981fcf11279f2f661e3fc21e58ffLennart Poettering hashmap_free(e->child_sources);
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering free(e);
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering}
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering_public_ int sd_event_new(sd_event** ret) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering sd_event *e;
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering int r;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering assert_return(ret, -EINVAL);
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering e = new0(sd_event, 1);
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering if (!e)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return -ENOMEM;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering e->n_ref = 1;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering e->signal_fd = e->realtime_fd = e->monotonic_fd = e->watchdog_fd = e->epoll_fd = -1;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering e->realtime_next = e->monotonic_next = (usec_t) -1;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering e->original_pid = getpid();
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering assert_se(sigemptyset(&e->sigset) == 0);
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering e->pending = prioq_new(pending_prioq_compare);
6797c324a653f119a3d7133122648aaa4878ddd6Lennart Poettering if (!e->pending) {
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering r = -ENOMEM;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering goto fail;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering }
6797c324a653f119a3d7133122648aaa4878ddd6Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering e->epoll_fd = epoll_create1(EPOLL_CLOEXEC);
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering if (e->epoll_fd < 0) {
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering r = -errno;
6797c324a653f119a3d7133122648aaa4878ddd6Lennart Poettering goto fail;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering }
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering *ret = e;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering return 0;
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering
6797c324a653f119a3d7133122648aaa4878ddd6Lennart Poetteringfail:
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering event_free(e);
6797c324a653f119a3d7133122648aaa4878ddd6Lennart Poettering return r;
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering}
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering_public_ sd_event* sd_event_ref(sd_event *e) {
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering assert_return(e, NULL);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering assert(e->n_ref >= 1);
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering e->n_ref++;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return e;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering}
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering_public_ sd_event* sd_event_unref(sd_event *e) {
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering if (!e)
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering return NULL;
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering
554604b3073467af75dc94fac9e2343148603289Lennart Poettering assert(e->n_ref >= 1);
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering e->n_ref--;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering if (e->n_ref <= 0)
554604b3073467af75dc94fac9e2343148603289Lennart Poettering event_free(e);
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering return NULL;
554604b3073467af75dc94fac9e2343148603289Lennart Poettering}
554604b3073467af75dc94fac9e2343148603289Lennart Poettering
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poetteringstatic bool event_pid_changed(sd_event *e) {
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering assert(e);
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering
554604b3073467af75dc94fac9e2343148603289Lennart Poettering /* We don't support people creating am event loop and keeping
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering * it around over a fork(). Let's complain. */
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering return e->original_pid != getpid();
554604b3073467af75dc94fac9e2343148603289Lennart Poettering}
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poetteringstatic int source_io_unregister(sd_event_source *s) {
554604b3073467af75dc94fac9e2343148603289Lennart Poettering int r;
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering assert(s);
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering assert(s->type == SOURCE_IO);
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering if (!s->io.registered)
554604b3073467af75dc94fac9e2343148603289Lennart Poettering return 0;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering r = epoll_ctl(s->event->epoll_fd, EPOLL_CTL_DEL, s->io.fd, NULL);
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering if (r < 0)
554604b3073467af75dc94fac9e2343148603289Lennart Poettering return -errno;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering s->io.registered = false;
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering return 0;
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering}
554604b3073467af75dc94fac9e2343148603289Lennart Poettering
554604b3073467af75dc94fac9e2343148603289Lennart Poetteringstatic int source_io_register(
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering sd_event_source *s,
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering int enabled,
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering uint32_t events) {
554604b3073467af75dc94fac9e2343148603289Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering struct epoll_event ev = {};
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering int r;
554604b3073467af75dc94fac9e2343148603289Lennart Poettering
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering assert(s);
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering assert(s->type == SOURCE_IO);
a658cafa98ab55ea948c29bc87eb3945d515fb41Lennart Poettering assert(enabled != SD_EVENT_OFF);
a658cafa98ab55ea948c29bc87eb3945d515fb41Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering ev.events = events;
554604b3073467af75dc94fac9e2343148603289Lennart Poettering ev.data.ptr = s;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
554604b3073467af75dc94fac9e2343148603289Lennart Poettering if (enabled == SD_EVENT_ONESHOT)
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering ev.events |= EPOLLONESHOT;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering if (s->io.registered)
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering r = epoll_ctl(s->event->epoll_fd, EPOLL_CTL_MOD, s->io.fd, &ev);
554604b3073467af75dc94fac9e2343148603289Lennart Poettering else
a658cafa98ab55ea948c29bc87eb3945d515fb41Lennart Poettering r = epoll_ctl(s->event->epoll_fd, EPOLL_CTL_ADD, s->io.fd, &ev);
a658cafa98ab55ea948c29bc87eb3945d515fb41Lennart Poettering
554604b3073467af75dc94fac9e2343148603289Lennart Poettering if (r < 0)
a658cafa98ab55ea948c29bc87eb3945d515fb41Lennart Poettering return -errno;
a658cafa98ab55ea948c29bc87eb3945d515fb41Lennart Poettering
554604b3073467af75dc94fac9e2343148603289Lennart Poettering s->io.registered = true;
a658cafa98ab55ea948c29bc87eb3945d515fb41Lennart Poettering
a658cafa98ab55ea948c29bc87eb3945d515fb41Lennart Poettering return 0;
554604b3073467af75dc94fac9e2343148603289Lennart Poettering}
554604b3073467af75dc94fac9e2343148603289Lennart Poettering
554604b3073467af75dc94fac9e2343148603289Lennart Poetteringstatic void source_free(sd_event_source *s) {
554604b3073467af75dc94fac9e2343148603289Lennart Poettering assert(s);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (s->event) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering assert(s->event->n_sources > 0);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering switch (s->type) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering case SOURCE_IO:
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering if (s->io.fd >= 0)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering source_io_unregister(s);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering break;
554604b3073467af75dc94fac9e2343148603289Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering case SOURCE_MONOTONIC:
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering prioq_remove(s->event->monotonic_earliest, s, &s->time.earliest_index);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering prioq_remove(s->event->monotonic_latest, s, &s->time.latest_index);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering break;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering case SOURCE_REALTIME:
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering prioq_remove(s->event->realtime_earliest, s, &s->time.earliest_index);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering prioq_remove(s->event->realtime_latest, s, &s->time.latest_index);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering break;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering case SOURCE_SIGNAL:
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering if (s->signal.sig > 0) {
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering if (s->signal.sig != SIGCHLD || s->event->n_enabled_child_sources == 0)
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering assert_se(sigdelset(&s->event->sigset, s->signal.sig) == 0);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
a658cafa98ab55ea948c29bc87eb3945d515fb41Lennart Poettering if (s->event->signal_sources)
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering s->event->signal_sources[s->signal.sig] = NULL;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering }
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering break;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering case SOURCE_CHILD:
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (s->child.pid > 0) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (s->enabled != SD_EVENT_OFF) {
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering assert(s->event->n_enabled_child_sources > 0);
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering s->event->n_enabled_child_sources--;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering }
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (!s->event->signal_sources || !s->event->signal_sources[SIGCHLD])
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering assert_se(sigdelset(&s->event->sigset, SIGCHLD) == 0);
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering hashmap_remove(s->event->child_sources, INT_TO_PTR(s->child.pid));
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering }
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering break;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering case SOURCE_DEFER:
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering /* nothing */
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering break;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering case SOURCE_EXIT:
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering prioq_remove(s->event->exit, s, &s->exit.prioq_index);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering break;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering case SOURCE_WATCHDOG:
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering assert_not_reached("Wut? I shouldn't exist.");
554604b3073467af75dc94fac9e2343148603289Lennart Poettering }
554604b3073467af75dc94fac9e2343148603289Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering if (s->pending)
554604b3073467af75dc94fac9e2343148603289Lennart Poettering prioq_remove(s->event->pending, s, &s->pending_index);
554604b3073467af75dc94fac9e2343148603289Lennart Poettering
554604b3073467af75dc94fac9e2343148603289Lennart Poettering if (s->prepare)
554604b3073467af75dc94fac9e2343148603289Lennart Poettering prioq_remove(s->event->prepare, s, &s->prepare_index);
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering s->event->n_sources--;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering sd_event_unref(s->event);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering }
86b8d289717bad2800342efca0a5023aa8374e9cLennart Poettering
86b8d289717bad2800342efca0a5023aa8374e9cLennart Poettering free(s);
86b8d289717bad2800342efca0a5023aa8374e9cLennart Poettering}
86b8d289717bad2800342efca0a5023aa8374e9cLennart Poettering
c49b30a23583ff39daaa26696bcab478d2fee0bbLennart Poetteringstatic int source_set_pending(sd_event_source *s, bool b) {
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering int r;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering assert(s);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering assert(s->type != SOURCE_EXIT);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (s->pending == b)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return 0;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering s->pending = b;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (b) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering s->pending_iteration = s->event->iteration;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering r = prioq_put(s->event->pending, s, &s->pending_index);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (r < 0) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering s->pending = false;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return r;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering }
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering } else
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering assert_se(prioq_remove(s->event->pending, s, &s->pending_index));
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering if (s->type == SOURCE_REALTIME) {
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering prioq_reshuffle(s->event->realtime_earliest, s, &s->time.earliest_index);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering prioq_reshuffle(s->event->realtime_latest, s, &s->time.latest_index);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering } else if (s->type == SOURCE_MONOTONIC) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering prioq_reshuffle(s->event->monotonic_earliest, s, &s->time.earliest_index);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering prioq_reshuffle(s->event->monotonic_latest, s, &s->time.latest_index);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering }
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return 0;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering}
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poetteringstatic sd_event_source *source_new(sd_event *e, EventSourceType type) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering sd_event_source *s;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering assert(e);
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering s = new0(sd_event_source, 1);
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering if (!s)
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering return NULL;
6797c324a653f119a3d7133122648aaa4878ddd6Lennart Poettering
6797c324a653f119a3d7133122648aaa4878ddd6Lennart Poettering s->n_ref = 1;
6797c324a653f119a3d7133122648aaa4878ddd6Lennart Poettering s->event = sd_event_ref(e);
6797c324a653f119a3d7133122648aaa4878ddd6Lennart Poettering s->type = type;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering s->pending_index = s->prepare_index = PRIOQ_IDX_NULL;
6797c324a653f119a3d7133122648aaa4878ddd6Lennart Poettering
6797c324a653f119a3d7133122648aaa4878ddd6Lennart Poettering e->n_sources ++;
6797c324a653f119a3d7133122648aaa4878ddd6Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return s;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering}
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering_public_ int sd_event_add_io(
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering sd_event *e,
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering int fd,
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering uint32_t events,
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering sd_event_io_handler_t callback,
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering void *userdata,
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering sd_event_source **ret) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering sd_event_source *s;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering int r;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering assert_return(e, -EINVAL);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering assert_return(fd >= 0, -EINVAL);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering assert_return(!(events & ~(EPOLLIN|EPOLLOUT|EPOLLRDHUP|EPOLLPRI|EPOLLERR|EPOLLHUP|EPOLLET)), -EINVAL);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering assert_return(callback, -EINVAL);
6797c324a653f119a3d7133122648aaa4878ddd6Lennart Poettering assert_return(ret, -EINVAL);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering assert_return(e->state != SD_EVENT_FINISHED, -ESTALE);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering assert_return(!event_pid_changed(e), -ECHILD);
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering s = source_new(e, SOURCE_IO);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (!s)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return -ENOMEM;
a658cafa98ab55ea948c29bc87eb3945d515fb41Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering s->io.fd = fd;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering s->io.events = events;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering s->io.callback = callback;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering s->userdata = userdata;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering s->enabled = SD_EVENT_ON;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
a658cafa98ab55ea948c29bc87eb3945d515fb41Lennart Poettering r = source_io_register(s, s->enabled, events);
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering if (r < 0) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering source_free(s);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return -errno;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering }
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering *ret = s;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return 0;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering}
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poetteringstatic int event_setup_timer_fd(
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering sd_event *e,
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering EventSourceType type,
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering int *timer_fd,
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering clockid_t id) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering struct epoll_event ev = {};
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering int r, fd;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering sd_id128_t bootid;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering assert(e);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering assert(timer_fd);
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering if (_likely_(*timer_fd >= 0))
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return 0;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering fd = timerfd_create(id, TFD_NONBLOCK|TFD_CLOEXEC);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (fd < 0)
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering return -errno;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
6797c324a653f119a3d7133122648aaa4878ddd6Lennart Poettering ev.events = EPOLLIN;
6797c324a653f119a3d7133122648aaa4878ddd6Lennart Poettering ev.data.ptr = INT_TO_PTR(type);
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering r = epoll_ctl(e->epoll_fd, EPOLL_CTL_ADD, fd, &ev);
6797c324a653f119a3d7133122648aaa4878ddd6Lennart Poettering if (r < 0) {
6797c324a653f119a3d7133122648aaa4878ddd6Lennart Poettering close_nointr_nofail(fd);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return -errno;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering }
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering /* When we sleep for longer, we try to realign the wakeup to
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering the same time wihtin each minute/second/250ms, so that
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering events all across the system can be coalesced into a single
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering CPU wakeup. However, let's take some system-specific
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering randomness for this value, so that in a network of systems
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering with synced clocks timer events are distributed a
bd16acf35e13a19cd2ded0a0c2ef774a98f73808Zbigniew Jędrzejewski-Szmek bit. Here, we calculate a perturbation usec offset from the
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering boot ID. */
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering if (sd_id128_get_boot(&bootid) >= 0)
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering e->perturb = (bootid.qwords[0] ^ bootid.qwords[1]) % USEC_PER_MINUTE;
bd16acf35e13a19cd2ded0a0c2ef774a98f73808Zbigniew Jędrzejewski-Szmek
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering *timer_fd = fd;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering return 0;
bd16acf35e13a19cd2ded0a0c2ef774a98f73808Zbigniew Jędrzejewski-Szmek}
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poetteringstatic int event_add_time_internal(
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering sd_event *e,
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering EventSourceType type,
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering int *timer_fd,
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering clockid_t id,
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering Prioq **earliest,
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering Prioq **latest,
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering uint64_t usec,
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering uint64_t accuracy,
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering sd_event_time_handler_t callback,
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering void *userdata,
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering sd_event_source **ret) {
bd16acf35e13a19cd2ded0a0c2ef774a98f73808Zbigniew Jędrzejewski-Szmek
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering sd_event_source *s;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering int r;
bd16acf35e13a19cd2ded0a0c2ef774a98f73808Zbigniew Jędrzejewski-Szmek
bd16acf35e13a19cd2ded0a0c2ef774a98f73808Zbigniew Jędrzejewski-Szmek assert_return(e, -EINVAL);
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering assert_return(callback, -EINVAL);
bd16acf35e13a19cd2ded0a0c2ef774a98f73808Zbigniew Jędrzejewski-Szmek assert_return(ret, -EINVAL);
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering assert_return(usec != (uint64_t) -1, -EINVAL);
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering assert_return(accuracy != (uint64_t) -1, -EINVAL);
bd16acf35e13a19cd2ded0a0c2ef774a98f73808Zbigniew Jędrzejewski-Szmek assert_return(e->state != SD_EVENT_FINISHED, -ESTALE);
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering assert_return(!event_pid_changed(e), -ECHILD);
bd16acf35e13a19cd2ded0a0c2ef774a98f73808Zbigniew Jędrzejewski-Szmek
ab49725fd8587ef2b90dd0a67b2c915bc772d089Kay Sievers assert(timer_fd);
ab49725fd8587ef2b90dd0a67b2c915bc772d089Kay Sievers assert(earliest);
ab49725fd8587ef2b90dd0a67b2c915bc772d089Kay Sievers assert(latest);
ab49725fd8587ef2b90dd0a67b2c915bc772d089Kay Sievers
ab49725fd8587ef2b90dd0a67b2c915bc772d089Kay Sievers if (!*earliest) {
ab49725fd8587ef2b90dd0a67b2c915bc772d089Kay Sievers *earliest = prioq_new(earliest_time_prioq_compare);
ab49725fd8587ef2b90dd0a67b2c915bc772d089Kay Sievers if (!*earliest)
ab49725fd8587ef2b90dd0a67b2c915bc772d089Kay Sievers return -ENOMEM;
ab49725fd8587ef2b90dd0a67b2c915bc772d089Kay Sievers }
ab49725fd8587ef2b90dd0a67b2c915bc772d089Kay Sievers
ab49725fd8587ef2b90dd0a67b2c915bc772d089Kay Sievers if (!*latest) {
ab49725fd8587ef2b90dd0a67b2c915bc772d089Kay Sievers *latest = prioq_new(latest_time_prioq_compare);
ab49725fd8587ef2b90dd0a67b2c915bc772d089Kay Sievers if (!*latest)
ab49725fd8587ef2b90dd0a67b2c915bc772d089Kay Sievers return -ENOMEM;
ab49725fd8587ef2b90dd0a67b2c915bc772d089Kay Sievers }
ab49725fd8587ef2b90dd0a67b2c915bc772d089Kay Sievers
ab49725fd8587ef2b90dd0a67b2c915bc772d089Kay Sievers if (*timer_fd < 0) {
ab49725fd8587ef2b90dd0a67b2c915bc772d089Kay Sievers r = event_setup_timer_fd(e, type, timer_fd, id);
ab49725fd8587ef2b90dd0a67b2c915bc772d089Kay Sievers if (r < 0)
ab49725fd8587ef2b90dd0a67b2c915bc772d089Kay Sievers return r;
ab49725fd8587ef2b90dd0a67b2c915bc772d089Kay Sievers }
ab49725fd8587ef2b90dd0a67b2c915bc772d089Kay Sievers
ab49725fd8587ef2b90dd0a67b2c915bc772d089Kay Sievers s = source_new(e, type);
ab49725fd8587ef2b90dd0a67b2c915bc772d089Kay Sievers if (!s)
ab49725fd8587ef2b90dd0a67b2c915bc772d089Kay Sievers return -ENOMEM;
ab49725fd8587ef2b90dd0a67b2c915bc772d089Kay Sievers
ab49725fd8587ef2b90dd0a67b2c915bc772d089Kay Sievers s->time.next = usec;
ab49725fd8587ef2b90dd0a67b2c915bc772d089Kay Sievers s->time.accuracy = accuracy == 0 ? DEFAULT_ACCURACY_USEC : accuracy;
ab49725fd8587ef2b90dd0a67b2c915bc772d089Kay Sievers s->time.callback = callback;
ab49725fd8587ef2b90dd0a67b2c915bc772d089Kay Sievers s->time.earliest_index = s->time.latest_index = PRIOQ_IDX_NULL;
ab49725fd8587ef2b90dd0a67b2c915bc772d089Kay Sievers s->userdata = userdata;
ab49725fd8587ef2b90dd0a67b2c915bc772d089Kay Sievers s->enabled = SD_EVENT_ONESHOT;
ab49725fd8587ef2b90dd0a67b2c915bc772d089Kay Sievers
ab49725fd8587ef2b90dd0a67b2c915bc772d089Kay Sievers r = prioq_put(*earliest, s, &s->time.earliest_index);
ab49725fd8587ef2b90dd0a67b2c915bc772d089Kay Sievers if (r < 0)
ab49725fd8587ef2b90dd0a67b2c915bc772d089Kay Sievers goto fail;
ab49725fd8587ef2b90dd0a67b2c915bc772d089Kay Sievers
ab49725fd8587ef2b90dd0a67b2c915bc772d089Kay Sievers r = prioq_put(*latest, s, &s->time.latest_index);
ab49725fd8587ef2b90dd0a67b2c915bc772d089Kay Sievers if (r < 0)
ab49725fd8587ef2b90dd0a67b2c915bc772d089Kay Sievers goto fail;
ab49725fd8587ef2b90dd0a67b2c915bc772d089Kay Sievers
*ret = s;
return 0;
fail:
source_free(s);
return r;
}
_public_ int sd_event_add_monotonic(sd_event *e,
uint64_t usec,
uint64_t accuracy,
sd_event_time_handler_t callback,
void *userdata,
sd_event_source **ret) {
return event_add_time_internal(e, SOURCE_MONOTONIC, &e->monotonic_fd, CLOCK_MONOTONIC, &e->monotonic_earliest, &e->monotonic_latest, usec, accuracy, callback, userdata, ret);
}
_public_ int sd_event_add_realtime(sd_event *e,
uint64_t usec,
uint64_t accuracy,
sd_event_time_handler_t callback,
void *userdata,
sd_event_source **ret) {
return event_add_time_internal(e, SOURCE_REALTIME, &e->realtime_fd, CLOCK_REALTIME, &e->realtime_earliest, &e->monotonic_latest, usec, accuracy, callback, userdata, ret);
}
static int event_update_signal_fd(sd_event *e) {
struct epoll_event ev = {};
bool add_to_epoll;
int r;
assert(e);
add_to_epoll = e->signal_fd < 0;
r = signalfd(e->signal_fd, &e->sigset, SFD_NONBLOCK|SFD_CLOEXEC);
if (r < 0)
return -errno;
e->signal_fd = r;
if (!add_to_epoll)
return 0;
ev.events = EPOLLIN;
ev.data.ptr = INT_TO_PTR(SOURCE_SIGNAL);
r = epoll_ctl(e->epoll_fd, EPOLL_CTL_ADD, e->signal_fd, &ev);
if (r < 0) {
close_nointr_nofail(e->signal_fd);
e->signal_fd = -1;
return -errno;
}
return 0;
}
_public_ int sd_event_add_signal(
sd_event *e,
int sig,
sd_event_signal_handler_t callback,
void *userdata,
sd_event_source **ret) {
sd_event_source *s;
int r;
assert_return(e, -EINVAL);
assert_return(sig > 0, -EINVAL);
assert_return(sig < _NSIG, -EINVAL);
assert_return(callback, -EINVAL);
assert_return(ret, -EINVAL);
assert_return(e->state != SD_EVENT_FINISHED, -ESTALE);
assert_return(!event_pid_changed(e), -ECHILD);
if (!e->signal_sources) {
e->signal_sources = new0(sd_event_source*, _NSIG);
if (!e->signal_sources)
return -ENOMEM;
} else if (e->signal_sources[sig])
return -EBUSY;
s = source_new(e, SOURCE_SIGNAL);
if (!s)
return -ENOMEM;
s->signal.sig = sig;
s->signal.callback = callback;
s->userdata = userdata;
s->enabled = SD_EVENT_ON;
e->signal_sources[sig] = s;
assert_se(sigaddset(&e->sigset, sig) == 0);
if (sig != SIGCHLD || e->n_enabled_child_sources == 0) {
r = event_update_signal_fd(e);
if (r < 0) {
source_free(s);
return r;
}
}
*ret = s;
return 0;
}
_public_ int sd_event_add_child(
sd_event *e,
pid_t pid,
int options,
sd_event_child_handler_t callback,
void *userdata,
sd_event_source **ret) {
sd_event_source *s;
int r;
assert_return(e, -EINVAL);
assert_return(pid > 1, -EINVAL);
assert_return(!(options & ~(WEXITED|WSTOPPED|WCONTINUED)), -EINVAL);
assert_return(options != 0, -EINVAL);
assert_return(callback, -EINVAL);
assert_return(ret, -EINVAL);
assert_return(e->state != SD_EVENT_FINISHED, -ESTALE);
assert_return(!event_pid_changed(e), -ECHILD);
r = hashmap_ensure_allocated(&e->child_sources, trivial_hash_func, trivial_compare_func);
if (r < 0)
return r;
if (hashmap_contains(e->child_sources, INT_TO_PTR(pid)))
return -EBUSY;
s = source_new(e, SOURCE_CHILD);
if (!s)
return -ENOMEM;
s->child.pid = pid;
s->child.options = options;
s->child.callback = callback;
s->userdata = userdata;
s->enabled = SD_EVENT_ONESHOT;
r = hashmap_put(e->child_sources, INT_TO_PTR(pid), s);
if (r < 0) {
source_free(s);
return r;
}
e->n_enabled_child_sources ++;
assert_se(sigaddset(&e->sigset, SIGCHLD) == 0);
if (!e->signal_sources || !e->signal_sources[SIGCHLD]) {
r = event_update_signal_fd(e);
if (r < 0) {
source_free(s);
return -errno;
}
}
e->need_process_child = true;
*ret = s;
return 0;
}
_public_ int sd_event_add_defer(
sd_event *e,
sd_event_handler_t callback,
void *userdata,
sd_event_source **ret) {
sd_event_source *s;
int r;
assert_return(e, -EINVAL);
assert_return(callback, -EINVAL);
assert_return(ret, -EINVAL);
assert_return(e->state != SD_EVENT_FINISHED, -ESTALE);
assert_return(!event_pid_changed(e), -ECHILD);
s = source_new(e, SOURCE_DEFER);
if (!s)
return -ENOMEM;
s->defer.callback = callback;
s->userdata = userdata;
s->enabled = SD_EVENT_ONESHOT;
r = source_set_pending(s, true);
if (r < 0) {
source_free(s);
return r;
}
*ret = s;
return 0;
}
_public_ int sd_event_add_exit(
sd_event *e,
sd_event_handler_t callback,
void *userdata,
sd_event_source **ret) {
sd_event_source *s;
int r;
assert_return(e, -EINVAL);
assert_return(callback, -EINVAL);
assert_return(ret, -EINVAL);
assert_return(e->state != SD_EVENT_FINISHED, -ESTALE);
assert_return(!event_pid_changed(e), -ECHILD);
if (!e->exit) {
e->exit = prioq_new(exit_prioq_compare);
if (!e->exit)
return -ENOMEM;
}
s = source_new(e, SOURCE_EXIT);
if (!s)
return -ENOMEM;
s->exit.callback = callback;
s->userdata = userdata;
s->exit.prioq_index = PRIOQ_IDX_NULL;
s->enabled = SD_EVENT_ONESHOT;
r = prioq_put(s->event->exit, s, &s->exit.prioq_index);
if (r < 0) {
source_free(s);
return r;
}
*ret = s;
return 0;
}
_public_ sd_event_source* sd_event_source_ref(sd_event_source *s) {
assert_return(s, NULL);
assert(s->n_ref >= 1);
s->n_ref++;
return s;
}
_public_ sd_event_source* sd_event_source_unref(sd_event_source *s) {
if (!s)
return NULL;
assert(s->n_ref >= 1);
s->n_ref--;
if (s->n_ref <= 0) {
/* Here's a special hack: when we are called from a
* dispatch handler we won't free the event source
* immediately, but we will detach the fd from the
* epoll. This way it is safe for the caller to unref
* the event source and immediately close the fd, but
* we still retain a valid event source object after
* the callback. */
if (s->dispatching) {
if (s->type == SOURCE_IO)
source_io_unregister(s);
} else
source_free(s);
}
return NULL;
}
_public_ sd_event *sd_event_source_get_event(sd_event_source *s) {
assert_return(s, NULL);
return s->event;
}
_public_ int sd_event_source_get_pending(sd_event_source *s) {
assert_return(s, -EINVAL);
assert_return(s->type != SOURCE_EXIT, -EDOM);
assert_return(s->event->state != SD_EVENT_FINISHED, -ESTALE);
assert_return(!event_pid_changed(s->event), -ECHILD);
return s->pending;
}
_public_ int sd_event_source_get_io_fd(sd_event_source *s) {
assert_return(s, -EINVAL);
assert_return(s->type == SOURCE_IO, -EDOM);
assert_return(!event_pid_changed(s->event), -ECHILD);
return s->io.fd;
}
_public_ int sd_event_source_set_io_fd(sd_event_source *s, int fd) {
int r;
assert_return(s, -EINVAL);
assert_return(fd >= 0, -EINVAL);
assert_return(s->type == SOURCE_IO, -EDOM);
assert_return(!event_pid_changed(s->event), -ECHILD);
if (s->io.fd == fd)
return 0;
if (s->enabled == SD_EVENT_OFF) {
s->io.fd = fd;
s->io.registered = false;
} else {
int saved_fd;
saved_fd = s->io.fd;
assert(s->io.registered);
s->io.fd = fd;
s->io.registered = false;
r = source_io_register(s, s->enabled, s->io.events);
if (r < 0) {
s->io.fd = saved_fd;
s->io.registered = true;
return r;
}
epoll_ctl(s->event->epoll_fd, EPOLL_CTL_DEL, saved_fd, NULL);
}
return 0;
}
_public_ int sd_event_source_get_io_events(sd_event_source *s, uint32_t* events) {
assert_return(s, -EINVAL);
assert_return(events, -EINVAL);
assert_return(s->type == SOURCE_IO, -EDOM);
assert_return(!event_pid_changed(s->event), -ECHILD);
*events = s->io.events;
return 0;
}
_public_ int sd_event_source_set_io_events(sd_event_source *s, uint32_t events) {
int r;
assert_return(s, -EINVAL);
assert_return(s->type == SOURCE_IO, -EDOM);
assert_return(!(events & ~(EPOLLIN|EPOLLOUT|EPOLLRDHUP|EPOLLPRI|EPOLLERR|EPOLLHUP|EPOLLET)), -EINVAL);
assert_return(s->event->state != SD_EVENT_FINISHED, -ESTALE);
assert_return(!event_pid_changed(s->event), -ECHILD);
if (s->io.events == events)
return 0;
if (s->enabled != SD_EVENT_OFF) {
r = source_io_register(s, s->enabled, events);
if (r < 0)
return r;
}
s->io.events = events;
source_set_pending(s, false);
return 0;
}
_public_ int sd_event_source_get_io_revents(sd_event_source *s, uint32_t* revents) {
assert_return(s, -EINVAL);
assert_return(revents, -EINVAL);
assert_return(s->type == SOURCE_IO, -EDOM);
assert_return(s->pending, -ENODATA);
assert_return(!event_pid_changed(s->event), -ECHILD);
*revents = s->io.revents;
return 0;
}
_public_ int sd_event_source_get_signal(sd_event_source *s) {
assert_return(s, -EINVAL);
assert_return(s->type == SOURCE_SIGNAL, -EDOM);
assert_return(!event_pid_changed(s->event), -ECHILD);
return s->signal.sig;
}
_public_ int sd_event_source_get_priority(sd_event_source *s, int *priority) {
assert_return(s, -EINVAL);
assert_return(!event_pid_changed(s->event), -ECHILD);
return s->priority;
}
_public_ int sd_event_source_set_priority(sd_event_source *s, int priority) {
assert_return(s, -EINVAL);
assert_return(s->event->state != SD_EVENT_FINISHED, -ESTALE);
assert_return(!event_pid_changed(s->event), -ECHILD);
if (s->priority == priority)
return 0;
s->priority = priority;
if (s->pending)
prioq_reshuffle(s->event->pending, s, &s->pending_index);
if (s->prepare)
prioq_reshuffle(s->event->prepare, s, &s->prepare_index);
if (s->type == SOURCE_EXIT)
prioq_reshuffle(s->event->exit, s, &s->exit.prioq_index);
return 0;
}
_public_ int sd_event_source_get_enabled(sd_event_source *s, int *m) {
assert_return(s, -EINVAL);
assert_return(m, -EINVAL);
assert_return(!event_pid_changed(s->event), -ECHILD);
*m = s->enabled;
return 0;
}
_public_ int sd_event_source_set_enabled(sd_event_source *s, int m) {
int r;
assert_return(s, -EINVAL);
assert_return(m == SD_EVENT_OFF || m == SD_EVENT_ON || m == SD_EVENT_ONESHOT, -EINVAL);
assert_return(s->event->state != SD_EVENT_FINISHED, -ESTALE);
assert_return(!event_pid_changed(s->event), -ECHILD);
if (s->enabled == m)
return 0;
if (m == SD_EVENT_OFF) {
switch (s->type) {
case SOURCE_IO:
r = source_io_unregister(s);
if (r < 0)
return r;
s->enabled = m;
break;
case SOURCE_MONOTONIC:
s->enabled = m;
prioq_reshuffle(s->event->monotonic_earliest, s, &s->time.earliest_index);
prioq_reshuffle(s->event->monotonic_latest, s, &s->time.latest_index);
break;
case SOURCE_REALTIME:
s->enabled = m;
prioq_reshuffle(s->event->realtime_earliest, s, &s->time.earliest_index);
prioq_reshuffle(s->event->realtime_latest, s, &s->time.latest_index);
break;
case SOURCE_SIGNAL:
s->enabled = m;
if (s->signal.sig != SIGCHLD || s->event->n_enabled_child_sources == 0) {
assert_se(sigdelset(&s->event->sigset, s->signal.sig) == 0);
event_update_signal_fd(s->event);
}
break;
case SOURCE_CHILD:
s->enabled = m;
assert(s->event->n_enabled_child_sources > 0);
s->event->n_enabled_child_sources--;
if (!s->event->signal_sources || !s->event->signal_sources[SIGCHLD]) {
assert_se(sigdelset(&s->event->sigset, SIGCHLD) == 0);
event_update_signal_fd(s->event);
}
break;
case SOURCE_EXIT:
s->enabled = m;
prioq_reshuffle(s->event->exit, s, &s->exit.prioq_index);
break;
case SOURCE_DEFER:
s->enabled = m;
break;
case SOURCE_WATCHDOG:
assert_not_reached("Wut? I shouldn't exist.");
}
} else {
switch (s->type) {
case SOURCE_IO:
r = source_io_register(s, m, s->io.events);
if (r < 0)
return r;
s->enabled = m;
break;
case SOURCE_MONOTONIC:
s->enabled = m;
prioq_reshuffle(s->event->monotonic_earliest, s, &s->time.earliest_index);
prioq_reshuffle(s->event->monotonic_latest, s, &s->time.latest_index);
break;
case SOURCE_REALTIME:
s->enabled = m;
prioq_reshuffle(s->event->realtime_earliest, s, &s->time.earliest_index);
prioq_reshuffle(s->event->realtime_latest, s, &s->time.latest_index);
break;
case SOURCE_SIGNAL:
s->enabled = m;
if (s->signal.sig != SIGCHLD || s->event->n_enabled_child_sources == 0) {
assert_se(sigaddset(&s->event->sigset, s->signal.sig) == 0);
event_update_signal_fd(s->event);
}
break;
case SOURCE_CHILD:
s->enabled = m;
if (s->enabled == SD_EVENT_OFF) {
s->event->n_enabled_child_sources++;
if (!s->event->signal_sources || !s->event->signal_sources[SIGCHLD]) {
assert_se(sigaddset(&s->event->sigset, SIGCHLD) == 0);
event_update_signal_fd(s->event);
}
}
break;
case SOURCE_EXIT:
s->enabled = m;
prioq_reshuffle(s->event->exit, s, &s->exit.prioq_index);
break;
case SOURCE_DEFER:
s->enabled = m;
break;
case SOURCE_WATCHDOG:
assert_not_reached("Wut? I shouldn't exist.");
}
}
if (s->pending)
prioq_reshuffle(s->event->pending, s, &s->pending_index);
if (s->prepare)
prioq_reshuffle(s->event->prepare, s, &s->prepare_index);
return 0;
}
_public_ int sd_event_source_get_time(sd_event_source *s, uint64_t *usec) {
assert_return(s, -EINVAL);
assert_return(usec, -EINVAL);
assert_return(s->type == SOURCE_REALTIME || s->type == SOURCE_MONOTONIC, -EDOM);
assert_return(!event_pid_changed(s->event), -ECHILD);
*usec = s->time.next;
return 0;
}
_public_ int sd_event_source_set_time(sd_event_source *s, uint64_t usec) {
assert_return(s, -EINVAL);
assert_return(usec != (uint64_t) -1, -EINVAL);
assert_return(s->type == SOURCE_REALTIME || s->type == SOURCE_MONOTONIC, -EDOM);
assert_return(s->event->state != SD_EVENT_FINISHED, -ESTALE);
assert_return(!event_pid_changed(s->event), -ECHILD);
s->time.next = usec;
source_set_pending(s, false);
if (s->type == SOURCE_REALTIME) {
prioq_reshuffle(s->event->realtime_earliest, s, &s->time.earliest_index);
prioq_reshuffle(s->event->realtime_latest, s, &s->time.latest_index);
} else {
prioq_reshuffle(s->event->monotonic_earliest, s, &s->time.earliest_index);
prioq_reshuffle(s->event->monotonic_latest, s, &s->time.latest_index);
}
return 0;
}
_public_ int sd_event_source_get_time_accuracy(sd_event_source *s, uint64_t *usec) {
assert_return(s, -EINVAL);
assert_return(usec, -EINVAL);
assert_return(s->type == SOURCE_REALTIME || s->type == SOURCE_MONOTONIC, -EDOM);
assert_return(!event_pid_changed(s->event), -ECHILD);
*usec = s->time.accuracy;
return 0;
}
_public_ int sd_event_source_set_time_accuracy(sd_event_source *s, uint64_t usec) {
assert_return(s, -EINVAL);
assert_return(usec != (uint64_t) -1, -EINVAL);
assert_return(s->type == SOURCE_REALTIME || s->type == SOURCE_MONOTONIC, -EDOM);
assert_return(s->event->state != SD_EVENT_FINISHED, -ESTALE);
assert_return(!event_pid_changed(s->event), -ECHILD);
if (usec == 0)
usec = DEFAULT_ACCURACY_USEC;
s->time.accuracy = usec;
source_set_pending(s, false);
if (s->type == SOURCE_REALTIME)
prioq_reshuffle(s->event->realtime_latest, s, &s->time.latest_index);
else
prioq_reshuffle(s->event->monotonic_latest, s, &s->time.latest_index);
return 0;
}
_public_ int sd_event_source_get_child_pid(sd_event_source *s, pid_t *pid) {
assert_return(s, -EINVAL);
assert_return(pid, -EINVAL);
assert_return(s->type == SOURCE_CHILD, -EDOM);
assert_return(!event_pid_changed(s->event), -ECHILD);
*pid = s->child.pid;
return 0;
}
_public_ int sd_event_source_set_prepare(sd_event_source *s, sd_event_handler_t callback) {
int r;
assert_return(s, -EINVAL);
assert_return(s->type != SOURCE_EXIT, -EDOM);
assert_return(s->event->state != SD_EVENT_FINISHED, -ESTALE);
assert_return(!event_pid_changed(s->event), -ECHILD);
if (s->prepare == callback)
return 0;
if (callback && s->prepare) {
s->prepare = callback;
return 0;
}
r = prioq_ensure_allocated(&s->event->prepare, prepare_prioq_compare);
if (r < 0)
return r;
s->prepare = callback;
if (callback) {
r = prioq_put(s->event->prepare, s, &s->prepare_index);
if (r < 0)
return r;
} else
prioq_remove(s->event->prepare, s, &s->prepare_index);
return 0;
}
_public_ void* sd_event_source_get_userdata(sd_event_source *s) {
assert_return(s, NULL);
return s->userdata;
}
_public_ void *sd_event_source_set_userdata(sd_event_source *s, void *userdata) {
void *ret;
assert_return(s, NULL);
ret = s->userdata;
s->userdata = userdata;
return ret;
}
static usec_t sleep_between(sd_event *e, usec_t a, usec_t b) {
usec_t c;
assert(e);
assert(a <= b);
if (a <= 0)
return 0;
if (b <= a + 1)
return a;
/*
Find a good time to wake up again between times a and b. We
have two goals here:
a) We want to wake up as seldom as possible, hence prefer
later times over earlier times.
b) But if we have to wake up, then let's make sure to
dispatch as much as possible on the entire system.
We implement this by waking up everywhere at the same time
within any given minute if we can, synchronised via the
perturbation value determined from the boot ID. If we can't,
then we try to find the same spot in every 10s, then 1s and
then 250ms step. Otherwise, we pick the last possible time
to wake up.
*/
c = (b / USEC_PER_MINUTE) * USEC_PER_MINUTE + e->perturb;
if (c >= b) {
if (_unlikely_(c < USEC_PER_MINUTE))
return b;
c -= USEC_PER_MINUTE;
}
if (c >= a)
return c;
c = (b / (USEC_PER_SEC*10)) * (USEC_PER_SEC*10) + (e->perturb % (USEC_PER_SEC*10));
if (c >= b) {
if (_unlikely_(c < USEC_PER_SEC*10))
return b;
c -= USEC_PER_SEC*10;
}
if (c >= a)
return c;
c = (b / USEC_PER_SEC) * USEC_PER_SEC + (e->perturb % USEC_PER_SEC);
if (c >= b) {
if (_unlikely_(c < USEC_PER_SEC))
return b;
c -= USEC_PER_SEC;
}
if (c >= a)
return c;
c = (b / (USEC_PER_MSEC*250)) * (USEC_PER_MSEC*250) + (e->perturb % (USEC_PER_MSEC*250));
if (c >= b) {
if (_unlikely_(c < USEC_PER_MSEC*250))
return b;
c -= USEC_PER_MSEC*250;
}
if (c >= a)
return c;
return b;
}
static int event_arm_timer(
sd_event *e,
int timer_fd,
Prioq *earliest,
Prioq *latest,
usec_t *next) {
struct itimerspec its = {};
sd_event_source *a, *b;
usec_t t;
int r;
assert(e);
assert(next);
a = prioq_peek(earliest);
if (!a || a->enabled == SD_EVENT_OFF) {
if (timer_fd < 0)
return 0;
if (*next == (usec_t) -1)
return 0;
/* disarm */
r = timerfd_settime(timer_fd, TFD_TIMER_ABSTIME, &its, NULL);
if (r < 0)
return r;
*next = (usec_t) -1;
return 0;
}
b = prioq_peek(latest);
assert_se(b && b->enabled != SD_EVENT_OFF);
t = sleep_between(e, a->time.next, b->time.next + b->time.accuracy);
if (*next == t)
return 0;
assert_se(timer_fd >= 0);
if (t == 0) {
/* We don' want to disarm here, just mean some time looooong ago. */
its.it_value.tv_sec = 0;
its.it_value.tv_nsec = 1;
} else
timespec_store(&its.it_value, t);
r = timerfd_settime(timer_fd, TFD_TIMER_ABSTIME, &its, NULL);
if (r < 0)
return -errno;
*next = t;
return 0;
}
static int process_io(sd_event *e, sd_event_source *s, uint32_t revents) {
assert(e);
assert(s);
assert(s->type == SOURCE_IO);
/* If the event source was already pending, we just OR in the
* new revents, otherwise we reset the value. The ORing is
* necessary to handle EPOLLONESHOT events properly where
* readability might happen independently of writability, and
* we need to keep track of both */
if (s->pending)
s->io.revents |= revents;
else
s->io.revents = revents;
return source_set_pending(s, true);
}
static int flush_timer(sd_event *e, int fd, uint32_t events, usec_t *next) {
uint64_t x;
ssize_t ss;
assert(e);
assert(fd >= 0);
assert_return(events == EPOLLIN, -EIO);
ss = read(fd, &x, sizeof(x));
if (ss < 0) {
if (errno == EAGAIN || errno == EINTR)
return 0;
return -errno;
}
if (_unlikely_(ss != sizeof(x)))
return -EIO;
if (next)
*next = (usec_t) -1;
return 0;
}
static int process_timer(
sd_event *e,
usec_t n,
Prioq *earliest,
Prioq *latest) {
sd_event_source *s;
int r;
assert(e);
for (;;) {
s = prioq_peek(earliest);
if (!s ||
s->time.next > n ||
s->enabled == SD_EVENT_OFF ||
s->pending)
break;
r = source_set_pending(s, true);
if (r < 0)
return r;
prioq_reshuffle(earliest, s, &s->time.earliest_index);
prioq_reshuffle(latest, s, &s->time.latest_index);
}
return 0;
}
static int process_child(sd_event *e) {
sd_event_source *s;
Iterator i;
int r;
assert(e);
e->need_process_child = false;
/*
So, this is ugly. We iteratively invoke waitid() with P_PID
+ WNOHANG for each PID we wait for, instead of using
P_ALL. This is because we only want to get child
information of very specific child processes, and not all
of them. We might not have processed the SIGCHLD even of a
previous invocation and we don't want to maintain a
unbounded *per-child* event queue, hence we really don't
want anything flushed out of the kernel's queue that we
don't care about. Since this is O(n) this means that if you
have a lot of processes you probably want to handle SIGCHLD
yourself.
We do not reap the children here (by using WNOWAIT), this
is only done after the event source is dispatched so that
the callback still sees the process as a zombie.
*/
HASHMAP_FOREACH(s, e->child_sources, i) {
assert(s->type == SOURCE_CHILD);
if (s->pending)
continue;
if (s->enabled == SD_EVENT_OFF)
continue;
zero(s->child.siginfo);
r = waitid(P_PID, s->child.pid, &s->child.siginfo,
WNOHANG | (s->child.options & WEXITED ? WNOWAIT : 0) | s->child.options);
if (r < 0)
return -errno;
if (s->child.siginfo.si_pid != 0) {
bool zombie =
s->child.siginfo.si_code == CLD_EXITED ||
s->child.siginfo.si_code == CLD_KILLED ||
s->child.siginfo.si_code == CLD_DUMPED;
if (!zombie && (s->child.options & WEXITED)) {
/* If the child isn't dead then let's
* immediately remove the state change
* from the queue, since there's no
* benefit in leaving it queued */
assert(s->child.options & (WSTOPPED|WCONTINUED));
waitid(P_PID, s->child.pid, &s->child.siginfo, WNOHANG|(s->child.options & (WSTOPPED|WCONTINUED)));
}
r = source_set_pending(s, true);
if (r < 0)
return r;
}
}
return 0;
}
static int process_signal(sd_event *e, uint32_t events) {
bool read_one = false;
int r;
assert(e);
assert(e->signal_sources);
assert_return(events == EPOLLIN, -EIO);
for (;;) {
struct signalfd_siginfo si;
ssize_t ss;
sd_event_source *s;
ss = read(e->signal_fd, &si, sizeof(si));
if (ss < 0) {
if (errno == EAGAIN || errno == EINTR)
return read_one;
return -errno;
}
if (_unlikely_(ss != sizeof(si)))
return -EIO;
read_one = true;
s = e->signal_sources[si.ssi_signo];
if (si.ssi_signo == SIGCHLD) {
r = process_child(e);
if (r < 0)
return r;
if (r > 0 || !s)
continue;
} else
if (!s)
return -EIO;
s->signal.siginfo = si;
r = source_set_pending(s, true);
if (r < 0)
return r;
}
return 0;
}
static int source_dispatch(sd_event_source *s) {
int r = 0;
assert(s);
assert(s->pending || s->type == SOURCE_EXIT);
if (s->type != SOURCE_DEFER && s->type != SOURCE_EXIT) {
r = source_set_pending(s, false);
if (r < 0)
return r;
}
if (s->enabled == SD_EVENT_ONESHOT) {
r = sd_event_source_set_enabled(s, SD_EVENT_OFF);
if (r < 0)
return r;
}
s->dispatching = true;
switch (s->type) {
case SOURCE_IO:
r = s->io.callback(s, s->io.fd, s->io.revents, s->userdata);
break;
case SOURCE_MONOTONIC:
r = s->time.callback(s, s->time.next, s->userdata);
break;
case SOURCE_REALTIME:
r = s->time.callback(s, s->time.next, s->userdata);
break;
case SOURCE_SIGNAL:
r = s->signal.callback(s, &s->signal.siginfo, s->userdata);
break;
case SOURCE_CHILD: {
bool zombie;
zombie = s->child.siginfo.si_code == CLD_EXITED ||
s->child.siginfo.si_code == CLD_KILLED ||
s->child.siginfo.si_code == CLD_DUMPED;
r = s->child.callback(s, &s->child.siginfo, s->userdata);
/* Now, reap the PID for good. */
if (zombie)
waitid(P_PID, s->child.pid, &s->child.siginfo, WNOHANG|WEXITED);
break;
}
case SOURCE_DEFER:
r = s->defer.callback(s, s->userdata);
break;
case SOURCE_EXIT:
r = s->exit.callback(s, s->userdata);
break;
case SOURCE_WATCHDOG:
assert_not_reached("Wut? I shouldn't exist.");
}
s->dispatching = false;
if (r < 0)
log_debug("Event source %p returned error, disabling: %s", s, strerror(-r));
if (s->n_ref == 0)
source_free(s);
else if (r < 0)
sd_event_source_set_enabled(s, SD_EVENT_OFF);
return 1;
}
static int event_prepare(sd_event *e) {
int r;
assert(e);
for (;;) {
sd_event_source *s;
s = prioq_peek(e->prepare);
if (!s || s->prepare_iteration == e->iteration || s->enabled == SD_EVENT_OFF)
break;
s->prepare_iteration = e->iteration;
r = prioq_reshuffle(e->prepare, s, &s->prepare_index);
if (r < 0)
return r;
assert(s->prepare);
s->dispatching = true;
r = s->prepare(s, s->userdata);
s->dispatching = false;
if (r < 0)
log_debug("Prepare callback of event source %p returned error, disabling: %s", s, strerror(-r));
if (s->n_ref == 0)
source_free(s);
else if (r < 0)
sd_event_source_set_enabled(s, SD_EVENT_OFF);
}
return 0;
}
static int dispatch_exit(sd_event *e) {
sd_event_source *p;
int r;
assert(e);
p = prioq_peek(e->exit);
if (!p || p->enabled == SD_EVENT_OFF) {
e->state = SD_EVENT_FINISHED;
return 0;
}
sd_event_ref(e);
e->iteration++;
e->state = SD_EVENT_EXITING;
r = source_dispatch(p);
e->state = SD_EVENT_PASSIVE;
sd_event_unref(e);
return r;
}
static sd_event_source* event_next_pending(sd_event *e) {
sd_event_source *p;
assert(e);
p = prioq_peek(e->pending);
if (!p)
return NULL;
if (p->enabled == SD_EVENT_OFF)
return NULL;
return p;
}
static int arm_watchdog(sd_event *e) {
struct itimerspec its = {};
usec_t t;
int r;
assert(e);
assert(e->watchdog_fd >= 0);
t = sleep_between(e,
e->watchdog_last + (e->watchdog_period / 2),
e->watchdog_last + (e->watchdog_period * 3 / 4));
timespec_store(&its.it_value, t);
r = timerfd_settime(e->watchdog_fd, TFD_TIMER_ABSTIME, &its, NULL);
if (r < 0)
return -errno;
return 0;
}
static int process_watchdog(sd_event *e) {
assert(e);
if (!e->watchdog)
return 0;
/* Don't notify watchdog too often */
if (e->watchdog_last + e->watchdog_period / 4 > e->timestamp.monotonic)
return 0;
sd_notify(false, "WATCHDOG=1");
e->watchdog_last = e->timestamp.monotonic;
return arm_watchdog(e);
}
_public_ int sd_event_run(sd_event *e, uint64_t timeout) {
struct epoll_event *ev_queue;
unsigned ev_queue_max;
sd_event_source *p;
int r, i, m;
assert_return(e, -EINVAL);
assert_return(!event_pid_changed(e), -ECHILD);
assert_return(e->state != SD_EVENT_FINISHED, -ESTALE);
assert_return(e->state == SD_EVENT_PASSIVE, -EBUSY);
if (e->exit_requested)
return dispatch_exit(e);
sd_event_ref(e);
e->iteration++;
e->state = SD_EVENT_RUNNING;
r = event_prepare(e);
if (r < 0)
goto finish;
r = event_arm_timer(e, e->monotonic_fd, e->monotonic_earliest, e->monotonic_latest, &e->monotonic_next);
if (r < 0)
goto finish;
r = event_arm_timer(e, e->realtime_fd, e->realtime_earliest, e->realtime_latest, &e->realtime_next);
if (r < 0)
goto finish;
if (event_next_pending(e) || e->need_process_child)
timeout = 0;
ev_queue_max = CLAMP(e->n_sources, 1U, EPOLL_QUEUE_MAX);
ev_queue = newa(struct epoll_event, ev_queue_max);
m = epoll_wait(e->epoll_fd, ev_queue, ev_queue_max,
timeout == (uint64_t) -1 ? -1 : (int) ((timeout + USEC_PER_MSEC - 1) / USEC_PER_MSEC));
if (m < 0) {
r = errno == EAGAIN || errno == EINTR ? 0 : -errno;
goto finish;
}
dual_timestamp_get(&e->timestamp);
for (i = 0; i < m; i++) {
if (ev_queue[i].data.ptr == INT_TO_PTR(SOURCE_MONOTONIC))
r = flush_timer(e, e->monotonic_fd, ev_queue[i].events, &e->monotonic_next);
else if (ev_queue[i].data.ptr == INT_TO_PTR(SOURCE_REALTIME))
r = flush_timer(e, e->realtime_fd, ev_queue[i].events, &e->realtime_next);
else if (ev_queue[i].data.ptr == INT_TO_PTR(SOURCE_SIGNAL))
r = process_signal(e, ev_queue[i].events);
else if (ev_queue[i].data.ptr == INT_TO_PTR(SOURCE_WATCHDOG))
r = flush_timer(e, e->watchdog_fd, ev_queue[i].events, NULL);
else
r = process_io(e, ev_queue[i].data.ptr, ev_queue[i].events);
if (r < 0)
goto finish;
}
r = process_watchdog(e);
if (r < 0)
goto finish;
r = process_timer(e, e->timestamp.monotonic, e->monotonic_earliest, e->monotonic_latest);
if (r < 0)
goto finish;
r = process_timer(e, e->timestamp.realtime, e->realtime_earliest, e->realtime_latest);
if (r < 0)
goto finish;
if (e->need_process_child) {
r = process_child(e);
if (r < 0)
goto finish;
}
p = event_next_pending(e);
if (!p) {
r = 0;
goto finish;
}
r = source_dispatch(p);
finish:
e->state = SD_EVENT_PASSIVE;
sd_event_unref(e);
return r;
}
_public_ int sd_event_loop(sd_event *e) {
int r;
assert_return(e, -EINVAL);
assert_return(!event_pid_changed(e), -ECHILD);
assert_return(e->state == SD_EVENT_PASSIVE, -EBUSY);
sd_event_ref(e);
while (e->state != SD_EVENT_FINISHED) {
r = sd_event_run(e, (uint64_t) -1);
if (r < 0)
goto finish;
}
r = e->exit_code;
finish:
sd_event_unref(e);
return r;
}
_public_ int sd_event_get_state(sd_event *e) {
assert_return(e, -EINVAL);
assert_return(!event_pid_changed(e), -ECHILD);
return e->state;
}
_public_ int sd_event_get_exit_code(sd_event *e, int *code) {
assert_return(e, -EINVAL);
assert_return(code, -EINVAL);
assert_return(!event_pid_changed(e), -ECHILD);
if (!e->exit_requested)
return -ENODATA;
*code = e->exit_code;
return 0;
}
_public_ int sd_event_exit(sd_event *e, int code) {
assert_return(e, -EINVAL);
assert_return(e->state != SD_EVENT_FINISHED, -ESTALE);
assert_return(!event_pid_changed(e), -ECHILD);
e->exit_requested = true;
e->exit_code = code;
return 0;
}
_public_ int sd_event_get_now_realtime(sd_event *e, uint64_t *usec) {
assert_return(e, -EINVAL);
assert_return(usec, -EINVAL);
assert_return(dual_timestamp_is_set(&e->timestamp), -ENODATA);
assert_return(!event_pid_changed(e), -ECHILD);
*usec = e->timestamp.realtime;
return 0;
}
_public_ int sd_event_get_now_monotonic(sd_event *e, uint64_t *usec) {
assert_return(e, -EINVAL);
assert_return(usec, -EINVAL);
assert_return(dual_timestamp_is_set(&e->timestamp), -ENODATA);
assert_return(!event_pid_changed(e), -ECHILD);
*usec = e->timestamp.monotonic;
return 0;
}
_public_ int sd_event_default(sd_event **ret) {
static thread_local sd_event *default_event = NULL;
sd_event *e;
int r;
if (!ret)
return !!default_event;
if (default_event) {
*ret = sd_event_ref(default_event);
return 0;
}
r = sd_event_new(&e);
if (r < 0)
return r;
e->default_event_ptr = &default_event;
e->tid = gettid();
default_event = e;
*ret = e;
return 1;
}
_public_ int sd_event_get_tid(sd_event *e, pid_t *tid) {
assert_return(e, -EINVAL);
assert_return(tid, -EINVAL);
assert_return(!event_pid_changed(e), -ECHILD);
if (e->tid != 0) {
*tid = e->tid;
return 0;
}
return -ENXIO;
}
_public_ int sd_event_set_watchdog(sd_event *e, int b) {
int r;
assert_return(e, -EINVAL);
assert_return(!event_pid_changed(e), -ECHILD);
if (e->watchdog == !!b)
return e->watchdog;
if (b) {
struct epoll_event ev = {};
const char *env;
env = getenv("WATCHDOG_USEC");
if (!env)
return false;
r = safe_atou64(env, &e->watchdog_period);
if (r < 0)
return r;
if (e->watchdog_period <= 0)
return -EIO;
/* Issue first ping immediately */
sd_notify(false, "WATCHDOG=1");
e->watchdog_last = now(CLOCK_MONOTONIC);
e->watchdog_fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK|TFD_CLOEXEC);
if (e->watchdog_fd < 0)
return -errno;
r = arm_watchdog(e);
if (r < 0)
goto fail;
ev.events = EPOLLIN;
ev.data.ptr = INT_TO_PTR(SOURCE_WATCHDOG);
r = epoll_ctl(e->epoll_fd, EPOLL_CTL_ADD, e->watchdog_fd, &ev);
if (r < 0) {
r = -errno;
goto fail;
}
} else {
if (e->watchdog_fd >= 0) {
epoll_ctl(e->epoll_fd, EPOLL_CTL_DEL, e->watchdog_fd, NULL);
close_nointr_nofail(e->watchdog_fd);
e->watchdog_fd = -1;
}
}
e->watchdog = !!b;
return e->watchdog;
fail:
close_nointr_nofail(e->watchdog_fd);
e->watchdog_fd = -1;
return r;
}
_public_ int sd_event_get_watchdog(sd_event *e) {
assert_return(e, -EINVAL);
assert_return(!event_pid_changed(e), -ECHILD);
return e->watchdog;
}