Commit graph

71 commits

Author SHA1 Message Date
Jo-Philipp Wich
13d9b04fb0 uloop: add support for user defined signal handlers
Reuse and extend the existing signal waker pipe mechanism to add user
defined signal handling functionality to uloop.

This commit introduces two new api functions `uloop_signal_add()` and
`uloop_signal_remove()` along with a new structure type `uloop_signal`
to allow adding and removing arbitrary signal handlers.

Registered signal handlers are maintained in a linked list and matched
by their signo member value which allows registering multiple handlers
for the same signal numbers.

Upon registering a new signal handler, the existing handler is saved
in the `uloop_signal` structure. When removing the user defined signal
handler, the original behavior is restored.

The Lua binding has been updated as well to support the new signal
handler mechanism.

Signed-off-by: Jo-Philipp Wich <jo@mein.io>
2023-11-02 17:56:45 +01:00
Jo-Philipp Wich
82fa6480de uloop: add support for interval timers
So far, the only way to implement periodic interval timers was to use
one-shot uloop_timeout timers which are rearmed within their completion
callback immediately on expiration.

While simple, this approach is not very precise and interval lengths will
slowly drift over time, due to callback execution overhead, scheduling
granularity etc.

In order to make uloop provide stable and precise interval timer
capabilities, this commit introduces a new `uloop_interval` structure
along with the new related `uloop_interval_set()`, `uloop_interval_cancel()`
and `uloop_interval_remaining()` api functions.

Periodic timers are implemented using the timerfd facility an Linux and
kqueue EVFILT_TIMER events on macOS/BSD.

The Lua binding has been updated to include support for the new timer type
as well.

Signed-off-by: Jo-Philipp Wich <jo@mein.io>
2023-11-02 17:49:55 +01:00
Felix Fietkau
75a3b870ca uloop: add support for integrating with a different event loop
- support reading the next timeout in order to determine the poll timeout
- add a callback for fd add/delete/update

Signed-off-by: Felix Fietkau <nbd@nbd.name>
2023-05-23 15:32:36 +02:00
Felix Fietkau
362951a2d9 uloop: fix uloop_run_timeout
Avoid running infinite poll loop, fix timeout value

Signed-off-by: Felix Fietkau <nbd@nbd.name>
2023-05-23 15:32:36 +02:00
Stijn Tintel
3344157381 uloop: add uloop_timeout_remaining64
This uses the same return type as tv_diff so we don't need to check for
integer overflow.

Signed-off-by: Stijn Tintel <stijn@linux-ipv6.be>
Acked-by: Jo-Philipp Wich <jo@mein.io>
Acked-by: John Crispin <john@phrozen.org>
2021-11-04 13:05:24 +02:00
Stijn Tintel
123e976f3d uloop: restore return type of uloop_timeout_remaining
The uloop_timeout_remaining function is public and changing its return
type breaks ABI. Change the return type back to int, and return INT_MIN
or INT_MAX if the value returned by tv_diff would overflow integer.

Fixes: be3dc7223a ("uloop: avoid integer overflow in tv_diff")
Signed-off-by: Stijn Tintel <stijn@linux-ipv6.be>
Acked-by: Jo-Philipp Wich <jo@mein.io>
Acked-by: John Crispin <john@phrozen.org>
2021-11-04 13:03:25 +02:00
Stijn Tintel
be3dc7223a uloop: avoid integer overflow in tv_diff
The tv_diff function can potentially overflow as soon as t2->tv_sec is
larger than 2147483. This is very easily hit in ujail, after only
2147484 seconds of uptime, or 24.85 days.

Improve the behaviour by changing the return type to int64_t.

Fixes: FS#3943
Signed-off-by: Stijn Tintel <stijn@linux-ipv6.be>
2021-11-04 01:45:46 +02:00
Petar Paradzik
f714be125c uloop: make SIGCHLD signal handling optional
Some programs want to manage their own child life cycle without using
SIGCHLD signal handler. In these cases, uloop is reaping children for
them because they don't have SIGCHLD handler set. This patch makes it
possible to disable reaping children through 'uloop_handle_sigchld'
variable.

