sd-event.c revision 6203e07a83214a55bb1f88508fcda2005c601dea
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering/***
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering This file is part of systemd.
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering Copyright 2013 Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering systemd is free software; you can redistribute it and/or modify it
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering under the terms of the GNU Lesser General Public License as published by
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering the Free Software Foundation; either version 2.1 of the License, or
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering (at your option) any later version.
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering systemd is distributed in the hope that it will be useful, but
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering Lesser General Public License for more details.
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering You should have received a copy of the GNU Lesser General Public License
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering***/
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
b5efdb8af40ea759a1ea584c1bc44ecc81dd00ceLennart Poettering#include <sys/epoll.h>
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering#include <sys/timerfd.h>
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poettering#include <sys/wait.h>
b5efdb8af40ea759a1ea584c1bc44ecc81dd00ceLennart Poettering
be808ea083fa07271116b4519c3c27fd20c5f077Tom Gundersen#include "sd-id128.h"
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poettering#include "sd-daemon.h"
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering#include "macro.h"
9df3ba6c6cb65eecec06f39dfe85a3596cedac4eTom Gundersen#include "prioq.h"
9df3ba6c6cb65eecec06f39dfe85a3596cedac4eTom Gundersen#include "hashmap.h"
9df3ba6c6cb65eecec06f39dfe85a3596cedac4eTom Gundersen#include "util.h"
9df3ba6c6cb65eecec06f39dfe85a3596cedac4eTom Gundersen#include "time-util.h"
be808ea083fa07271116b4519c3c27fd20c5f077Tom Gundersen#include "missing.h"
be808ea083fa07271116b4519c3c27fd20c5f077Tom Gundersen
be808ea083fa07271116b4519c3c27fd20c5f077Tom Gundersen#include "sd-event.h"
be808ea083fa07271116b4519c3c27fd20c5f077Tom Gundersen
be808ea083fa07271116b4519c3c27fd20c5f077Tom Gundersen#define EPOLL_QUEUE_MAX 64
be808ea083fa07271116b4519c3c27fd20c5f077Tom Gundersen#define DEFAULT_ACCURACY_USEC (250 * USEC_PER_MSEC)
be808ea083fa07271116b4519c3c27fd20c5f077Tom Gundersen
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poetteringtypedef enum EventSourceType {
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering SOURCE_IO,
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering SOURCE_MONOTONIC,
4e945a6f7971fd7d1f6b2c62ee3afdaff3c95ce4Lennart Poettering SOURCE_REALTIME,
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering SOURCE_SIGNAL,
0dd25fb9f005d8ab7ac4bc10a609d00569f8c56aLennart Poettering SOURCE_CHILD,
3c0cf502796be355431d4a64d738e75f543aa51dLennart Poettering SOURCE_DEFER,
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering SOURCE_EXIT,
eed857b71702f8551b46b66b31fa0d08583cf23cLennart Poettering SOURCE_WATCHDOG
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering} EventSourceType;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
4e945a6f7971fd7d1f6b2c62ee3afdaff3c95ce4Lennart Poetteringstruct sd_event_source {
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering unsigned n_ref;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
eed857b71702f8551b46b66b31fa0d08583cf23cLennart Poettering sd_event *event;
eed857b71702f8551b46b66b31fa0d08583cf23cLennart Poettering void *userdata;
eed857b71702f8551b46b66b31fa0d08583cf23cLennart Poettering sd_event_handler_t prepare;
eed857b71702f8551b46b66b31fa0d08583cf23cLennart Poettering
eed857b71702f8551b46b66b31fa0d08583cf23cLennart Poettering EventSourceType type:4;
eed857b71702f8551b46b66b31fa0d08583cf23cLennart Poettering int enabled:3;
eed857b71702f8551b46b66b31fa0d08583cf23cLennart Poettering bool pending:1;
eed857b71702f8551b46b66b31fa0d08583cf23cLennart Poettering
eed857b71702f8551b46b66b31fa0d08583cf23cLennart Poettering int priority;
eed857b71702f8551b46b66b31fa0d08583cf23cLennart Poettering unsigned pending_index;
eed857b71702f8551b46b66b31fa0d08583cf23cLennart Poettering unsigned prepare_index;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering unsigned pending_iteration;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering unsigned prepare_iteration;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering union {
91b14d6ff362b938a72db17b095ee9903d07381bTom Gundersen struct {
0b58db658b5c3f586ac3a837427f1f7fec2abb2eLennart Poettering sd_event_io_handler_t callback;
f4461e5641d53f27d6e76e0607bdaa9c0c58c1f6Lennart Poettering int fd;
f4461e5641d53f27d6e76e0607bdaa9c0c58c1f6Lennart Poettering uint32_t events;
be808ea083fa07271116b4519c3c27fd20c5f077Tom Gundersen uint32_t revents;
d74fb368b18f0fbd9a4fe6f15691bbea7f3c4a01Tom Gundersen bool registered:1;
4e945a6f7971fd7d1f6b2c62ee3afdaff3c95ce4Lennart Poettering } io;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering struct {
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering sd_event_time_handler_t callback;
9df3ba6c6cb65eecec06f39dfe85a3596cedac4eTom Gundersen usec_t next, accuracy;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering unsigned earliest_index;
0b58db658b5c3f586ac3a837427f1f7fec2abb2eLennart Poettering unsigned latest_index;
0b58db658b5c3f586ac3a837427f1f7fec2abb2eLennart Poettering } time;
0b58db658b5c3f586ac3a837427f1f7fec2abb2eLennart Poettering struct {
0b58db658b5c3f586ac3a837427f1f7fec2abb2eLennart Poettering sd_event_signal_handler_t callback;
eed857b71702f8551b46b66b31fa0d08583cf23cLennart Poettering struct signalfd_siginfo siginfo;
eed857b71702f8551b46b66b31fa0d08583cf23cLennart Poettering int sig;
0b58db658b5c3f586ac3a837427f1f7fec2abb2eLennart Poettering } signal;
0b58db658b5c3f586ac3a837427f1f7fec2abb2eLennart Poettering struct {
0b58db658b5c3f586ac3a837427f1f7fec2abb2eLennart Poettering sd_event_child_handler_t callback;
eed857b71702f8551b46b66b31fa0d08583cf23cLennart Poettering siginfo_t siginfo;
eed857b71702f8551b46b66b31fa0d08583cf23cLennart Poettering pid_t pid;
0b58db658b5c3f586ac3a837427f1f7fec2abb2eLennart Poettering int options;
0b58db658b5c3f586ac3a837427f1f7fec2abb2eLennart Poettering } child;
0b58db658b5c3f586ac3a837427f1f7fec2abb2eLennart Poettering struct {
eed857b71702f8551b46b66b31fa0d08583cf23cLennart Poettering sd_event_handler_t callback;
eed857b71702f8551b46b66b31fa0d08583cf23cLennart Poettering } defer;
0b58db658b5c3f586ac3a837427f1f7fec2abb2eLennart Poettering struct {
0b58db658b5c3f586ac3a837427f1f7fec2abb2eLennart Poettering sd_event_handler_t callback;
0b58db658b5c3f586ac3a837427f1f7fec2abb2eLennart Poettering unsigned prioq_index;
4e945a6f7971fd7d1f6b2c62ee3afdaff3c95ce4Lennart Poettering } exit;
0b58db658b5c3f586ac3a837427f1f7fec2abb2eLennart Poettering };
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering};
0eac462399c8e87bcce252cf058eba9f2678f2bdLennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poetteringstruct sd_event {
4e945a6f7971fd7d1f6b2c62ee3afdaff3c95ce4Lennart Poettering unsigned n_ref;
4e945a6f7971fd7d1f6b2c62ee3afdaff3c95ce4Lennart Poettering
4e945a6f7971fd7d1f6b2c62ee3afdaff3c95ce4Lennart Poettering int epoll_fd;
4e945a6f7971fd7d1f6b2c62ee3afdaff3c95ce4Lennart Poettering int signal_fd;
3e684349c2cead2e6fd2f816c34eb17daba23a49Lennart Poettering int realtime_fd;
3e684349c2cead2e6fd2f816c34eb17daba23a49Lennart Poettering int monotonic_fd;
3e684349c2cead2e6fd2f816c34eb17daba23a49Lennart Poettering int watchdog_fd;
4e945a6f7971fd7d1f6b2c62ee3afdaff3c95ce4Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering Prioq *pending;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering Prioq *prepare;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering /* For both clocks we maintain two priority queues each, one
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering * ordered for the earliest times the events may be
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering * dispatched, and one ordered by the latest times they must
91b14d6ff362b938a72db17b095ee9903d07381bTom Gundersen * have been dispatched. The range between the top entries in
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering * the two prioqs is the time window we can freely schedule
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering * wakeups in */
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering Prioq *monotonic_earliest;
91b14d6ff362b938a72db17b095ee9903d07381bTom Gundersen Prioq *monotonic_latest;
91b14d6ff362b938a72db17b095ee9903d07381bTom Gundersen Prioq *realtime_earliest;
cab5b05903096e1c9cf5575ccc73f89d15c8db69Lennart Poettering Prioq *realtime_latest;
91b14d6ff362b938a72db17b095ee9903d07381bTom Gundersen
91b14d6ff362b938a72db17b095ee9903d07381bTom Gundersen usec_t realtime_next, monotonic_next;
91b14d6ff362b938a72db17b095ee9903d07381bTom Gundersen usec_t perturb;
0eac462399c8e87bcce252cf058eba9f2678f2bdLennart Poettering
91b14d6ff362b938a72db17b095ee9903d07381bTom Gundersen sigset_t sigset;
91b14d6ff362b938a72db17b095ee9903d07381bTom Gundersen sd_event_source **signal_sources;
3e684349c2cead2e6fd2f816c34eb17daba23a49Lennart Poettering
0eac462399c8e87bcce252cf058eba9f2678f2bdLennart Poettering Hashmap *child_sources;
0eac462399c8e87bcce252cf058eba9f2678f2bdLennart Poettering unsigned n_enabled_child_sources;
91b14d6ff362b938a72db17b095ee9903d07381bTom Gundersen
0eac462399c8e87bcce252cf058eba9f2678f2bdLennart Poettering Prioq *exit;
0eac462399c8e87bcce252cf058eba9f2678f2bdLennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering pid_t original_pid;
6cb08a8930bdaca950b152b1e8b82466ed59511cLennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering unsigned iteration;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering dual_timestamp timestamp;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering int state;
87f5a19343acf8ba697acc5a62bdb1a2b8c9eda3Lennart Poettering
0eac462399c8e87bcce252cf058eba9f2678f2bdLennart Poettering bool exit_requested:1;
0eac462399c8e87bcce252cf058eba9f2678f2bdLennart Poettering bool need_process_child:1;
0eac462399c8e87bcce252cf058eba9f2678f2bdLennart Poettering bool watchdog:1;
91b14d6ff362b938a72db17b095ee9903d07381bTom Gundersen
0eac462399c8e87bcce252cf058eba9f2678f2bdLennart Poettering int exit_code;
0eac462399c8e87bcce252cf058eba9f2678f2bdLennart Poettering
0eac462399c8e87bcce252cf058eba9f2678f2bdLennart Poettering pid_t tid;
91b14d6ff362b938a72db17b095ee9903d07381bTom Gundersen sd_event **default_event_ptr;
0eac462399c8e87bcce252cf058eba9f2678f2bdLennart Poettering
0eac462399c8e87bcce252cf058eba9f2678f2bdLennart Poettering usec_t watchdog_last, watchdog_period;
91b14d6ff362b938a72db17b095ee9903d07381bTom Gundersen};
0eac462399c8e87bcce252cf058eba9f2678f2bdLennart Poettering
0eac462399c8e87bcce252cf058eba9f2678f2bdLennart Poetteringstatic int pending_prioq_compare(const void *a, const void *b) {
0eac462399c8e87bcce252cf058eba9f2678f2bdLennart Poettering const sd_event_source *x = a, *y = b;
0eac462399c8e87bcce252cf058eba9f2678f2bdLennart Poettering
eed857b71702f8551b46b66b31fa0d08583cf23cLennart Poettering assert(x->pending);
0eac462399c8e87bcce252cf058eba9f2678f2bdLennart Poettering assert(y->pending);
0eac462399c8e87bcce252cf058eba9f2678f2bdLennart Poettering
0eac462399c8e87bcce252cf058eba9f2678f2bdLennart Poettering /* Enabled ones first */
0eac462399c8e87bcce252cf058eba9f2678f2bdLennart Poettering if (x->enabled != SD_EVENT_OFF && y->enabled == SD_EVENT_OFF)
eed857b71702f8551b46b66b31fa0d08583cf23cLennart Poettering return -1;
0eac462399c8e87bcce252cf058eba9f2678f2bdLennart Poettering if (x->enabled == SD_EVENT_OFF && y->enabled != SD_EVENT_OFF)
eed857b71702f8551b46b66b31fa0d08583cf23cLennart Poettering return 1;
0eac462399c8e87bcce252cf058eba9f2678f2bdLennart Poettering
0eac462399c8e87bcce252cf058eba9f2678f2bdLennart Poettering /* Lower priority values first */
0eac462399c8e87bcce252cf058eba9f2678f2bdLennart Poettering if (x->priority < y->priority)
eed857b71702f8551b46b66b31fa0d08583cf23cLennart Poettering return -1;
0eac462399c8e87bcce252cf058eba9f2678f2bdLennart Poettering if (x->priority > y->priority)
eed857b71702f8551b46b66b31fa0d08583cf23cLennart Poettering return 1;
0eac462399c8e87bcce252cf058eba9f2678f2bdLennart Poettering
0eac462399c8e87bcce252cf058eba9f2678f2bdLennart Poettering /* Older entries first */
0eac462399c8e87bcce252cf058eba9f2678f2bdLennart Poettering if (x->pending_iteration < y->pending_iteration)
0eac462399c8e87bcce252cf058eba9f2678f2bdLennart Poettering return -1;
0eac462399c8e87bcce252cf058eba9f2678f2bdLennart Poettering if (x->pending_iteration > y->pending_iteration)
0eac462399c8e87bcce252cf058eba9f2678f2bdLennart Poettering return 1;
0eac462399c8e87bcce252cf058eba9f2678f2bdLennart Poettering
0eac462399c8e87bcce252cf058eba9f2678f2bdLennart Poettering /* Stability for the rest */
0eac462399c8e87bcce252cf058eba9f2678f2bdLennart Poettering if (x < y)
0eac462399c8e87bcce252cf058eba9f2678f2bdLennart Poettering return -1;
0eac462399c8e87bcce252cf058eba9f2678f2bdLennart Poettering if (x > y)
0eac462399c8e87bcce252cf058eba9f2678f2bdLennart Poettering return 1;
91b14d6ff362b938a72db17b095ee9903d07381bTom Gundersen
91b14d6ff362b938a72db17b095ee9903d07381bTom Gundersen return 0;
0b58db658b5c3f586ac3a837427f1f7fec2abb2eLennart Poettering}
0b58db658b5c3f586ac3a837427f1f7fec2abb2eLennart Poettering
0b58db658b5c3f586ac3a837427f1f7fec2abb2eLennart Poetteringstatic int prepare_prioq_compare(const void *a, const void *b) {
0b58db658b5c3f586ac3a837427f1f7fec2abb2eLennart Poettering const sd_event_source *x = a, *y = b;
0b58db658b5c3f586ac3a837427f1f7fec2abb2eLennart Poettering
0b58db658b5c3f586ac3a837427f1f7fec2abb2eLennart Poettering assert(x->prepare);
0b58db658b5c3f586ac3a837427f1f7fec2abb2eLennart Poettering assert(y->prepare);
0b58db658b5c3f586ac3a837427f1f7fec2abb2eLennart Poettering
0b58db658b5c3f586ac3a837427f1f7fec2abb2eLennart Poettering /* Move most recently prepared ones last, so that we can stop
0b58db658b5c3f586ac3a837427f1f7fec2abb2eLennart Poettering * preparing as soon as we hit one that has already been
0b58db658b5c3f586ac3a837427f1f7fec2abb2eLennart Poettering * prepared in the current iteration */
0b58db658b5c3f586ac3a837427f1f7fec2abb2eLennart Poettering if (x->prepare_iteration < y->prepare_iteration)
0b58db658b5c3f586ac3a837427f1f7fec2abb2eLennart Poettering return -1;
0b58db658b5c3f586ac3a837427f1f7fec2abb2eLennart Poettering if (x->prepare_iteration > y->prepare_iteration)
0b58db658b5c3f586ac3a837427f1f7fec2abb2eLennart Poettering return 1;
0b58db658b5c3f586ac3a837427f1f7fec2abb2eLennart Poettering
0b58db658b5c3f586ac3a837427f1f7fec2abb2eLennart Poettering /* Enabled ones first */
0b58db658b5c3f586ac3a837427f1f7fec2abb2eLennart Poettering if (x->enabled != SD_EVENT_OFF && y->enabled == SD_EVENT_OFF)
0b58db658b5c3f586ac3a837427f1f7fec2abb2eLennart Poettering return -1;
0b58db658b5c3f586ac3a837427f1f7fec2abb2eLennart Poettering if (x->enabled == SD_EVENT_OFF && y->enabled != SD_EVENT_OFF)
0b58db658b5c3f586ac3a837427f1f7fec2abb2eLennart Poettering return 1;
0b58db658b5c3f586ac3a837427f1f7fec2abb2eLennart Poettering
0b58db658b5c3f586ac3a837427f1f7fec2abb2eLennart Poettering /* Lower priority values first */
0b58db658b5c3f586ac3a837427f1f7fec2abb2eLennart Poettering if (x->priority < y->priority)
0b58db658b5c3f586ac3a837427f1f7fec2abb2eLennart Poettering return -1;
0b58db658b5c3f586ac3a837427f1f7fec2abb2eLennart Poettering if (x->priority > y->priority)
0b58db658b5c3f586ac3a837427f1f7fec2abb2eLennart Poettering return 1;
0b58db658b5c3f586ac3a837427f1f7fec2abb2eLennart Poettering
0b58db658b5c3f586ac3a837427f1f7fec2abb2eLennart Poettering /* Stability for the rest */
0b58db658b5c3f586ac3a837427f1f7fec2abb2eLennart Poettering if (x < y)
0b58db658b5c3f586ac3a837427f1f7fec2abb2eLennart Poettering return -1;
0b58db658b5c3f586ac3a837427f1f7fec2abb2eLennart Poettering if (x > y)
0b58db658b5c3f586ac3a837427f1f7fec2abb2eLennart Poettering return 1;
0b58db658b5c3f586ac3a837427f1f7fec2abb2eLennart Poettering
0b58db658b5c3f586ac3a837427f1f7fec2abb2eLennart Poettering return 0;
0b58db658b5c3f586ac3a837427f1f7fec2abb2eLennart Poettering}
0b58db658b5c3f586ac3a837427f1f7fec2abb2eLennart Poettering
0b58db658b5c3f586ac3a837427f1f7fec2abb2eLennart Poetteringstatic int earliest_time_prioq_compare(const void *a, const void *b) {
0b58db658b5c3f586ac3a837427f1f7fec2abb2eLennart Poettering const sd_event_source *x = a, *y = b;
0b58db658b5c3f586ac3a837427f1f7fec2abb2eLennart Poettering
0b58db658b5c3f586ac3a837427f1f7fec2abb2eLennart Poettering assert(x->type == SOURCE_MONOTONIC || x->type == SOURCE_REALTIME);
0b58db658b5c3f586ac3a837427f1f7fec2abb2eLennart Poettering assert(y->type == SOURCE_MONOTONIC || y->type == SOURCE_REALTIME);
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering
9df3ba6c6cb65eecec06f39dfe85a3596cedac4eTom Gundersen /* Enabled ones first */
9df3ba6c6cb65eecec06f39dfe85a3596cedac4eTom Gundersen if (x->enabled != SD_EVENT_OFF && y->enabled == SD_EVENT_OFF)
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering return -1;
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering if (x->enabled == SD_EVENT_OFF && y->enabled != SD_EVENT_OFF)
b652d4a2099d1c167584dcc1d179d47c58dc38a2Lennart Poettering return 1;
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering /* Move the pending ones to the end */
f4461e5641d53f27d6e76e0607bdaa9c0c58c1f6Lennart Poettering if (!x->pending && y->pending)
be808ea083fa07271116b4519c3c27fd20c5f077Tom Gundersen return -1;
be808ea083fa07271116b4519c3c27fd20c5f077Tom Gundersen if (x->pending && !y->pending)
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering return 1;
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering /* Order by time */
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering if (x->time.next < y->time.next)
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering return -1;
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering if (x->time.next > y->time.next)
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering return 1;
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering /* Stability for the rest */
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering if (x < y)
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering return -1;
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering if (x > y)
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering return 1;
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering return 0;
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering}
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poetteringstatic int latest_time_prioq_compare(const void *a, const void *b) {
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering const sd_event_source *x = a, *y = b;
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering assert((x->type == SOURCE_MONOTONIC && y->type == SOURCE_MONOTONIC) ||
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering (x->type == SOURCE_REALTIME && y->type == SOURCE_REALTIME));
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering /* Enabled ones first */
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering if (x->enabled != SD_EVENT_OFF && y->enabled == SD_EVENT_OFF)
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering return -1;
84129d46cd6e95e142973da93aede4c7433c9600Lennart Poettering if (x->enabled == SD_EVENT_OFF && y->enabled != SD_EVENT_OFF)
d74fb368b18f0fbd9a4fe6f15691bbea7f3c4a01Tom Gundersen return 1;
d74fb368b18f0fbd9a4fe6f15691bbea7f3c4a01Tom Gundersen
d74fb368b18f0fbd9a4fe6f15691bbea7f3c4a01Tom Gundersen /* Move the pending ones to the end */
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering if (!x->pending && y->pending)
d74fb368b18f0fbd9a4fe6f15691bbea7f3c4a01Tom Gundersen return -1;
d74fb368b18f0fbd9a4fe6f15691bbea7f3c4a01Tom Gundersen if (x->pending && !y->pending)
be808ea083fa07271116b4519c3c27fd20c5f077Tom Gundersen return 1;
be808ea083fa07271116b4519c3c27fd20c5f077Tom Gundersen
efd46a696d31097c38f653b36921e00c4df62319Lennart Poettering /* Order by time */
be808ea083fa07271116b4519c3c27fd20c5f077Tom Gundersen if (x->time.next + x->time.accuracy < y->time.next + y->time.accuracy)
9df3ba6c6cb65eecec06f39dfe85a3596cedac4eTom Gundersen return -1;
9df3ba6c6cb65eecec06f39dfe85a3596cedac4eTom Gundersen if (x->time.next + x->time.accuracy > y->time.next + y->time.accuracy)
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering return 1;
9df3ba6c6cb65eecec06f39dfe85a3596cedac4eTom Gundersen
be808ea083fa07271116b4519c3c27fd20c5f077Tom Gundersen /* Stability for the rest */
be808ea083fa07271116b4519c3c27fd20c5f077Tom Gundersen if (x < y)
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering return -1;
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering if (x > y)
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering return 1;
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering return 0;
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering}
9df3ba6c6cb65eecec06f39dfe85a3596cedac4eTom Gundersen
84129d46cd6e95e142973da93aede4c7433c9600Lennart Poetteringstatic int exit_prioq_compare(const void *a, const void *b) {
84129d46cd6e95e142973da93aede4c7433c9600Lennart Poettering const sd_event_source *x = a, *y = b;
84129d46cd6e95e142973da93aede4c7433c9600Lennart Poettering
84129d46cd6e95e142973da93aede4c7433c9600Lennart Poettering assert(x->type == SOURCE_EXIT);
9df3ba6c6cb65eecec06f39dfe85a3596cedac4eTom Gundersen assert(y->type == SOURCE_EXIT);
9df3ba6c6cb65eecec06f39dfe85a3596cedac4eTom Gundersen
f4461e5641d53f27d6e76e0607bdaa9c0c58c1f6Lennart Poettering /* Enabled ones first */
4e0b8b17a7465653f4e7b819dad5f8e30d64c0c4Tom Gundersen if (x->enabled != SD_EVENT_OFF && y->enabled == SD_EVENT_OFF)
4e0b8b17a7465653f4e7b819dad5f8e30d64c0c4Tom Gundersen return -1;
4e0b8b17a7465653f4e7b819dad5f8e30d64c0c4Tom Gundersen if (x->enabled == SD_EVENT_OFF && y->enabled != SD_EVENT_OFF)
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering return 1;
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering
f4461e5641d53f27d6e76e0607bdaa9c0c58c1f6Lennart Poettering /* Lower priority values first */
4e0b8b17a7465653f4e7b819dad5f8e30d64c0c4Tom Gundersen if (x->priority < y->priority)
4e0b8b17a7465653f4e7b819dad5f8e30d64c0c4Tom Gundersen return -1;
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering if (x->priority > y->priority)
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering return 1;
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering /* Stability for the rest */
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering if (x < y)
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering return -1;
571370c1555d2aa697733479a50957aff024bbcbLennart Poettering if (x > y)
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering return 1;
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering return 0;
571370c1555d2aa697733479a50957aff024bbcbLennart Poettering}
571370c1555d2aa697733479a50957aff024bbcbLennart Poettering
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poetteringstatic void event_free(sd_event *e) {
4e0b8b17a7465653f4e7b819dad5f8e30d64c0c4Tom Gundersen assert(e);
4e0b8b17a7465653f4e7b819dad5f8e30d64c0c4Tom Gundersen
b652d4a2099d1c167584dcc1d179d47c58dc38a2Lennart Poettering if (e->default_event_ptr)
b652d4a2099d1c167584dcc1d179d47c58dc38a2Lennart Poettering *(e->default_event_ptr) = NULL;
b652d4a2099d1c167584dcc1d179d47c58dc38a2Lennart Poettering
b652d4a2099d1c167584dcc1d179d47c58dc38a2Lennart Poettering if (e->epoll_fd >= 0)
6cb08a8930bdaca950b152b1e8b82466ed59511cLennart Poettering close_nointr_nofail(e->epoll_fd);
b652d4a2099d1c167584dcc1d179d47c58dc38a2Lennart Poettering
b652d4a2099d1c167584dcc1d179d47c58dc38a2Lennart Poettering if (e->signal_fd >= 0)
b652d4a2099d1c167584dcc1d179d47c58dc38a2Lennart Poettering close_nointr_nofail(e->signal_fd);
b652d4a2099d1c167584dcc1d179d47c58dc38a2Lennart Poettering
be808ea083fa07271116b4519c3c27fd20c5f077Tom Gundersen if (e->realtime_fd >= 0)
be808ea083fa07271116b4519c3c27fd20c5f077Tom Gundersen close_nointr_nofail(e->realtime_fd);
be808ea083fa07271116b4519c3c27fd20c5f077Tom Gundersen
be808ea083fa07271116b4519c3c27fd20c5f077Tom Gundersen if (e->monotonic_fd >= 0)
be808ea083fa07271116b4519c3c27fd20c5f077Tom Gundersen close_nointr_nofail(e->monotonic_fd);
be808ea083fa07271116b4519c3c27fd20c5f077Tom Gundersen
be808ea083fa07271116b4519c3c27fd20c5f077Tom Gundersen if (e->watchdog_fd >= 0)
be808ea083fa07271116b4519c3c27fd20c5f077Tom Gundersen close_nointr_nofail(e->watchdog_fd);
be808ea083fa07271116b4519c3c27fd20c5f077Tom Gundersen
be808ea083fa07271116b4519c3c27fd20c5f077Tom Gundersen prioq_free(e->pending);
be808ea083fa07271116b4519c3c27fd20c5f077Tom Gundersen prioq_free(e->prepare);
be808ea083fa07271116b4519c3c27fd20c5f077Tom Gundersen prioq_free(e->monotonic_earliest);
be808ea083fa07271116b4519c3c27fd20c5f077Tom Gundersen prioq_free(e->monotonic_latest);
be808ea083fa07271116b4519c3c27fd20c5f077Tom Gundersen prioq_free(e->realtime_earliest);
be808ea083fa07271116b4519c3c27fd20c5f077Tom Gundersen prioq_free(e->realtime_latest);
be808ea083fa07271116b4519c3c27fd20c5f077Tom Gundersen prioq_free(e->exit);
be808ea083fa07271116b4519c3c27fd20c5f077Tom Gundersen
be808ea083fa07271116b4519c3c27fd20c5f077Tom Gundersen free(e->signal_sources);
be808ea083fa07271116b4519c3c27fd20c5f077Tom Gundersen
f4461e5641d53f27d6e76e0607bdaa9c0c58c1f6Lennart Poettering hashmap_free(e->child_sources);
be808ea083fa07271116b4519c3c27fd20c5f077Tom Gundersen free(e);
be808ea083fa07271116b4519c3c27fd20c5f077Tom Gundersen}
f4461e5641d53f27d6e76e0607bdaa9c0c58c1f6Lennart Poettering
be808ea083fa07271116b4519c3c27fd20c5f077Tom Gundersen_public_ int sd_event_new(sd_event** ret) {
be808ea083fa07271116b4519c3c27fd20c5f077Tom Gundersen sd_event *e;
f4461e5641d53f27d6e76e0607bdaa9c0c58c1f6Lennart Poettering int r;
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering assert_return(ret, -EINVAL);
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering e = new0(sd_event, 1);
be808ea083fa07271116b4519c3c27fd20c5f077Tom Gundersen if (!e)
b652d4a2099d1c167584dcc1d179d47c58dc38a2Lennart Poettering return -ENOMEM;
be808ea083fa07271116b4519c3c27fd20c5f077Tom Gundersen
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering e->n_ref = 1;
6cb08a8930bdaca950b152b1e8b82466ed59511cLennart Poettering e->signal_fd = e->realtime_fd = e->monotonic_fd = e->watchdog_fd = e->epoll_fd = -1;
6cb08a8930bdaca950b152b1e8b82466ed59511cLennart Poettering e->realtime_next = e->monotonic_next = (usec_t) -1;
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering e->original_pid = getpid();
f4461e5641d53f27d6e76e0607bdaa9c0c58c1f6Lennart Poettering
f4461e5641d53f27d6e76e0607bdaa9c0c58c1f6Lennart Poettering assert_se(sigemptyset(&e->sigset) == 0);
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering e->pending = prioq_new(pending_prioq_compare);
be808ea083fa07271116b4519c3c27fd20c5f077Tom Gundersen if (!e->pending) {
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering r = -ENOMEM;
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering goto fail;
6a1a5eec43892dee3ff6e208bceb1931c25c782eLennart Poettering }
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering e->epoll_fd = epoll_create1(EPOLL_CLOEXEC);
6a1a5eec43892dee3ff6e208bceb1931c25c782eLennart Poettering if (e->epoll_fd < 0) {
be808ea083fa07271116b4519c3c27fd20c5f077Tom Gundersen r = -errno;
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering goto fail;
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering }
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering *ret = e;
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering return 0;
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poetteringfail:
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering event_free(e);
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering return r;
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering}
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering_public_ sd_event* sd_event_ref(sd_event *e) {
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering assert_return(e, NULL);
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering assert(e->n_ref >= 1);
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering e->n_ref++;
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering return e;
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering}
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering_public_ sd_event* sd_event_unref(sd_event *e) {
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering if (!e)
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering return NULL;
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering assert(e->n_ref >= 1);
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering e->n_ref--;
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering if (e->n_ref <= 0)
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering event_free(e);
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering return NULL;
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering}
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poetteringstatic bool event_pid_changed(sd_event *e) {
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering assert(e);
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering /* We don't support people creating am event loop and keeping
6cb08a8930bdaca950b152b1e8b82466ed59511cLennart Poettering * it around over a fork(). Let's complain. */
6cb08a8930bdaca950b152b1e8b82466ed59511cLennart Poettering
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering return e->original_pid != getpid();
be808ea083fa07271116b4519c3c27fd20c5f077Tom Gundersen}
be808ea083fa07271116b4519c3c27fd20c5f077Tom Gundersen
f4461e5641d53f27d6e76e0607bdaa9c0c58c1f6Lennart Poetteringstatic int source_io_unregister(sd_event_source *s) {
be808ea083fa07271116b4519c3c27fd20c5f077Tom Gundersen int r;
be808ea083fa07271116b4519c3c27fd20c5f077Tom Gundersen
519ef04651b07a547f010d6462603669d7fde4e5Lennart Poettering assert(s);
519ef04651b07a547f010d6462603669d7fde4e5Lennart Poettering assert(s->type == SOURCE_IO);
519ef04651b07a547f010d6462603669d7fde4e5Lennart Poettering
519ef04651b07a547f010d6462603669d7fde4e5Lennart Poettering if (!s->io.registered)
519ef04651b07a547f010d6462603669d7fde4e5Lennart Poettering return 0;
519ef04651b07a547f010d6462603669d7fde4e5Lennart Poettering
519ef04651b07a547f010d6462603669d7fde4e5Lennart Poettering r = epoll_ctl(s->event->epoll_fd, EPOLL_CTL_DEL, s->io.fd, NULL);
519ef04651b07a547f010d6462603669d7fde4e5Lennart Poettering if (r < 0)
519ef04651b07a547f010d6462603669d7fde4e5Lennart Poettering return -errno;
519ef04651b07a547f010d6462603669d7fde4e5Lennart Poettering
519ef04651b07a547f010d6462603669d7fde4e5Lennart Poettering s->io.registered = false;
519ef04651b07a547f010d6462603669d7fde4e5Lennart Poettering return 0;
519ef04651b07a547f010d6462603669d7fde4e5Lennart Poettering}
519ef04651b07a547f010d6462603669d7fde4e5Lennart Poettering
519ef04651b07a547f010d6462603669d7fde4e5Lennart Poetteringstatic int source_io_register(
519ef04651b07a547f010d6462603669d7fde4e5Lennart Poettering sd_event_source *s,
519ef04651b07a547f010d6462603669d7fde4e5Lennart Poettering int enabled,
519ef04651b07a547f010d6462603669d7fde4e5Lennart Poettering uint32_t events) {
519ef04651b07a547f010d6462603669d7fde4e5Lennart Poettering
519ef04651b07a547f010d6462603669d7fde4e5Lennart Poettering struct epoll_event ev = {};
519ef04651b07a547f010d6462603669d7fde4e5Lennart Poettering int r;
519ef04651b07a547f010d6462603669d7fde4e5Lennart Poettering
519ef04651b07a547f010d6462603669d7fde4e5Lennart Poettering assert(s);
519ef04651b07a547f010d6462603669d7fde4e5Lennart Poettering assert(s->type == SOURCE_IO);
519ef04651b07a547f010d6462603669d7fde4e5Lennart Poettering assert(enabled != SD_EVENT_OFF);
519ef04651b07a547f010d6462603669d7fde4e5Lennart Poettering
519ef04651b07a547f010d6462603669d7fde4e5Lennart Poettering ev.events = events;
519ef04651b07a547f010d6462603669d7fde4e5Lennart Poettering ev.data.ptr = s;
6cb08a8930bdaca950b152b1e8b82466ed59511cLennart Poettering
6cb08a8930bdaca950b152b1e8b82466ed59511cLennart Poettering if (enabled == SD_EVENT_ONESHOT)
6cb08a8930bdaca950b152b1e8b82466ed59511cLennart Poettering ev.events |= EPOLLONESHOT;
6cb08a8930bdaca950b152b1e8b82466ed59511cLennart Poettering
6cb08a8930bdaca950b152b1e8b82466ed59511cLennart Poettering if (s->io.registered)
6cb08a8930bdaca950b152b1e8b82466ed59511cLennart Poettering r = epoll_ctl(s->event->epoll_fd, EPOLL_CTL_MOD, s->io.fd, &ev);
6cb08a8930bdaca950b152b1e8b82466ed59511cLennart Poettering else
6cb08a8930bdaca950b152b1e8b82466ed59511cLennart Poettering r = epoll_ctl(s->event->epoll_fd, EPOLL_CTL_ADD, s->io.fd, &ev);
6cb08a8930bdaca950b152b1e8b82466ed59511cLennart Poettering
b826ab586c9e0a9c0d438a75c28cf3a8ab485929Tom Gundersen if (r < 0)
87f5a19343acf8ba697acc5a62bdb1a2b8c9eda3Lennart Poettering return -errno;
87f5a19343acf8ba697acc5a62bdb1a2b8c9eda3Lennart Poettering
b826ab586c9e0a9c0d438a75c28cf3a8ab485929Tom Gundersen s->io.registered = true;
87f5a19343acf8ba697acc5a62bdb1a2b8c9eda3Lennart Poettering
b826ab586c9e0a9c0d438a75c28cf3a8ab485929Tom Gundersen return 0;
b826ab586c9e0a9c0d438a75c28cf3a8ab485929Tom Gundersen}
87f5a19343acf8ba697acc5a62bdb1a2b8c9eda3Lennart Poettering
87f5a19343acf8ba697acc5a62bdb1a2b8c9eda3Lennart Poetteringstatic void source_free(sd_event_source *s) {
d5099efc47d4e6ac60816b5381a5f607ab03f06eMichal Schmidt assert(s);
87f5a19343acf8ba697acc5a62bdb1a2b8c9eda3Lennart Poettering
87f5a19343acf8ba697acc5a62bdb1a2b8c9eda3Lennart Poettering if (s->event) {
87f5a19343acf8ba697acc5a62bdb1a2b8c9eda3Lennart Poettering switch (s->type) {
87f5a19343acf8ba697acc5a62bdb1a2b8c9eda3Lennart Poettering
87f5a19343acf8ba697acc5a62bdb1a2b8c9eda3Lennart Poettering case SOURCE_IO:
87f5a19343acf8ba697acc5a62bdb1a2b8c9eda3Lennart Poettering if (s->io.fd >= 0)
87f5a19343acf8ba697acc5a62bdb1a2b8c9eda3Lennart Poettering source_io_unregister(s);
87f5a19343acf8ba697acc5a62bdb1a2b8c9eda3Lennart Poettering
87f5a19343acf8ba697acc5a62bdb1a2b8c9eda3Lennart Poettering break;
d5099efc47d4e6ac60816b5381a5f607ab03f06eMichal Schmidt
d5099efc47d4e6ac60816b5381a5f607ab03f06eMichal Schmidt case SOURCE_MONOTONIC:
d5099efc47d4e6ac60816b5381a5f607ab03f06eMichal Schmidt prioq_remove(s->event->monotonic_earliest, s, &s->time.earliest_index);
d5099efc47d4e6ac60816b5381a5f607ab03f06eMichal Schmidt prioq_remove(s->event->monotonic_latest, s, &s->time.latest_index);
d5099efc47d4e6ac60816b5381a5f607ab03f06eMichal Schmidt break;
636e813dc98ea40c58c6c85bc5e7e3c9f0904ea2Lennart Poettering
4b95f1798f22c1bb75295f448188560cb6ec9eceLennart Poettering case SOURCE_REALTIME:
4b95f1798f22c1bb75295f448188560cb6ec9eceLennart Poettering prioq_remove(s->event->realtime_earliest, s, &s->time.earliest_index);
0eac462399c8e87bcce252cf058eba9f2678f2bdLennart Poettering prioq_remove(s->event->realtime_latest, s, &s->time.latest_index);
4b95f1798f22c1bb75295f448188560cb6ec9eceLennart Poettering break;
4b95f1798f22c1bb75295f448188560cb6ec9eceLennart Poettering
0eac462399c8e87bcce252cf058eba9f2678f2bdLennart Poettering case SOURCE_SIGNAL:
4b95f1798f22c1bb75295f448188560cb6ec9eceLennart Poettering if (s->signal.sig > 0) {
4b95f1798f22c1bb75295f448188560cb6ec9eceLennart Poettering if (s->signal.sig != SIGCHLD || s->event->n_enabled_child_sources == 0)
636e813dc98ea40c58c6c85bc5e7e3c9f0904ea2Lennart Poettering assert_se(sigdelset(&s->event->sigset, s->signal.sig) == 0);
4b95f1798f22c1bb75295f448188560cb6ec9eceLennart Poettering
0eac462399c8e87bcce252cf058eba9f2678f2bdLennart Poettering if (s->event->signal_sources)
0eac462399c8e87bcce252cf058eba9f2678f2bdLennart Poettering s->event->signal_sources[s->signal.sig] = NULL;
4b95f1798f22c1bb75295f448188560cb6ec9eceLennart Poettering }
4b95f1798f22c1bb75295f448188560cb6ec9eceLennart Poettering
636e813dc98ea40c58c6c85bc5e7e3c9f0904ea2Lennart Poettering break;
4b95f1798f22c1bb75295f448188560cb6ec9eceLennart Poettering
4b95f1798f22c1bb75295f448188560cb6ec9eceLennart Poettering case SOURCE_CHILD:
636e813dc98ea40c58c6c85bc5e7e3c9f0904ea2Lennart Poettering if (s->child.pid > 0) {
4b95f1798f22c1bb75295f448188560cb6ec9eceLennart Poettering if (s->enabled != SD_EVENT_OFF) {
636e813dc98ea40c58c6c85bc5e7e3c9f0904ea2Lennart Poettering assert(s->event->n_enabled_child_sources > 0);
4b95f1798f22c1bb75295f448188560cb6ec9eceLennart Poettering s->event->n_enabled_child_sources--;
0eac462399c8e87bcce252cf058eba9f2678f2bdLennart Poettering }
636e813dc98ea40c58c6c85bc5e7e3c9f0904ea2Lennart Poettering
4b95f1798f22c1bb75295f448188560cb6ec9eceLennart Poettering if (!s->event->signal_sources || !s->event->signal_sources[SIGCHLD])
4b95f1798f22c1bb75295f448188560cb6ec9eceLennart Poettering assert_se(sigdelset(&s->event->sigset, SIGCHLD) == 0);
636e813dc98ea40c58c6c85bc5e7e3c9f0904ea2Lennart Poettering
4b95f1798f22c1bb75295f448188560cb6ec9eceLennart Poettering hashmap_remove(s->event->child_sources, INT_TO_PTR(s->child.pid));
4b95f1798f22c1bb75295f448188560cb6ec9eceLennart Poettering }
4b95f1798f22c1bb75295f448188560cb6ec9eceLennart Poettering
636e813dc98ea40c58c6c85bc5e7e3c9f0904ea2Lennart Poettering break;
4b95f1798f22c1bb75295f448188560cb6ec9eceLennart Poettering
4b95f1798f22c1bb75295f448188560cb6ec9eceLennart Poettering case SOURCE_DEFER:
636e813dc98ea40c58c6c85bc5e7e3c9f0904ea2Lennart Poettering /* nothing */
636e813dc98ea40c58c6c85bc5e7e3c9f0904ea2Lennart Poettering break;
4b95f1798f22c1bb75295f448188560cb6ec9eceLennart Poettering
4b95f1798f22c1bb75295f448188560cb6ec9eceLennart Poettering case SOURCE_EXIT:
636e813dc98ea40c58c6c85bc5e7e3c9f0904ea2Lennart Poettering prioq_remove(s->event->exit, s, &s->exit.prioq_index);
636e813dc98ea40c58c6c85bc5e7e3c9f0904ea2Lennart Poettering break;
4b95f1798f22c1bb75295f448188560cb6ec9eceLennart Poettering }
4b95f1798f22c1bb75295f448188560cb6ec9eceLennart Poettering
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poettering if (s->pending)
4b95f1798f22c1bb75295f448188560cb6ec9eceLennart Poettering prioq_remove(s->event->pending, s, &s->pending_index);
4b95f1798f22c1bb75295f448188560cb6ec9eceLennart Poettering
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poettering if (s->prepare)
4b95f1798f22c1bb75295f448188560cb6ec9eceLennart Poettering prioq_remove(s->event->prepare, s, &s->prepare_index);
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poettering
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poettering sd_event_unref(s->event);
4b95f1798f22c1bb75295f448188560cb6ec9eceLennart Poettering }
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poettering
4b95f1798f22c1bb75295f448188560cb6ec9eceLennart Poettering free(s);
4b95f1798f22c1bb75295f448188560cb6ec9eceLennart Poettering}
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poettering
4b95f1798f22c1bb75295f448188560cb6ec9eceLennart Poetteringstatic int source_set_pending(sd_event_source *s, bool b) {
4b95f1798f22c1bb75295f448188560cb6ec9eceLennart Poettering int r;
4b95f1798f22c1bb75295f448188560cb6ec9eceLennart Poettering
4b95f1798f22c1bb75295f448188560cb6ec9eceLennart Poettering assert(s);
4b95f1798f22c1bb75295f448188560cb6ec9eceLennart Poettering assert(s->type != SOURCE_EXIT);
4b95f1798f22c1bb75295f448188560cb6ec9eceLennart Poettering
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poettering if (s->pending == b)
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poettering return 0;
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poettering
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poettering s->pending = b;
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poettering
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poettering if (b) {
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poettering s->pending_iteration = s->event->iteration;
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poettering
6cb08a8930bdaca950b152b1e8b82466ed59511cLennart Poettering r = prioq_put(s->event->pending, s, &s->pending_index);
6cb08a8930bdaca950b152b1e8b82466ed59511cLennart Poettering if (r < 0) {
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poettering s->pending = false;
0eac462399c8e87bcce252cf058eba9f2678f2bdLennart Poettering return r;
0eac462399c8e87bcce252cf058eba9f2678f2bdLennart Poettering }
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poettering } else
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poettering assert_se(prioq_remove(s->event->pending, s, &s->pending_index));
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poettering
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poettering if (s->type == SOURCE_REALTIME) {
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poettering prioq_reshuffle(s->event->realtime_earliest, s, &s->time.earliest_index);
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poettering prioq_reshuffle(s->event->realtime_latest, s, &s->time.latest_index);
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poettering } else if (s->type == SOURCE_MONOTONIC) {
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poettering prioq_reshuffle(s->event->monotonic_earliest, s, &s->time.earliest_index);
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poettering prioq_reshuffle(s->event->monotonic_latest, s, &s->time.latest_index);
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poettering }
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poettering
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poettering return 0;
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poettering}
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poettering
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poetteringstatic sd_event_source *source_new(sd_event *e, EventSourceType type) {
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poettering sd_event_source *s;
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poettering
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poettering assert(e);
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poettering
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poettering s = new0(sd_event_source, 1);
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poettering if (!s)
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poettering return NULL;
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poettering
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poettering s->n_ref = 1;
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poettering s->event = sd_event_ref(e);
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poettering s->type = type;
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poettering s->pending_index = s->prepare_index = PRIOQ_IDX_NULL;
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poettering
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poettering return s;
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poettering}
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poettering
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poettering_public_ int sd_event_add_io(
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poettering sd_event *e,
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poettering int fd,
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poettering uint32_t events,
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poettering sd_event_io_handler_t callback,
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poettering void *userdata,
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poettering sd_event_source **ret) {
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poettering
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poettering sd_event_source *s;
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poettering int r;
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poettering
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poettering assert_return(e, -EINVAL);
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poettering assert_return(fd >= 0, -EINVAL);
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poettering assert_return(!(events & ~(EPOLLIN|EPOLLOUT|EPOLLRDHUP|EPOLLPRI|EPOLLERR|EPOLLHUP|EPOLLET)), -EINVAL);
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poettering assert_return(callback, -EINVAL);
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poettering assert_return(ret, -EINVAL);
0eac462399c8e87bcce252cf058eba9f2678f2bdLennart Poettering assert_return(e->state != SD_EVENT_FINISHED, -ESTALE);
0eac462399c8e87bcce252cf058eba9f2678f2bdLennart Poettering assert_return(!event_pid_changed(e), -ECHILD);
0eac462399c8e87bcce252cf058eba9f2678f2bdLennart Poettering
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poettering s = source_new(e, SOURCE_IO);
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poettering if (!s)
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poettering return -ENOMEM;
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poettering
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poettering s->io.fd = fd;
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poettering s->io.events = events;
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poettering s->io.callback = callback;
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poettering s->userdata = userdata;
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poettering s->enabled = SD_EVENT_ON;
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poettering
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poettering r = source_io_register(s, s->enabled, events);
be808ea083fa07271116b4519c3c27fd20c5f077Tom Gundersen if (r < 0) {
be808ea083fa07271116b4519c3c27fd20c5f077Tom Gundersen source_free(s);
be808ea083fa07271116b4519c3c27fd20c5f077Tom Gundersen return -errno;
be808ea083fa07271116b4519c3c27fd20c5f077Tom Gundersen }
9c5e12a4314e7192e834e1b855e5e80111e636a6Tom Gundersen
7586f4d172dd9c3ccc3126fc47dca9e49adec132Tom Gundersen *ret = s;
d74fb368b18f0fbd9a4fe6f15691bbea7f3c4a01Tom Gundersen return 0;
be808ea083fa07271116b4519c3c27fd20c5f077Tom Gundersen}
be808ea083fa07271116b4519c3c27fd20c5f077Tom Gundersen
static int event_setup_timer_fd(
sd_event *e,
EventSourceType type,
int *timer_fd,
clockid_t id) {
struct epoll_event ev = {};
int r, fd;
sd_id128_t bootid;
assert(e);
assert(timer_fd);
if (_likely_(*timer_fd >= 0))
return 0;
fd = timerfd_create(id, TFD_NONBLOCK|TFD_CLOEXEC);
if (fd < 0)
return -errno;
ev.events = EPOLLIN;
ev.data.ptr = INT_TO_PTR(type);
r = epoll_ctl(e->epoll_fd, EPOLL_CTL_ADD, fd, &ev);
if (r < 0) {
close_nointr_nofail(fd);
return -errno;
}
/* When we sleep for longer, we try to realign the wakeup to
the same time wihtin each minute/second/250ms, so that
events all across the system can be coalesced into a single
CPU wakeup. However, let's take some system-specific
randomness for this value, so that in a network of systems
with synced clocks timer events are distributed a
bit. Here, we calculate a perturbation usec offset from the
boot ID. */
if (sd_id128_get_boot(&bootid) >= 0)
e->perturb = (bootid.qwords[0] ^ bootid.qwords[1]) % USEC_PER_MINUTE;
*timer_fd = fd;
return 0;
}
static int event_add_time_internal(
sd_event *e,
EventSourceType type,
int *timer_fd,
clockid_t id,
Prioq **earliest,
Prioq **latest,
uint64_t usec,
uint64_t accuracy,
sd_event_time_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(usec != (uint64_t) -1, -EINVAL);
assert_return(accuracy != (uint64_t) -1, -EINVAL);
assert_return(e->state != SD_EVENT_FINISHED, -ESTALE);
assert_return(!event_pid_changed(e), -ECHILD);
assert(timer_fd);
assert(earliest);
assert(latest);
if (!*earliest) {
*earliest = prioq_new(earliest_time_prioq_compare);
if (!*earliest)
return -ENOMEM;
}
if (!*latest) {
*latest = prioq_new(latest_time_prioq_compare);
if (!*latest)
return -ENOMEM;
}
if (*timer_fd < 0) {
r = event_setup_timer_fd(e, type, timer_fd, id);
if (r < 0)
return r;
}
s = source_new(e, type);
if (!s)
return -ENOMEM;
s->time.next = usec;
s->time.accuracy = accuracy == 0 ? DEFAULT_ACCURACY_USEC : accuracy;
s->time.callback = callback;
s->time.earliest_index = s->time.latest_index = PRIOQ_IDX_NULL;
s->userdata = userdata;
s->enabled = SD_EVENT_ONESHOT;
r = prioq_put(*earliest, s, &s->time.earliest_index);
if (r < 0)
goto fail;
r = prioq_put(*latest, s, &s->time.latest_index);
if (r < 0)
goto fail;
*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)
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_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;
}
} 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;
}
}
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;
}
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 events) {
assert(e);
assert(s);
assert(s->type == SOURCE_IO);
s->io.revents = events;
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 (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 (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;
}
sd_event_source_ref(s);
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;
}
if (r < 0) {
log_debug("Event source %p returned error, disabling: %s", s, strerror(-r));
sd_event_source_set_enabled(s, SD_EVENT_OFF);
}
sd_event_source_unref(s);
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);
r = s->prepare(s, s->userdata);
if (r < 0)
return r;
}
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[EPOLL_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;
m = epoll_wait(e->epoll_fd, ev_queue, EPOLL_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 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);
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;
}