Signed-off-by: Petar Paradzik <petar.paradzik@sartura.hr>
2017-09-29 13:37:17 +02:00
Michal Sojka
7a1057604e uloop: Fix race condition in SIGCHLD handling
When uloop_process_add() is called outside of uloop_run(), i.e. not
from a callback (which is the case of at least utrace and ujail),
child events can be missed. The reason is that when SIGCHILD handler
is installed in uloop_run(), after the uloop_process_add() is called,
then an initial signal could be missed.

Commit 4e3a47a ("uloop: use a waker for notifying sigchld and loop
cancel events", 2016-06-09) solved a similar problem and introduced
uloop_init() but forgot to move a call to uloop_setup_signals() there.
This is what this commit does.

Now, uloop_process_add() can be called any time after uloop_init()
without missing any event.

Signed-off-by: Michal Sojka <sojkam1@fel.cvut.cz>
Acked-by: Yousong Zhou <yszhou4tech@gmail.com>
2017-09-15 15:39:42 +08:00
Felix Fietkau
fd57eea9f3 uloop: allow passing 0 as timeout to uloop_run
Useful for processing only immediate timers and fds

Signed-off-by: Felix Fietkau <nbd@nbd.name>
2017-06-17 11:47:49 +02:00
Felix Fietkau
4bc3decf87 uloop: fix a regression in timeout handling
Variable confusion was breaking timers

Fixes: 368fd26458 ("uloop: allow specifying a timeout for uloop_run()")
Signed-off-by: Felix Fietkau <nbd@nbd.name>
2017-06-17 11:40:11 +02:00
Felix Fietkau
368fd26458 uloop: allow specifying a timeout for uloop_run()
This can be useful for cleanup with pending timers, or for hooking into
existing code that does not use uloop

Signed-off-by: Felix Fietkau <nbd@nbd.name>
2017-06-01 11:24:44 +02:00
Felix Fietkau
de3f14b643 uloop: add uloop_cancelling function
Returns true if uloop_run is still running and uloop_cancelled is set

Signed-off-by: Felix Fietkau <nbd@nbd.name>
2017-02-03 16:52:21 +01:00
Eyal Birger
d197c8ffa3 uloop: handle waker pipe write() return value
Recent glibc warns if result of read() or write() is unused.

Added a retry in case of EINTR, all other faults are silently discarded.

Signed-off-by: Eyal Birger <eyal.birger@gmail.com>

-----
- I was not able to reproduce the EINTR case, but it seems to be the right
  thing to do
- Retrying on EAGAIN in this case would be weird as there is no one to read
  from the other end of the pipe. We could call waker_consume() directly but
  since the size of the message is just one byte, I think this would be dead
  code
2016-06-26 13:05:54 +02:00
Matthias Schiffer
1ad3d93eb8 loop: make uloop_run() return the cancelling signal
When a process quits in response to a signal it handles, it should to so
be re-sending the signal to itself. This especially important for SIGINT,
as is explained in [1].

uloop currently hides the reason for quitting uloop_run(). Fix this by
returning the signal that caused the loop to quit (or 0 when uloop_end()
was used), so a program using loop an comply with [1].

[1] https://www.cons.org/cracauer/sigint.html

Signed-off-by: Matthias Schiffer <mschiffer@universe-factory.net>
2016-06-26 12:55:31 +02:00
Felix Fietkau
c2f2c47f3e uloop: add missing waker_pipe initialization
Signed-off-by: Felix Fietkau <nbd@nbd.name>
2016-06-15 15:14:51 +02:00
Yousong Zhou
4e3a47a4cb uloop: use a waker for notifying sigchld and loop cancel events
Fix a race condition when do_sigchld, uloop_cancelled were set just
before epoll_wait(timeout=-1), resulting the loop stuck in the syscall
without noticing the events just happened

Signed-off-by: Yousong Zhou <yszhou4tech@gmail.com>
Signed-off-by: Felix Fietkau <nbd@nbd.name>
2016-06-15 11:54:37 +02:00
Felix Fietkau
1257a38a6e uloop: revert signalfd support for now
It hasn't fixed the reported race condition and it introduced some new
issues.

Signed-off-by: Felix Fietkau <nbd@nbd.name>
2016-05-19 10:59:48 +02:00
Felix Fietkau
93be9309b8 uloop: add back support for overriding signal handlers when signalfd is in use
Signed-off-by: Felix Fietkau <nbd@nbd.name>
2016-05-17 13:59:05 +02:00
Felix Fietkau
b06cd8c58e uloop: retry waitpid on signal interrupt
Signed-off-by: Felix Fietkau <nbd@nbd.name>
2016-05-17 13:27:44 +02:00
Felix Fietkau
6a75b3b643 uloop: try to use signalfd for signal handling if available
Signed-off-by: Felix Fietkau <nbd@nbd.name>
2016-05-17 13:23:38 +02:00
Felix Fietkau
8ae74b4378 uloop: move epoll code into a separate file
Signed-off-by: Felix Fietkau <nbd@nbd.name>
2016-05-17 13:23:38 +02:00
Felix Fietkau
4b0aa9ccc2 uloop: move kqueue code into a separate file
Signed-off-by: Felix Fietkau <nbd@nbd.name>
2016-05-17 13:23:38 +02:00
John Crispin
b8d9b382e3 allow process callback to call uloop_end()
Signed-off-by: John Crispin <blogic@openwrt.org>
2015-03-21 05:50:23 +01:00
Rafał Miłecki
827ad8337e uloop: ignore SIGPIPE by default
Most app don't want to crash because of unhandled SIGPIPE. It could
happen is such trivial situations like writing to socket.

Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
2015-01-28 10:51:15 +01:00
Yousong Zhou
08c27ceb01 uloop: optimize uloop_timeout_set() implementaiton a bit.
Signed-off-by: Yousong Zhou <yszhou4tech@gmail.com>
2015-01-21 20:02:46 +01:00
Michel Stam
464e05e33b uloop: Do not override signal handlers not installed by us
Signed-off-by: Michel Stam <m.stam@fugro.nl>
2014-10-12 13:21:20 +02:00
Michel Stam
213122a083 uloop: Remove uloop_cancelled variable, it is not used anywhere
Signed-off-by: Michel Stam <m.stam@fugro.nl>
2014-10-12 13:21:17 +02:00
Luka Perkov
f32a53f92b uloop: fix multiple calls to uloop_run()
Signed-off-by: Luka Perkov <luka@openwrt.org>
2014-05-05 11:24:07 +02:00
Felix Fietkau
73a88451dd uloop: clear uloop_fd::error on add
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
2014-04-26 16:55:17 +02:00
Karl Vogel
926121113b uloop: Add flag to allow callback to be called on error conditions.
In some conditions, an application is interested in errors happening
on a file descriptor and might be able to resolve the issue in the
callback function.

This patch adds a flag to notify the uloop framework that errors
should be passed to the callback function, instead of silently
removing the fd from the polling set.

Signed-off-by: Karl Vogel <karl.vogel@gmail.com>
2014-02-23 18:18:32 +01:00
Kristian Evensen
13a9b7c709 Restore signal handler after uloop_run()
uloop_run calls uloop_setup_signals() to set up signal handling before the while
loop, but does not remove the signal handling after the loop has ended. This can
cause problems for for example applications using the ubus file descriptor in
their own event loops, and perhaps with their own signal handling.

This patch stores the signal handle that was in place when the initial
uloop_run() call was made, and restores the handle when this call returns.
For recursive calls, the signal handler is not updated.

One use-case I experienced was an application that subscribed to several ubus
objects and used the ubus file descriptor in its own event loop. Even though
ubus_register_subscriber() (which calls uloop_run()) had returned, the signal
handler was not removed. This caused SIGINT not to be caught by the application.

Signed-off-by: Kristian Evensen <kristian.evensen@gmail.com>
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
2013-10-22 17:26:05 +02:00
Felix Fietkau
04f194aa8a uloop: fix deleting pending fd events on uloop_fd_del
When a fd gets deleted internally due to errors, fd->registered gets set
to false before events are moved to the staging array.
This leads to pending events not getting cleared properly when the fd
user finally calls uloop_fd_del.
Fix this by moving the check down and always checking for pending
events.

Signed-off-by: Felix Fietkau <nbd@openwrt.org>
2013-08-01 00:01:40 +02:00
Helmut Schaa
510e4956e5 uloop: Fix incorrect timeout
uloop timeouts are calculated based on a time value that was fetched
before any callbacks were executed. Hence, the next timeout is off by
the time the callback execution took which can lead to strange side
effects.

Fix this by calculating the next timeout based on a fresh time value.

Signed-off-by: Helmut Schaa <helmut.schaa@googlemail.com>
2013-07-24 15:01:19 +02:00
Felix Fietkau
b9ebdbcc64 uloop: fix corner cases with recursive uloop_run calls
With multiple recursive calls to uloop_run, the callback for the same fd
can be run multiple times from different levels in the stack.
Prevent this by tracking the stack of uloop_fd callbacks and buffering new
incoming events for fds already on the stack.

Signed-off-by: Felix Fietkau <nbd@openwrt.org>
2013-06-18 12:05:09 +02:00
Felix Fietkau
35cee2c206 uloop: fix event flags processing on mac os x
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
2013-06-18 12:05:09 +02:00
Felix Fietkau
e386259632 libubox: make uloop_fd::flags generic
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
2013-06-18 12:05:09 +02:00
Felix Fietkau
cd5238b500 uloop: fix edge trigger handling on mac os x
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
2013-06-18 11:02:20 +02:00
Felix Fietkau
ae40b66130 uloop: rework event processing, fix use-after-free issues
Recursive calls to uloop_run() need to process already fetched events
first, before running kqueue/epoll to get more.

The state of cur_fd/cur_nfds and the event list needs to be maintained
properly to prevent accidental running of events pointing at deleted
uloop_fd structs.

Signed-off-by: Felix Fietkau <nbd@openwrt.org>
2013-06-11 12:55:21 +02:00
Felix Fietkau
766ff98050 uloop: remove file descriptors if neither read nor write notification is requested
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
2013-01-31 16:43:08 +01:00
Jo-Philipp Wich
8b0d933154 uloop: rename uloop_timeout_pending() to uloop_timeout_remaining() 2013-01-23 19:33:12 +01:00
Jo-Philipp Wich
77984bd24d uloop: add uloop_timeout_pending() function to determine the remaining time of an active timeout 2013-01-23 19:32:45 +01:00
Felix Fietkau
569bc29c5a uloop: replace copyright info (code has been completely rewritten over time), relicense to ISC
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
2013-01-13 09:47:51 +01:00
Felix Fietkau
dde64e47ca uloop: use clock_gettime with the monotonic clock instead of using gettimeofday()
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
2013-01-06 03:04:04 +01:00
Felix Fietkau
b7930023ee uloop: add back state tracking on mac os x, it seems to work reliably now (after the other fixes)
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
2013-01-05 16:04:55 +01:00
Felix Fietkau
17f4e41ecb uloop: improve edge trigger reliability on mac os x
Sometimes after re-arming a fd, an initial event for reads is not generated,
even though there is data pending. Work around this by making the trigger
level-triggered first, then switching to edge trigger after processing the first
event.

Signed-off-by: Felix Fietkau <nbd@openwrt.org>
2013-01-04 03:18:42 +01:00
Felix Fietkau
c2916d7bcc uloop: ensure SIGCHLD is properly received on mac os x
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
2013-01-04 03:13:29 +01:00
Felix Fietkau
6a8df07590 uloop: do less state/change tracking for kevent() on mac os x, it is unreliable
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
2013-01-04 01:15:48 +01:00
Felix Fietkau
e7825661a2 uloop: fix immediate timeout processing on mac os x
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
2013-01-01 23:37:22 +01:00
Felix Fietkau
9c8ab5d64c utils: move ARRAY_SIZE from uloop to utils.h
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
2012-12-31 15:24:27 +01:00