86 Commits
Author SHA1 Message Date
Joachim Nilsson de89b6647d Update ChangeLog and bump ABI + release version for v2.1.3 release
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2018-09-06 22:03:16 +02:00
Joachim Nilsson 7eee63e5eb debian: The bare .so symlink should go in the -dev package [Policy]
Clarify rules: libuev.a and libuev.so are for initial linking.  See
Debian Policy sect. 8.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2018-09-06 22:02:56 +02:00
Joachim Nilsson c780b82929 Update ChangeLog for upcoming bug fix release v2.1.3
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2018-09-05 17:48:50 +02:00
Joachim Nilsson cccaabfad5 Don't call uev_timer_set() when stopping timer, just close() it
The semantics for timerfd in Linux is to use close() to stop,
so no need for the extra overhead with uev_timer_set().

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2018-09-04 21:22:33 +02:00
Joachim Nilsson 6d33c56d0f Return early and OK if signal watcher is already stopped
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2018-09-04 07:16:01 +02:00
Joachim Nilsson 6ae98d135c tests: Restart stopped timer before calling uev_exit()
There's an issue with uftpd not exiting properly.  Cannot nail it down
properly but it seems to be related to the stopping of active timers.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2018-09-04 07:11:23 +02:00
Joachim Nilsson d3e5900f73 Refactor, use LIST_FOREACH_SAFE() instead of while() in uev_exit()
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2018-09-01 18:55:22 +02:00
Joachim Nilsson 2ff15101ae New API test to verify uev_exit() terminates properly
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2018-09-01 18:54:56 +02:00
Joachim Nilsson 04d9e1c80a Bump version for next bugfix release cycle
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2018-09-01 18:50:30 +02:00
Joachim Nilsson 0674fb8db4 Reminder to investigate for next release
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2018-09-01 18:50:18 +02:00
Joachim Nilsson c4ac2eae5d Update example, use /dev/input/js0, the first joystick
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2018-05-31 23:37:39 +02:00
Joachim Nilsson 951f959549 Bump version for v2.1.2 release
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2018-02-27 00:08:54 +01:00
Joachim Nilsson a2900279f6 Update ChangeLog for v2.1.2 release
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2018-02-27 00:06:26 +01:00
Joachim Nilsson f9c9f24afb debian/: Fix minor packaging issues between base and -dev .debs
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2018-02-27 00:05:45 +01:00
Joachim Nilsson ab05f71bbc Fix #17: Check for existence of AM_PROG_AR macro
This patch facilitates building newer versions of libuEv on systems with
older versions of autoconf and automake.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2018-02-26 22:30:44 +01:00
Joachim Nilsson 856546f4c7 Refactor, simplify
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2018-01-28 21:36:47 +01:00
Joachim Nilsson 748ebc998c Minor, whitespace
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2018-01-28 21:17:43 +01:00
Joachim Nilsson 0e97bfdc5a tests/: Return result of tests, not return value of uev_run()
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2018-01-28 16:32:38 +01:00
Joachim Nilsson cebe66e8a4 Update change logs and bump version for v2.1.1 release
Also bump ABI revision, code change.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2018-01-28 14:03:56 +01:00
Joachim Nilsson dd651ae791 Call watcher callback as last action for watcher, may delete itself
A watcher callback may be a timeout callback, or similar, that deletes
itself and the watcher.  So we should not dereference anything in the
watcher after the callback.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2018-01-28 13:53:10 +01:00
Joachim Nilsson a528405258 Minor, whitespace
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2018-01-28 13:50:50 +01:00
Joachim Nilsson 70f04c10e1 Merge pull request #13 from tisyang/master
Fix example code of timer usage not alarm in README.md
2017-11-22 02:33:35 +01:00
tisyang e3dca8255d Fix example code of timer usage not alarm in README.md 2017-11-22 09:25:12 +08:00
Joachim Nilsson dbf8c0dae2 Doc: a timer must have a non-zero timeout value to be armed properly
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-11-19 11:29:19 +01:00
Joachim Nilsson f75b1d5080 debian/changelog: New upstream release, new .deb package
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-11-14 17:41:09 +01:00
Joachim Nilsson 7f16876932 Bump version for v2.1.0 release
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-11-14 13:47:22 +01:00
Joachim Nilsson d7451cadd7 Update ChangeLog for v2.1.0 release
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-11-14 13:47:00 +01:00
Joachim Nilsson 804218ba44 Travis-CI: Test build with both GCC and Clang (LLVM)
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-11-14 13:39:02 +01:00
Joachim Nilsson 4d1875e49c Update, file used by redirect example
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-11-14 13:31:47 +01:00
Joachim Nilsson 3b356222cb Travis-CI: Fix missing .sh extension to autogen script
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-11-14 13:14:21 +01:00
Joachim Nilsson 9ec5dff692 Travis-CI: Enable examples in both regular and Coverity runs
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-11-14 13:03:28 +01:00
Joachim Nilsson e35c065d77 uev.c: Stop I/O watcher immediately on EPOLLERR or EPOLLHUP
No need to check fd with fcntl().  On EPOLLERR the descriptor has an
error condition that must bed ACK'ed by the callback.  On EPOLLHUP
we got a hang-up on the remote end, usually a stream or pipe, either
way the callback must ACK this too, regardless.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-11-14 12:56:39 +01:00
Joachim Nilsson 7d97b9f04a Bump version for v2.1.0 release cycle, pre-test
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-11-14 12:56:39 +01:00
Joachim Nilsson 9499052989 Update ChangeLog for upcoming v2.1.0 release
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-11-14 12:56:39 +01:00
Joachim Nilsson c77cee19e8 Bullet lists should not end with a period
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-11-14 12:56:39 +01:00
Joachim Nilsson fbcd200fd5 uev.h: Remind hardcore devs about checking common errors in callback
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-11-14 12:56:39 +01:00
Joachim Nilsson 84661a1b12 README: Mention error handling early, and point to API docs
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-11-14 12:56:39 +01:00
Joachim Nilsson ed313a1422 Update API documentation, UEV_ERROR and UEV_HUP must be handled
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-11-14 12:56:39 +01:00
Joachim Nilsson 28e735fd81 configure: Add missing --enable-examples option, mentioned in docs
The `examples/` directory was never built.  The documentation however
indicated the existence of an `--enable-examples` option, which didn't
really exist.  This patch adds that option.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-11-14 12:56:39 +01:00
Joachim Nilsson 2bea4192db Handle UEV_HUP properly in examples and unit tests
If an I/O watcher callback fails to read(), returning zero, we check
events for UEV_HUP to detect EOF or socket remote end shutdown().

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-11-14 12:56:39 +01:00
Joachim Nilsson d52254b4ec Make sure to restart the I/O watcher on UEV_ERROR
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-11-14 12:17:41 +01:00
Joachim Nilsson ebb574136b Make sure to restart I/O watcher when event loop returns error
This patch adds UEV_ERROR handling to the test I/O watcher, restarting
the watcher properly.  Also, additional error handling to read(), which
was unchecked and failed when fuzzing the libc read() function.

We also take the opportunity to document the reasons for when using the
w->fd (watcher descriptor) and when *not* to in the test.  Even to the
author this was confusing and looked suspicious.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-11-14 12:17:41 +01:00
Joachim Nilsson d7485c59ec Fix logical error, read before set, found by Valgrind
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-11-14 12:17:41 +01:00
Joachim Nilsson 505a7214a8 tests: Add basic error handling to callbacks, for reference
Many users look at both examples *and* unit tests to learn how to use a
library.  We should pride ourselves in that we have not just working but
also correct and readable tests.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-11-14 12:17:41 +01:00
Joachim Nilsson 9df7cbfc52 uev_timer_stop(): Check if already stopped to prevent double close()
Both cron and regular timers were closed twice on uev_exit(), first
when iterating over all watchers, next after each cb() has run in
uev_run().  This patch adds a check if a watcher is active before
attempting to stop it (again).

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-11-14 12:17:41 +01:00
Joachim Nilsson 6cbeb057b8 uev_timer_init(): Mark fd as uninitialized on error
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-11-14 12:17:41 +01:00
Joachim Nilsson 853604a65a Reorder switch in same order as enum, +minor whitespace
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-11-14 12:17:37 +01:00
Joachim Nilsson 35a54ef75e Follow-up to 2f9cce9, handle I/O watchers similar to timer+signal
This patch is a follow-up to 2f9cce9, and a complete refactor of
fe8f3f1 which first introduced the EPOLLERR and EPOLLHUP handling.
Then mainly for managing errors and hangups on stream sockets.

Now, instead of trying to reopen the epoll() fd, and breaking out
hard from the event loop on catastrophic error,  we now delegate
I/O watcher EPOLLERR and EPOLLHUP to the watcher callback, just
like other watchers.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-11-14 12:16:23 +01:00
Joachim Nilsson 966f29c207 Refactor, multiple if() statements into a switch()
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-11-13 17:01:55 +01:00
Joachim Nilsson 6bc1b88973 Refactor, main event loop cleanup and simplification
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-11-13 15:38:40 +01:00
Joachim Nilsson 7c86cc31f1 Reorder enum in order of first appearance in libuEv
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-11-13 15:02:06 +01:00
Joachim Nilsson d9f8caf0e8 Refactor 2f9cce9, stop timers and try to restart signal watchers
In 2f9cce9 the invalidate_watcher() function was introduced to stop
invalid timer/cron and signal watchers.  This patch refactors that
change to instead call the stop method for cron/timer and attempt to
restart failing signal watchers.

The cron/timer and signal watchers are quite different from regular
I/O watchers in that their internal "fd" is hidden from and not under
the control of the user, so we should try to handle them better.  For
the former two we cannot do much other than stop and call the user's
registered callback with UEV_ERROR, but for the latter we can at least
try to restart it.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-11-13 14:52:16 +01:00
Joachim Nilsson 3e5694cb76 Bump version for v2.0.0 release
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-11-11 16:46:34 +01:00
Joachim Nilsson f5806a28c0 Bump ABI, major change in how uev_run() and callbacks work
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-11-11 16:46:03 +01:00
Joachim Nilsson ef57250586 Change release target to run distcheck instead of dist
With distcheck we not only build the distribution files, but also runs
test suite and verifies that the resulting dist file(s) can be built.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-11-11 16:43:47 +01:00
Joachim Nilsson febace818b ChangeLog: Finishing touches for v2.0.0
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-11-11 16:41:46 +01:00
Joachim Nilsson 5496bf0931 Update debian/changelog for v2 release
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-11-11 16:41:18 +01:00
Joachim Nilsson cb93dd9c9d ChangeLog: Fix GIT diff URL
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-11-11 14:19:23 +01:00
Joachim Nilsson 341f7801fd Alert users of ABI breakage
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-11-11 14:17:49 +01:00
Joachim Nilsson dd475b5058 Move quote to API.md, need space to warn about ABI breakage in 2.0
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-11-11 14:17:49 +01:00
Joachim Nilsson 0a1a0ebffb Preparations for upcoming v2 release
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-11-11 14:17:49 +01:00
Joachim Nilsson 91bfe9faa7 Ignore global index files
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-11-11 13:59:55 +01:00
Joachim Nilsson ddfc1460eb redirect: Update example to handle new failure mode
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-11-11 13:59:05 +01:00
Joachim Nilsson 71e6d78fdc redirect: Use err.h functions for error handling
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-11-11 13:58:35 +01:00
Joachim Nilsson 5929295c37 Update joystick example with new failure mode
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-11-11 13:57:43 +01:00
Joachim Nilsson 412f04f413 API.md: Document uev_run() failure modes.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-11-10 23:41:17 +01:00
Joachim Nilsson f78348a92a uev_run(): Return unique error codes in case of actual error.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-11-10 23:40:49 +01:00
Joachim Nilsson d1f5062e79 Bump major version, for upcoming v2.0 release
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-11-10 22:26:03 +01:00
Joachim Nilsson 1037eed481 Minor simplification, result is never changed
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-11-10 22:25:12 +01:00
Joachim Nilsson 2f9cce9150 Do NOT exit event loop on timer/signal watcher error
This patch fixes a blocking issue discovered in the Finit project.
At shutdown, or when there is any problem with a timer or signal
watcher, the event loop is abruptly terminated.

Instead of unconditionally exiting the event loop on problems with a
single watcher, invalidate the watcher and run the callback one last
time with UEV_ERROR in the events argument.

This is a semantic change wrt. watchers and their callbacks, so the
major version number will be bumped accordingly to signal the severity
of this change.  From now on it is STRONGLY recommended that each call
back function check for UEV_ERROR.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-11-10 22:18:40 +01:00
Joachim Nilsson f3b3177963 Introduce UEV_ERROR, for unexpected error on timer+signal watchers
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-11-10 21:49:57 +01:00
Joachim Nilsson ad262efa97 Update documentation to mention lack of support for regular files
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-10-24 08:10:36 +02:00
Joachim Nilsson 0dfc9152bd uev_run(): Exit event loop as soon as there are no more watchers
The purpose of the event loop is to process events on all registered
watches.  When all watchers have completed the event loop should exit.

Having implemented a workaround for issue #12 in commit e0cebc3 it has
become evident we need to check the list of watchers at the beginning
of the event loop rather than the end, since the workaround skips past
the end.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-10-24 00:33:28 +02:00
Joachim Nilsson 9642443a7c Clean up redirect example a bit
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-10-22 11:16:10 +02:00
Joachim Nilsson 98748277f3 Add Emacs hints for indentation
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-10-21 20:52:30 +02:00
Joachim Nilsson 1de445535e Fix periodic timer example
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-10-21 20:51:08 +02:00
Joachim Nilsson 151f9294c9 Simplify Origin & References section
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-10-21 20:50:52 +02:00
Joachim Nilsson 61bb69795d Use FIONREAD to detect if stdin has data, safer than just select()
When handling the stdin redirect workaround we should use FIONREAD to
figure out if there is any data to read.

When there is no more data to read from stdin we remove the watcher from
internal bookkeeping but allow the callback to run one last time so it
can detect a short read.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-10-21 19:55:17 +02:00
Joachim Nilsson d46ff8e396 redirect: Make sure example application does not exit on len==0
We want to continue running the event loop until it is exited properly,
not if the callback for stdin detects a short read.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-10-21 19:54:00 +02:00
Joachim Nilsson e0cebc33b1 Fix #12: Implement workaround for application < foo.txt
This patch implements a workaround for issue #12, i.e. when an I/O
watcher for redirected stdin is registered and causes epoll_ctl()
to return EPERM.

The workaround registers the watcher as `active = -1` and bypasses
the epoll_wait() call in the main loop until all data has been read
from stdin and the temporary -1 watcher(s) have completed.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-10-21 19:10:04 +02:00
Joachim Nilsson 82a1018dd2 Ignore TroglOS build files
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-10-21 18:47:31 +02:00
Joachim Nilsson 58ec8e1d6f Simple example of stdin redirect problem, issue #12
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-10-21 18:46:55 +02:00
Joachim Nilsson 704d7d5612 Refactor, leverage internal API
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-10-21 12:47:01 +02:00
Joachim Nilsson ce4f8d6ef5 Follow-up to ed5c9bb, fix examples Makefile after relocation
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-10-21 12:21:51 +02:00
Joachim Nilsson 6f5e6e5232 Make internal API more private
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-10-21 12:04:13 +02:00
Joachim Nilsson 9751be5859 Update ChangeLog diff URLs
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-09-22 16:26:02 +02:00
29 changed files with 693 additions and 218 deletions

No files matched your search

+7 -1
View File
@@ -7,8 +7,14 @@
*.la
*.lo
*.html
.config
.deps
.libs
.unpacked
ID
GTAGS
GRTAGS
GPATH
compile
config.*
configure
@@ -27,4 +33,4 @@ bench
libuev*.tar.*
libuev.pc
!libuev.pc.in
test-driver
test-driver
+7 -2
View File
@@ -5,6 +5,11 @@ language: c
# Use docker for quicker builds, it now allows https://docs.travis-ci.com/user/apt/
sudo: false
# Test build with both GCC and Clang (LLVM)
compiler:
- gcc
- clang
env:
global:
# The next declaration is the encrypted COVERITY_SCAN_TOKEN, created
@@ -17,13 +22,13 @@ addons:
name: "troglobit/libuev"
description: "libuEv | Simple event loop for Linux"
notification_email: troglobit@gmail.com
build_command_prepend: "./autogen && ./configure"
build_command_prepend: "./autogen.sh && ./configure --enable-examples"
build_command: "make clean all"
branch_pattern: dev
script:
- ./autogen.sh
- ./configure --disable-silent-rules
- ./configure --disable-silent-rules --enable-examples
- make clean
- make -j5
- make check
+84 -13
View File
@@ -11,13 +11,21 @@ API Documentation
* [Joystick Example](#joystick-example)
> “Event driven software improves concurrency” -- [Dave Zarzycki, Apple][]
Introduction
------------
The C API to [libuEv][], listed in `uev/uev.h`, handles three different
types of events: I/O (files, sockets, message queues, etc.), timers, and
types of events: I/O (pipes, sockets, message queues, etc.), timers, and
signals. The [Summary](#summary) details a slight caveat on signals.
Notice the *lack of support for regular files* and directories. This is
a limitation of the underlying Linux `epoll` interface which will return
`EPERM` for regular files. Except for the special case when `stdin` is
redirected from the command line. See `examples/redirect.c` for more on
this particular case.
Timers can be either relative, timeout in milliseconds, or absolute with
a time given in `time_t`, see `mktime()` et al. Absolute timers are
called cron timers and their callbacks get an `UEV_HUP` error event if
@@ -39,6 +47,11 @@ Overview
* w->fd holds the file descriptor or socket, and events is set by
* libuEv to indicate status: UEV_READ and/or UEV_WRITE with any of
* the optional UEV_HUP, UEV_RDHUP, or UEV_PRI for urgent read data.
*
* Note: UEV_ERROR may be returned for any watcher and must be checked
* by all callbacks. I/O watchers may also need to check UEV_HUP.
* Appropriate action, e.g. restart the watcher, is up to the
* application and is thus delegated to the callback.
*/
void callback (uev_t *w, void *arg, int events);
@@ -56,7 +69,7 @@ int uev_io_set (uev_t *w, int fd, int events);
int uev_io_start (uev_t *w);
int uev_io_stop (uev_t *w);
/* Timer watcher: schedule a relative timer, timeout and period in milliseconds */
/* Timer watcher: schedule a relative timer, timeout (must be non-zero) and period in milliseconds */
int uev_timer_init (uev_ctx_t *ctx, uev_t *w, uev_cb_t *cb, void *arg, int timeout, int period);
int uev_timer_set (uev_t *w, int timeout, int period); /* Change timeout or period */
int uev_timer_start (uev_t *w); /* Restart a stopped timer */
@@ -91,16 +104,20 @@ uev_init(&ctx);
### Register an Event Watcher
For each event to monitor, be it a signal, timer or file descriptor, a
*watcher* must be registered with the event context. The watcher, an
`uev_t`, is registered by calling the event type's `_init()` function
with the `uev_ctx_t` context, the callback, and an optional argument.
For each event to monitor, be it a signal, cron/timer or a file/network
descriptor, a *watcher* must be registered with the event context. The
watcher, an `uev_t`, is registered by calling the event type's `_init()`
function with the `uev_ctx_t` context, the callback, and an optional
argument.
Here is a signal example:
```C
void cleanup_exit(uev_t *w, void *arg, int events)
{
if (UEV_ERROR == events)
puts("Ignoring signal watcher error ...");
/* Graceful exit, with optional cleanup ... */
uev_exit(w->ctx);
}
@@ -117,6 +134,17 @@ int main(void)
}
```
Notice that the callback must be prepared to handle `UEV_ERROR`. I/O
watchers in particular, but also timer watchers, must be restarted if
required by the application. libuEv automatically tries to restart a
signal watcher, but should that fail the callback will return error as
well.
I/O watchers should also check for `UEV_HUP`, preferably when handling
any short `read()` or `write()` system calls. A short read on a socket
may be due to the remote end having performed a `shutdown()`. This is
signaled to the callback using `UEV_HUP` in the `events` mask.
### Start Event Loop
@@ -127,13 +155,24 @@ used to integrate [libuEv][] into another event loop.
In this example we set `flags` to none:
```C
uev_run(&ctx, UEV_NONE);
result = uev_run(&ctx, UEV_NONE);
```
With `flags` set to `UEV_ONCE` the event loop returns as soon as it has
served the first event. If `flags` is set to `UEV_ONCE | UEV_NONBLOCK`
the event loop returns immediately if no event is available.
```
if (result < 0)
errx(result, "Unrecoverable event loop error, error %d", result);
```
If the call to `uev_run()` fails you should notify the user somehow.
libuEv fails if there is an invalid pointer, if `uev_init()` was not
called, or recurring `epoll()` errors thare are impossible to recover
from should occur. This is true for individual watchers as well, in
particular signal and timer watchers which can fail in miserable ways.
**Note:** libuEv handles many types of errors, stream close, or peer
shutdowns internally, but also lets the callback run. This is useful
for stateful connections to be able to detect EOF.
@@ -143,8 +182,16 @@ for stateful connections to be able to detect EOF.
1. Set up an event context with `uev_init()`
2. Register event callbacks with the event context using
`uev_io_init()`, `uev_signal_init()` or `uev_timer_init()`
3. Start the event loop with `uev_run()`
4. Exit the event loop with `uev_exit()`, possibly from a callback
3. Make sure callbacks checks their `events` mask and handles:
- `UEV_ERROR`, e.g. I/O watchers must be restarted
- `UEV_HUP`, reading any remaining data on the descriptor
In both of these cases the watcher is stopped by libuEv. On HUP the
descriptor/connection must be reopened and the watcher reinitialized
with `uev_io_set()`, if required by the application.
4. Start the event loop with `uev_run()`
5. Exit the event loop with `uev_exit()`, possibly from a callback
**Note 1:** Make sure to use non-blocking stream I/O! Most hard to find
bugs in event driven applications are due to sockets and files being
@@ -167,7 +214,7 @@ for stateful connections to be able to detect EOF.
Using -luev
-----------
LibuEv is by default installed as a library with a few header files, you
libuEv is by default installed as a library with a few header files, you
should only ever need to include one:
```C
@@ -221,9 +268,32 @@ struct js_event {
uint8_t number; /* axis/button number */
} e;
/*
* Called on any joystick event
*
* Note: We handle errors here by exiting, for a background daemon with
* multiple watchers you may want another approach.
*/
static void joystick_cb(uev_t *w, void *arg, int events)
{
read(w->fd, &e, sizeof(e));
ssize_t cnt;
if (UEV_ERROR == events) {
/* Possibly joystick was unplugged */
warnx("Spurious problem with the joystick watcher, restarting.");
uev_io_start(w);
}
cnt = read(w->fd, &e, sizeof(e));
if (cnt < 0) {
warn("Failed reading joystick event");
return;
}
if (cnt == 0 || UEV_HUP == events) {
warn("Joystick disconnected");
return;
}
switch (e.type) {
case 1:
@@ -242,7 +312,7 @@ int main(void)
uev_t watcher;
uev_ctx_t ctx;
fd = open("/dev/input/js1", O_RDONLY, O_NONBLOCK);
fd = open("/dev/input/js0", O_RDONLY, O_NONBLOCK);
if (fd < 0)
errx(errno, "Cannot find a joystick attached.");
@@ -279,5 +349,6 @@ library) for [reference benchmarks][7] against [libevent][1] and
[5]: https://github.com/troglobit/uftpd
[6]: https://github.com/troglobit/finit
[7]: http://libev.schmorp.de/bench.html
[LibuEv]: https://github.com/troglobit/libuev
[libuEv]: https://github.com/troglobit/libuev
[GLIBC workaround]: https://sourceware.org/glibc/wiki/Y2038ProofnessDesign
[Dave Zarzycki, Apple]: http://www.youtube.com/watch?v=cD_s6Fjdri8
+101 -11
View File
@@ -4,6 +4,92 @@ Change Log
All notable changes to the project are documented in this file.
[v2.1.3][] - 2018-09-06
-----------------------
### Changes
- Update joystick example, use first device, `/dev/input/js0`
- Minor refactor of `uev_exit()`, use `_SAFE` macros to traverse
list of watchers instead of `while()`
- New API test to verify that `uev_exit()` terminates properly
- Make `uev_signal_stop()` idempotent
### Fixes
- Let `uev_timer_stop()` call `close()` on the timerfd directly, do not
call `uev_timer_set()` since that may cause lockups or hangs
[v2.1.2][] - 2018-02-27
-----------------------
### Changes
- Minor refactor of event loop after fixing the nasty use-after-free bug
in v2.1.1. Code can now be collapsed and noticeably simplified
### Fixes
- Issue #17: Check if `AM_PROG_AR` macro exists before calling it, fixes
problem building libuEv on systems with older autoconf + automake.
Patch by Markus Svilans
- Fix minor issue with unit tests, return result of test not event loop
[v2.1.1][] - 2018-01-28
-----------------------
### Fixes
- Fix use after free in main event loop if watcher deletes itself in
the callback. I.e., the callback must be the last action for the
watcher in the event loop.
- Doc timer example fix by @tisyang
- Doc timer updates, non-zero timeout required
[v2.1.0][] - 2017-11-14
-----------------------
### Changes
- Remove event loop error tracking used to trigger a `epoll_create1()`
at a certain error threshold. This tracking was first introduced in
[v1.1.0][], triggered by spurious `EPOLLERR` on I/O watchers
- Unconditionally stop I/O watchers that return `EPOLLERR` or `EPOLLHUP`
it is up to the watcher callback to clear the error and/or `read()`
the last few bytes from the descriptor. HUP usally means EOF, or that
the remote end of a stream or pipe closed, this may also be signaled
by `read()` returning zero
- Add missing `--enable-examples` to `configure` script
- Update documentation, both [README.md][] and [API.md][]
### Fixes
- Properly stop and de-register signal and cron/timer watchers from the
epoll socket in case of errors, problem introduced in [v2.0.0][]
- Mark watcher file descriptor as unintialized on internal error
- Fix double-close of cron/timer watchers. Problem triggered when the
timer expires and calls `uev_exit()`, which stops all watchers. When
the timer callback returns another call to stop the watcher triggered
the double `close()`
- Fix unit test's error handling in watcher callbacks, for reference
- Fix use-before-set in cronrun unit test
- Make sure to restart unit test's I/O watchers on `UEV_ERROR`
- Make sure to restart example I/O watchers on `UEV_ERROR`
- Properly check for `UEV_HUP` in unit tests and examples
[v2.0.0][] - 2017-11-11
-----------------------
Beware, this is a major release, introducing incompatible changes to the
failure modes of `uev_run()` and watcher callbacks. Most users will most
likely not notice any difference, but please read on.
### Changes
- `uev_run()` no longer exits the main event loop if an unrecoverable
error with a watcher occurs. Instead, the watcher is disabled and the
callback is run one last time with `events` set to `UEV_ERROR`
- Watcher callbacks must handle `UEV_ERROR` conditions. This pertains
in particular to signal and timer watchers
- Examples and API docs updated with the new failure modes
[v1.6.0][] - 2017-09-18
-----------------------
@@ -36,7 +122,7 @@ All notable changes to the project are documented in this file.
### Changes
- Add support for absolute timers with the `uev_cron_*()` API.
- Update build & install instructions in README
- Update build & install instructions in [README.md][]
### Fixes
- Fix `uev_timer_set()` so that it returns error in case the underlying
@@ -78,7 +164,7 @@ introduced in [v1.2.1][]. Apologies for any problems this may cause!
`pkg-config` your C program must now `#include <uev/uev.h>`
- Support for `EPOLLPRI` events for I/O watchers, thanks to Markus Svilans
- Simplified joystick example
- Updated `README` slightly
- Updated [README.md][] slightly
[v1.3.1][] - 2016-02-02
@@ -86,7 +172,7 @@ introduced in [v1.2.1][]. Apologies for any problems this may cause!
### Fixes
- Remove symlinks to Markdown files from GIT
- Distribute and install Markdown files: README.md, etc.
- Distribute and install Markdown files: [README.md][], etc.
[v1.3.0][] - 2016-01-22
@@ -122,7 +208,7 @@ Very minor release.
- Dropped [TODO.md][] from distribution archives, only for devs
### Fixes
- Lots of Markdown syntax fixes in both README and ChangeLog
- Lots of Markdown syntax fixes in both [README.md][] and ChangeLog
- Silence annoying warning from newer GNU ar in Ubuntu 15.10
@@ -280,7 +366,16 @@ v0.0.1 - 2012-03-17
Lua users mailing list.
[UNRELEASED]: https://github.com/troglobit/libuev/compare/v1.4.2...HEAD
[UNRELEASED]: https://github.com/troglobit/libuev/compare/v2.1.3...HEAD
[v2.1.3]: https://github.com/troglobit/libuev/compare/v2.1.2...v2.1.3
[v2.1.2]: https://github.com/troglobit/libuev/compare/v2.1.1...v2.1.2
[v2.1.1]: https://github.com/troglobit/libuev/compare/v2.1.0...v2.1.1
[v2.1.0]: https://github.com/troglobit/libuev/compare/v2.0.0...v2.1.0
[v2.0.0]: https://github.com/troglobit/libuev/compare/v1.6.0...v2.0.0
[v1.6.0]: https://github.com/troglobit/libuev/compare/v1.5.2...v1.6.0
[v1.5.2]: https://github.com/troglobit/libuev/compare/v1.5.1...v1.5.2
[v1.5.1]: https://github.com/troglobit/libuev/compare/v1.5.0...v1.5.1
[v1.5.0]: https://github.com/troglobit/libuev/compare/v1.4.2...v1.5.0
[v1.4.2]: https://github.com/troglobit/libuev/compare/v1.4.1...v1.4.2
[v1.4.1]: https://github.com/troglobit/libuev/compare/v1.4.0...v1.4.1
[v1.4.0]: https://github.com/troglobit/libuev/compare/v1.3.1...v1.4.0
@@ -298,6 +393,7 @@ Lua users mailing list.
[v1.0.1]: https://github.com/troglobit/libuev/compare/v1.0.0...v1.0.1
[v1.0.0]: https://github.com/troglobit/libuev/compare/v0.0.1...v1.0.0
[TODO.md]: https://github.com/troglobit/libuev/blob/master/TODO.md
[API.md]: https://github.com/troglobit/libuev/blob/master/API.md
[README.md]: https://github.com/troglobit/libuev/blob/master/README.md
[ChangeLog.md]: https://github.com/troglobit/libuev/blob/master/ChangeLog.md
[joystick.c]: https://github.com/troglobit/libuev/blob/master/joystick.c
@@ -307,9 +403,3 @@ Lua users mailing list.
[libuevent]: https://code.google.com/p/libuevent/
[Flemming Madsen]: http://www.madsensoft.dk
[Initial announcement]: http://lua-users.org/lists/lua-l/2012-03/msg00510.html
<!--
-- Local Variables:
-- mode: markdown
-- End:
-->
+5 -1
View File
@@ -4,6 +4,10 @@ DIST_SUBDIRS = src examples tests
doc_DATA = API.md README.md LICENSE
EXTRA_DIST = API.md README.md LICENSE AUTHORS ChangeLog.md
if ENABLE_EXAMPLES
SUBDIRS += examples
endif
## Generate .deb package
package:
@dpkg-buildpackage -uc -us -B
@@ -34,7 +38,7 @@ release-hook:
fi
## Target to run when building a release
release: dist release-hook md5-dist
release: distcheck release-hook md5-dist
@for file in $(DIST_ARCHIVES); do \
printf "$$file \tDistribution tarball\n"; \
printf "$$file.md5\t"; cat $$file.md5 | cut -f1 -d' '; \
+20 -10
View File
@@ -15,7 +15,7 @@ libuEv | Simple event loop for Linux
* [Origin & References](#origin--references)
> “Event driven software improves concurrency” -- [Dave Zarzycki, Apple][]
> **NOTE:** Incompatible failure mode changes in v2.0 compared to v1.x!
Introduction
------------
@@ -25,14 +25,19 @@ Introduction
*u* (micro) in the name refers to both the small feature set and the
small size overhead impact of the library.
Experienced developers may appreciate that [libuEv][] is built on top of
modern Linux APIs: epoll, timerfd and signalfd.
Failure mode changes introduced in v2.0 may affect users of v1.x, See
the [ChangeLog][] for the full details.
The [API documentation](API.md) is available as a separate document.
Example
-------
The library documentation is available as a [separate document](API.md).
Notice below how watcher `UEV_ERROR` conditions must be handled by each
callback. I/O watchers must also check for `UEV_HUP`. Both errors are
usually fatal, libuEv makes sure to stop each watcher before a callback
runs, leaving it up to the callback to take appropriate action.
```C
#include <stdio.h>
@@ -40,6 +45,10 @@ The library documentation is available as a [separate document](API.md).
static void cb(uev_t *w, void *arg, int events)
{
if (UEV_ERROR == events) {
puts("Problem with timer, attempting to restart.");
uev_timer_start(w);
}
puts("Every other second");
}
@@ -49,7 +58,8 @@ int main(void)
uev_ctx_t ctx;
uev_init(&ctx);
uev_timer_init(&ctx, &timer, cb, NULL, 2 * 1000, 0);
/* Set up a timer watcher to call cb() every other second */
uev_timer_init(&ctx, &timer, cb, NULL, 2 * 1000, 2 * 1000);
return uev_run(&ctx, 0);
}
@@ -78,11 +88,10 @@ The resulting .so file is ~14 kiB.
Origin & References
-------------------
[libuEv][] was originally based on [LibUEvent][8] by [Flemming Madsen][]
but has been completely rewritten to provide a cleaner API. It is now
more similar to the famous [libev][2] by [Mark Lehmann][]. Another
small event library used for inspiration is the very small [picoev][9]
by [Oku Kazuho][].
[libuEv][] originates from [LibUEvent][8] by [Flemming Madsen][], but
with a rewritten and much cleaner API. It is now more similar to the
famous [libev][2] by [Mark Lehmann][]. Another library inspiring this
project is [picoev][9] by [Oku Kazuho][].
[libuEv][] is developed and maintained by [Joachim Nilsson][]. It is
built for and developed on GNU/Linux systems, patches to support *BSD
@@ -94,6 +103,7 @@ and its [kqueue][] interface are most welcome.
[3]: http://unix.com/man-page/All/3x/XtDispatchEvent
[8]: http://code.google.com/p/libuevent/
[9]: https://github.com/kazuho/picoev
[ChangeLog]: https://github.com/troglobit/libuev/blob/master/ChangeLog.md
[Travis]: https://travis-ci.org/troglobit/libuev
[Travis Status]: https://travis-ci.org/troglobit/libuev.png?branch=master
[Coverity Scan]: https://scan.coverity.com/projects/3846
+8 -2
View File
@@ -1,4 +1,4 @@
AC_INIT(libuev, 1.6.0, https://github.com/troglobit/libuev/issues)
AC_INIT(libuev, 2.1.3, https://github.com/troglobit/libuev/issues)
AM_INIT_AUTOMAKE([1.11 foreign no-dist-gzip dist-xz])
AM_SILENT_RULES([yes])
@@ -8,7 +8,13 @@ AC_CONFIG_FILES([Makefile src/libuev.pc src/Makefile examples/Makefile tests/Mak
AC_CONFIG_MACRO_DIR([m4])
AC_PROG_CC
AM_PROG_AR
m4_ifdef([AM_PROG_AR], [AM_PROG_AR])
LT_INIT
# Optional features
AC_ARG_ENABLE([examples],
[AC_HELP_STRING([--enable-examples], [Build libuEv examples/ directory])],
[], [enable_examples=no])
AM_CONDITIONAL([ENABLE_EXAMPLES], [test "$enable_examples" = yes])
AC_OUTPUT
+54
View File
@@ -1,3 +1,57 @@
libuev (2.1.3) unstable; urgency=medium
* Minor bugfix release
- Updated joystick example, use first joystick, /dev/input/js0
- Use LIST_FOREACH_SAFE() instead of while() in uev_exit()
- New API test for uev_exit()
- Don't call uev_timer_set() when stopping a timer, may cause lockups
- Return OK immediately if a signal watcher is already stopped
* Packaging fixes: libuev.so symlink goes in -dev package
-- Joachim Nilsson <troglobit@gmail.com> Thu, 06 Sep 2018 22:01:24 +0200
libuev (2.1.2) unstable; urgency=medium
* Minor bugfix release
- Fix #17: build problem on systems with too old autoconf + automake
- Fix unit tests, return result of test not result of event loop
- Refactor/simplify/collapse main event loop code after fixes in v2.1.1
* Fix minor packaging issues
-- Joachim Nilsson <troglobit@gmail.com> Tue, 27 Feb 2018 00:05:32 +0100
libuev (2.1.1) unstable; urgency=medium
* Minor bugfix release
* Use native version numbering for package
-- Joachim Nilsson <troglobit@gmail.com> Sun, 28 Jan 2018 13:38:00 +0100
libuev (2.1.0-1) unstable; urgency=medium
* New upstream release. Further improvements to failure modes, some
fixes to regressions introduced in v2.0.
- Unconditionally stop I/O watchers on UEV_HUP and UEV_ERR conditions.
- Attempt to restart failing signal watchers before dropping to error.
- Properly de-register signal and cron/timer watchers on error.
- Fix possible double close() on cron/timer watchers.
- Documentation updates, improved examples, and unit tests.
-- Joachim Nilsson <troglobit@gmail.com> Tue, 14 Nov 2017 17:40:43 +0100
libuev (2.0.0-1) unstable; urgency=medium
* Major new upstream version, possibly incompatible changes to both
uev_run() and how watchers are called in various failure modes.
- uev_run() no longer exits the main event loop if an unrecoverable
error with a watcher occurs. Instead, the watcher is disabled and
the callback is run one last time with events set to UEV_ERROR.
- Watcher callbacks must handle UEV_ERROR conditions. This pertains
in particular to signal and timer watchers.
-- Joachim Nilsson <troglobit@gmail.com> Sat, 11 Nov 2017 16:31:46 +0100
libuev (1.6.0-1) unstable; urgency=medium
* Support for edge triggered and oneshot event types
+3 -5
View File
@@ -1,6 +1,4 @@
usr/include/uev/uev.h
usr/include/uev/private.h
usr/include/uev/queue.h
usr/lib/*/lib*.a
usr/lib/*/lib*.so
usr/include/uev/*.h
usr/lib/*/libuev.a
usr/lib/*/libuev.so
usr/lib/*/pkgconfig/lib*.pc
+2
View File
@@ -2,3 +2,5 @@ joystick
signal
cronrun
test
redirect
hej.txt
+3 -5
View File
@@ -1,5 +1,3 @@
noinst_PROGRAMS = joystick
AM_CPPFLAGS = -I$(top_srcdir)
AM_LDFLAGS = -L$(top_srcdir)
LIBS = $(LTLIBINTL)
LDADD = $(top_srcdir)/libuev.la
noinst_PROGRAMS = joystick redirect
AM_CPPFLAGS = -I$(top_srcdir)/src
LDADD = $(top_srcdir)/src/libuev.la
+22 -3
View File
@@ -37,10 +37,29 @@ struct js_event {
uint8_t number; /* axis/button number */
} e;
/*
* Always check for UEV_ERROR in watcher callback!
* Possibly joystick was unplugged
*/
static void joystick_cb(uev_t *w, void *arg, int events)
{
if (read(w->fd, &e, sizeof(e)) < 0)
errx(errno, "Failed reading joystick event");
ssize_t len;
if (UEV_ERROR == events) {
warnx("Spurious problem with the joystick watcher, restarting.");
uev_io_start(w);
}
len = read(w->fd, &e, sizeof(e));
if (len < 0) {
warn("Failed reading joystick event");
return;
}
if (len == 0 || UEV_HUP == events) {
warn("Joystick disconnected");
return;
}
switch (e.type) {
case 1:
@@ -59,7 +78,7 @@ int main(void)
uev_t js1_watcher;
uev_ctx_t ctx;
fd = open("/dev/input/js1", O_RDONLY, O_NONBLOCK);
fd = open("/dev/input/js0", O_RDONLY, O_NONBLOCK);
if (fd < 0)
errx(errno, "Cannot find a joystick attached.");
+69
View File
@@ -0,0 +1,69 @@
/* Example of how to handle stdin redirect
*
* The problem is non-trivial since Linux epoll, which libuEv uses, does
* not support I/O watchers for regular files or directories.
*
* This works:
* echo foo | redirect
* This doesn't:
* redirect < foo.txt
*
* However, with a little bit of hacking libuEv can be made to handle
* reading from stdin as a special case.
*/
#include <err.h>
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include "src/uev.h"
void process_stdin(uev_t *w, void *arg, int events)
{
char buf[256];
int len;
if (UEV_ERROR == events) {
warnx("Spurious problem with the stdin watcher, restarting.");
uev_io_start(w);
}
len = read(w->fd, buf, sizeof(buf));
if (len == -1) {
warn("Error reading from stdin");
return;
}
if (len == 0 || UEV_HUP == events) {
warnx("Connection closed.");
return;
}
printf("Read %d bytes\n", len);
if (write(STDOUT_FILENO, buf, len) != len)
warn("Failed writing to stdout");
}
int main(int argc, char **argv)
{
int ret;
uev_t watcher;
uev_ctx_t ctx;
uev_init(&ctx);
ret = uev_io_init(&ctx, &watcher, process_stdin, NULL, STDIN_FILENO, UEV_READ);
if (ret)
err(errno, "Failed setting up STDIN watcher");
return uev_run(&ctx, 0);
}
/**
* Local Variables:
* compile-command: "make redirect; echo hej > hej.txt; ./redirect < hej.txt"
* indent-tabs-mode: t
* c-file-style: "linux"
* End:
*/
+1 -1
View File
@@ -2,7 +2,7 @@ lib_LTLIBRARIES = libuev.la
libuev_la_SOURCES = uev.c io.c timer.c signal.c cron.c
libuev_la_CPPFLAGS = -D_GNU_SOURCE -D_TIME_BITS=64
libuev_la_CFLAGS = -W -Wall -Wextra
libuev_la_LDFLAGS = $(AM_LDFLAGS) -version-info 1:2:0
libuev_la_LDFLAGS = $(AM_LDFLAGS) -version-info 2:2:0
noinst_PROGRAMS = bench
bench_CPPFLAGS = -D_GNU_SOURCE
+3 -3
View File
@@ -72,11 +72,11 @@ int uev_cron_init(uev_ctx_t *ctx, uev_t *w, uev_cb_t *cb, void *arg, time_t when
if (fd < 0)
return -1;
if (uev_watcher_init(ctx, w, UEV_CRON_TYPE, cb, arg, fd, UEV_READ))
if (_uev_watcher_init(ctx, w, UEV_CRON_TYPE, cb, arg, fd, UEV_READ))
goto exit;
if (uev_cron_set(w, when, interval)) {
uev_watcher_stop(w);
_uev_watcher_stop(w);
exit:
close(fd);
return -1;
@@ -132,7 +132,7 @@ int uev_cron_set(uev_t *w, time_t when, time_t interval)
return 1;
}
return uev_watcher_start(w);
return _uev_watcher_start(w);
}
/**
+5 -6
View File
@@ -44,10 +44,10 @@ int uev_io_init(uev_ctx_t *ctx, uev_t *w, uev_cb_t *cb, void *arg, int fd, int e
return -1;
}
if (uev_watcher_init(ctx, w, UEV_IO_TYPE, cb, arg, fd, events))
if (_uev_watcher_init(ctx, w, UEV_IO_TYPE, cb, arg, fd, events))
return -1;
return uev_watcher_start(w);
return _uev_watcher_start(w);
}
/**
@@ -60,9 +60,8 @@ int uev_io_init(uev_ctx_t *ctx, uev_t *w, uev_cb_t *cb, void *arg, int fd, int e
*/
int uev_io_set(uev_t *w, int fd, int events)
{
if ((events & UEV_ONESHOT) && w->active)
return uev_watcher_rearm(w);
if ((events & UEV_ONESHOT) && _uev_watcher_active(w))
return _uev_watcher_rearm(w);
/* Ignore any errors, only to clean up anything lingering ... */
uev_io_stop(w);
@@ -89,7 +88,7 @@ int uev_io_start(uev_t *w)
*/
int uev_io_stop(uev_t *w)
{
return uev_watcher_stop(w);
return _uev_watcher_stop(w);
}
/**
+11 -11
View File
@@ -31,21 +31,21 @@
/* I/O, timer, or signal watcher */
typedef enum {
UEV_CRON_TYPE = 1,
UEV_IO_TYPE,
UEV_IO_TYPE = 1,
UEV_SIGNAL_TYPE,
UEV_TIMER_TYPE,
UEV_CRON_TYPE,
} uev_type_t;
/* Event mask, used internally only. */
#define UEV_EVENT_MASK (UEV_READ | UEV_WRITE | UEV_PRI | UEV_HUP | UEV_RDHUP | UEV_EDGE | UEV_ONESHOT)
#define UEV_EVENT_MASK (UEV_ERROR | UEV_READ | UEV_WRITE | UEV_PRI | UEV_HUP | UEV_RDHUP | UEV_EDGE | UEV_ONESHOT)
/* Main libuEv context type */
typedef struct {
int running;
int fd; /* For epoll() */
uint32_t errors;
LIST_HEAD(,uev) watchers;
uint32_t workaround; /* For workarounds, e.g. redirected stdin */
} uev_ctx_t;
/* Forward declare due to dependencys, don't try this at home kids. */
@@ -81,13 +81,13 @@ struct uev;
uev_type_t
/* Internal API for dealing with generic watchers */
int uev_watcher_init (uev_ctx_t *ctx, struct uev *w, uev_type_t type,
void (*cb)(struct uev *, void *, int), void *arg,
int fd, int events);
int uev_watcher_start (struct uev *w);
int uev_watcher_stop (struct uev *w);
int uev_watcher_active(struct uev *w);
int uev_watcher_rearm (struct uev *w);
int _uev_watcher_init (uev_ctx_t *ctx, struct uev *w, uev_type_t type,
void (*cb)(struct uev *, void *, int), void *arg,
int fd, int events);
int _uev_watcher_start (struct uev *w);
int _uev_watcher_stop (struct uev *w);
int _uev_watcher_active(struct uev *w);
int _uev_watcher_rearm (struct uev *w);
#endif /* LIBUEV_PRIVATE_H_ */
+7 -4
View File
@@ -56,11 +56,11 @@ int uev_signal_init(uev_ctx_t *ctx, uev_t *w, uev_cb_t *cb, void *arg, int signo
if (fd < 0)
return -1;
if (uev_watcher_init(ctx, w, UEV_SIGNAL_TYPE, cb, arg, fd, UEV_READ))
if (_uev_watcher_init(ctx, w, UEV_SIGNAL_TYPE, cb, arg, fd, UEV_READ))
goto exit;
if (uev_signal_set(w, signo)) {
uev_watcher_stop(w);
_uev_watcher_stop(w);
exit:
close(fd);
return -1;
@@ -109,7 +109,7 @@ int uev_signal_set(uev_t *w, int signo)
if (signalfd(w->fd, &mask, SFD_NONBLOCK) < 0)
return -1;
return uev_watcher_start(w);
return _uev_watcher_start(w);
}
@@ -140,7 +140,10 @@ int uev_signal_start(uev_t *w)
*/
int uev_signal_stop(uev_t *w)
{
if (uev_watcher_stop(w))
if (!_uev_watcher_active(w))
return 0;
if (_uev_watcher_stop(w))
return -1;
close(w->fd);
+13 -9
View File
@@ -76,13 +76,14 @@ int uev_timer_init(uev_ctx_t *ctx, uev_t *w, uev_cb_t *cb, void *arg, int timeou
if (fd < 0)
return -1;
if (uev_watcher_init(ctx, w, UEV_TIMER_TYPE, cb, arg, fd, UEV_READ))
if (_uev_watcher_init(ctx, w, UEV_TIMER_TYPE, cb, arg, fd, UEV_READ))
goto exit;
if (uev_timer_set(w, timeout, period)) {
uev_watcher_stop(w);
_uev_watcher_stop(w);
exit:
close(fd);
w->fd = -1;
return -1;
}
@@ -92,9 +93,13 @@ int uev_timer_init(uev_ctx_t *ctx, uev_t *w, uev_cb_t *cb, void *arg, int timeou
/**
* Reset a timer
* @param w Watcher to reset
* @param timeout Timeout in milliseconds before @param cb is called
* @param timeout Timeout in milliseconds before @param cb is called, zero disarms timer
* @param period For periodic timers this is the period time that @param timeout is reset to
*
* Note, the @param timeout value must be non-zero. Setting it to zero
* will disarm the timer. This is the underlying Linux function @func
* timerfd_settimer() which has this behavior.
*
* @return POSIX OK(0) or non-zero with @param errno set on error.
*/
int uev_timer_set(uev_t *w, int timeout, int period)
@@ -135,7 +140,7 @@ int uev_timer_set(uev_t *w, int timeout, int period)
return 1;
}
return uev_watcher_start(w);
return _uev_watcher_start(w);
}
/**
@@ -152,7 +157,7 @@ int uev_timer_start(uev_t *w)
}
if (-1 != w->fd)
uev_watcher_stop(w);
_uev_watcher_stop(w);
return uev_timer_set(w, w->u.t.timeout, w->u.t.period);
}
@@ -165,13 +170,12 @@ int uev_timer_start(uev_t *w)
*/
int uev_timer_stop(uev_t *w)
{
/* Stop kernel timer */
uev_timer_set(w, 0, 0);
if (!_uev_watcher_active(w))
return 0;
if (uev_watcher_stop(w))
if (_uev_watcher_stop(w))
return -1;
/* Close timerfd, will have to be reopened again on reset */
close(w->fd);
w->fd = -1;
+115 -94
View File
@@ -26,6 +26,8 @@
#include <fcntl.h> /* O_CLOEXEC */
#include <string.h> /* memset() */
#include <sys/epoll.h>
#include <sys/ioctl.h>
#include <sys/select.h> /* for select() workaround */
#include <sys/signalfd.h> /* struct signalfd_siginfo */
#include <unistd.h> /* close(), read() */
@@ -50,14 +52,24 @@ static int _init(uev_ctx_t *ctx, int close_old)
return 0;
}
/* Simple check if a descriptor is still valid in the kernel */
static int is_valid_fd(int fd)
/* Used by file i/o workaround when epoll => EPERM */
static int has_data(int fd)
{
return fcntl(fd, F_GETFL) != -1 || errno != EBADF;
struct timeval timeout = { 0, 0 };
fd_set fds;
int n = 0;
FD_ZERO(&fds);
FD_SET(fd, &fds);
if (select(1, &fds, NULL, NULL, &timeout) > 0)
return ioctl(0, FIONREAD, &n) == 0 && n > 0;
return 0;
}
/* Private to libuEv, do not use directly! */
int uev_watcher_init(uev_ctx_t *ctx, uev_t *w, uev_type_t type, uev_cb_t *cb, void *arg, int fd, int events)
int _uev_watcher_init(uev_ctx_t *ctx, uev_t *w, uev_type_t type, uev_cb_t *cb, void *arg, int fd, int events)
{
if (!ctx || !w) {
errno = EINVAL;
@@ -76,7 +88,7 @@ int uev_watcher_init(uev_ctx_t *ctx, uev_t *w, uev_type_t type, uev_cb_t *cb, vo
}
/* Private to libuEv, do not use directly! */
int uev_watcher_start(uev_t *w)
int _uev_watcher_start(uev_t *w)
{
struct epoll_event ev;
@@ -85,15 +97,28 @@ int uev_watcher_start(uev_t *w)
return -1;
}
if (w->active)
if (_uev_watcher_active(w))
return 0;
ev.events = w->events | EPOLLRDHUP;
ev.data.ptr = w;
if (epoll_ctl(w->ctx->fd, EPOLL_CTL_ADD, w->fd, &ev) < 0)
return -1;
if (epoll_ctl(w->ctx->fd, EPOLL_CTL_ADD, w->fd, &ev) < 0) {
if (errno != EPERM)
return -1;
w->active = 1;
/* Handle special case: `application < file.txt` */
if (w->type != UEV_IO_TYPE || w->events != UEV_READ)
return -1;
/* Only allow this special handling for stdin */
if (w->fd != STDIN_FILENO)
return -1;
w->ctx->workaround = 1;
w->active = -1;
} else {
w->active = 1;
}
/* Add to internal list for bookkeeping */
LIST_INSERT_HEAD(&w->ctx->watchers, w, link);
@@ -102,14 +127,14 @@ int uev_watcher_start(uev_t *w)
}
/* Private to libuEv, do not use directly! */
int uev_watcher_stop(uev_t *w)
int _uev_watcher_stop(uev_t *w)
{
if (!w) {
errno = EINVAL;
return -1;
}
if (!w->active)
if (!_uev_watcher_active(w))
return 0;
w->active = 0;
@@ -125,16 +150,16 @@ int uev_watcher_stop(uev_t *w)
}
/* Private to libuEv, do not use directly! */
int uev_watcher_active(uev_t *w)
int _uev_watcher_active(uev_t *w)
{
if (!w)
return 0;
return w->active;
return w->active > 0;
}
/* Private to libuEv, do not use directly! */
int uev_watcher_rearm(uev_t *w)
int _uev_watcher_rearm(uev_t *w)
{
struct epoll_event ev;
@@ -178,18 +203,18 @@ int uev_init(uev_ctx_t *ctx)
*/
int uev_exit(uev_ctx_t *ctx)
{
uev_t *w, *next;
if (!ctx) {
errno = EINVAL;
return -1;
}
while (!LIST_EMPTY(&ctx->watchers)) {
uev_t *w = LIST_FIRST(&ctx->watchers);
LIST_FOREACH_SAFE(w, &ctx->watchers, link, next) {
/* Remove from internal list */
LIST_REMOVE(w, link);
if (!w->active)
if (!_uev_watcher_active(w))
continue;
switch (w->type) {
@@ -208,6 +233,7 @@ int uev_exit(uev_ctx_t *ctx)
}
}
LIST_INIT(&ctx->watchers);
ctx->running = 0;
close(ctx->fd);
ctx->fd = -1;
@@ -231,7 +257,7 @@ int uev_exit(uev_ctx_t *ctx)
*/
int uev_run(uev_ctx_t *ctx, int flags)
{
int result = 0, timeout = -1;
int timeout = -1;
uev_t *w;
if (!ctx || ctx->fd < 0) {
@@ -253,11 +279,31 @@ int uev_run(uev_ctx_t *ctx, int flags)
uev_timer_set(w, w->u.t.timeout, w->u.t.period);
}
while (ctx->running) {
int i, nfds;
struct epoll_event events[UEV_MAX_EVENTS];
while (ctx->running && !LIST_EMPTY(&ctx->watchers)) {
int i, nfds, rerun = 0;
struct epoll_event ee[UEV_MAX_EVENTS];
while ((nfds = epoll_wait(ctx->fd, events, UEV_MAX_EVENTS, timeout)) < 0) {
/* Handle special case: `application < file.txt` */
if (ctx->workaround) {
LIST_FOREACH(w, &ctx->watchers, link) {
if (w->active != -1 || !w->cb)
continue;
if (!has_data(w->fd)) {
w->active = 0;
LIST_REMOVE(w, link);
}
rerun++;
w->cb(w, w->arg, UEV_READ);
}
}
if (rerun)
continue;
ctx->workaround = 0;
while ((nfds = epoll_wait(ctx->fd, ee, UEV_MAX_EVENTS, timeout)) < 0) {
if (!ctx->running)
break;
@@ -266,102 +312,77 @@ int uev_run(uev_ctx_t *ctx, int flags)
/* Unrecoverable error, cleanup and exit with error. */
uev_exit(ctx);
return -1;
return -2;
}
for (i = 0; ctx->running && i < nfds; i++) {
w = (uev_t *)events[i].data.ptr;
uint64_t exp;
uint32_t events;
struct signalfd_siginfo fdsi;
ssize_t sz = sizeof(fdsi);
if (events[i].events & (EPOLLHUP | EPOLLERR)) {
ctx->errors++;
w = (uev_t *)ee[i].data.ptr;
events = ee[i].events;
if (ctx->errors >= 42) {
uev_t *tmp, *retry = w;;
switch (w->type) {
case UEV_IO_TYPE:
if (events & (EPOLLHUP | EPOLLERR))
uev_io_stop(w);
break;
/* If not valid anymore, try to remove, ignore any errors. */
if (!is_valid_fd(w->fd))
uev_watcher_stop(w);
/* Must recreate epoll fd now ... */
if (_init(ctx, 1)) {
uev_exit(ctx);
return -2;
case UEV_SIGNAL_TYPE:
if (read(w->fd, &fdsi, sz) != sz) {
if (uev_signal_start(w)) {
uev_signal_stop(w);
events = UEV_ERROR;
}
/* Restart watchers in new efd */
LIST_FOREACH_SAFE(w, &ctx->watchers, link, tmp) {
if (w->active) {
w->active = 0;
LIST_REMOVE(w, link);
uev_watcher_start(w);
}
}
uev_watcher_start(retry);
/* New efd, restart everything! */
ctx->errors = 0;
continue;
}
}
if (UEV_CRON_TYPE == w->type) {
uint64_t exp;
break;
case UEV_TIMER_TYPE:
if (read(w->fd, &exp, sizeof(exp)) != sizeof(exp)) {
if (errno != ECANCELED) {
uev_exit(ctx);
return -3;
}
uev_timer_stop(w);
events = UEV_ERROR;
}
events[i].events = UEV_HUP;
if (!w->u.t.period)
w->u.t.timeout = 0;
if (!w->u.t.timeout)
uev_timer_stop(w);
break;
case UEV_CRON_TYPE:
if (read(w->fd, &exp, sizeof(exp)) != sizeof(exp)) {
events = UEV_HUP;
if (errno != ECANCELED) {
uev_cron_stop(w);
events = UEV_ERROR;
}
}
if (!w->u.c.interval)
w->u.c.when = 0;
else
w->u.c.when += w->u.c.interval;
}
if (UEV_TIMER_TYPE == w->type) {
uint64_t exp;
if (read(w->fd, &exp, sizeof(exp)) != sizeof(exp)) {
uev_exit(ctx);
return -3;
}
if (!w->u.t.period)
w->u.t.timeout = 0;
}
if (UEV_SIGNAL_TYPE == w->type) {
struct signalfd_siginfo fdsi;
ssize_t sz = sizeof(fdsi);
if (read(w->fd, &fdsi, sz) != sz) {
uev_exit(ctx);
return -4;
}
}
if (w->cb)
w->cb(w, w->arg, events[i].events & UEV_EVENT_MASK);
if (UEV_CRON_TYPE == w->type) {
if (!w->u.c.when)
uev_timer_stop(w);
break;
}
if (UEV_TIMER_TYPE == w->type) {
if (!w->u.t.timeout)
uev_timer_stop(w);
}
/*
* NOTE: Must be last action for watcher, the
* callback may delete itself.
*/
if (w->cb)
w->cb(w, w->arg, events & UEV_EVENT_MASK);
}
if ((flags & UEV_ONCE) || LIST_EMPTY(&ctx->watchers))
if (flags & UEV_ONCE)
break;
}
return result;
return 0;
}
/**
+10 -4
View File
@@ -32,6 +32,7 @@
/* I/O events, signal and timer revents are always UEV_READ */
#define UEV_NONE 0
#define UEV_ERROR EPOLLERR
#define UEV_READ EPOLLIN
#define UEV_WRITE EPOLLOUT
#define UEV_PRI EPOLLPRI
@@ -45,10 +46,10 @@
#define UEV_NONBLOCK 2
/* Macros */
#define uev_io_active(w) uev_watcher_active(w)
#define uev_timer_active(w) uev_watcher_active(w)
#define uev_cron_active(w) uev_watcher_active(w)
#define uev_signal_active(w) uev_watcher_active(w)
#define uev_io_active(w) _uev_watcher_active(w)
#define uev_timer_active(w) _uev_watcher_active(w)
#define uev_cron_active(w) _uev_watcher_active(w)
#define uev_signal_active(w) _uev_watcher_active(w)
/* Event watcher */
typedef struct uev {
@@ -65,6 +66,11 @@ typedef struct uev {
* Generic callback for watchers, @events holds %UEV_READ and/or %UEV_WRITE
* with optional %UEV_PRI (priority data available to read) and any of the
* %UEV_HUP and/or %UEV_RDHUP, which may be used to signal hang-up events.
*
* Note: UEV_ERROR conditions must be handled by all callbacks!
* I/O watchers may also need to check UEV_HUP. Appropriate action,
* e.g. restart the watcher, is up to the application and is thus
* delegated to the callback.
*/
typedef void (uev_cb_t)(uev_t *w, void *arg, int events);
+1
View File
@@ -1,6 +1,7 @@
*.trs
*.log
active
api
complete
cronrun
signal
+1
View File
@@ -3,6 +3,7 @@ CLEANFILES = *~ *.trs *.log
TESTS =
TESTS += active
TESTS += api
TESTS += complete
TESTS += cronrun
TESTS += signal
+14 -1
View File
@@ -12,8 +12,11 @@ uev_t timer3;
uev_t cron1;
uev_t cron2;
static void cb(uev_t *w, void *UNUSED(arg), int UNUSED(events))
static void cb(uev_t *w, void *UNUSED(arg), int events)
{
if (UEV_ERROR == events)
fprintf(stderr, "timer watcher failed, ignoring ...\n");
fail_unless(w == &timer1);
fail_unless(uev_timer_active(&timer2));
@@ -27,6 +30,9 @@ static void cb(uev_t *w, void *UNUSED(arg), int UNUSED(events))
fail_unless(!uev_timer_active(&timer2));
fail_unless(!uev_cron_active(&cron2));
/* Restart timer and see if we fail in uev_exit() */
uev_timer_start(&timer2);
uev_exit(w->ctx);
}
@@ -49,3 +55,10 @@ int main(void)
return uev_run(&ctx, 0);
}
/**
* Local Variables:
* indent-tabs-mode: t
* c-file-style: "linux"
* End:
*/
+34
View File
@@ -0,0 +1,34 @@
#include "check.h"
uev_t timer, file;
int counter = 10;
static void cb(uev_t *w, void *UNUSED(arg), int events)
{
if (UEV_ERROR == events)
fprintf(stderr, "timer watcher failed, ignoring ...\n");
if (counter--)
return;
uev_exit(w->ctx);
}
int main(void)
{
uev_ctx_t ctx;
FILE *fp;
uev_init(&ctx);
uev_timer_init(&ctx, &timer, cb, NULL, 100, 100);
fp = fopen("/dev/one", "r");
if (fp)
uev_io_init(&ctx, &file, cb, NULL, fileno(fp), UEV_READ);
uev_run(&ctx, 0);
uev_exit(&ctx); /* Should not hang event loop, troglobit/uftpd#16 */
return 0;
}
+45 -12
View File
@@ -33,15 +33,21 @@ static int in, out;
static int period = 0;
static uev_t *watchdog;
static void lifetime_cb(uev_t *w, void *arg, int UNUSED(events))
static void lifetime_cb(uev_t *w, void *arg, int events)
{
if (UEV_ERROR == events)
fprintf(stderr, "timer watcher failed, ignoring ...\n");
fprintf(stderr, "\nLifetime exceeded, program completed successfully! (arg:%p)\n", arg);
uev_exit(w->ctx);
}
/* The pipe watchdog, if it triggers we haven't received data in time. */
static void timeout_cb(uev_t *w, void *arg, int UNUSED(events))
static void timeout_cb(uev_t *w, void *arg, int events)
{
if (UEV_ERROR == events)
fprintf(stderr, "timer watcher failed, ignoring ...\n");
watchdog = NULL;
fprintf(stderr, "\nTimeout exceeded %p\n", arg);
@@ -54,23 +60,46 @@ static void periodic_task(uev_t UNUSED(*w), void UNUSED(*arg), int UNUSED(events
fprintf(stderr, "|");
}
static void signal_cb(uev_t *w, void *UNUSED(arg), int UNUSED(events))
static void signal_cb(uev_t *w, void *UNUSED(arg), int events)
{
if (UEV_ERROR == events) {
fprintf(stderr, "Signal watcher failed, unrecoverable error.\n");
return;
}
fprintf(stderr, w->signo == SIGINT ? "^Cv" : "^\v");
}
static void pipe_read_cb(uev_t UNUSED(*w), void UNUSED(*arg), int UNUSED(events))
static void pipe_read_cb(uev_t *w, void UNUSED(*arg), int events)
{
int cnt;
int len;
char msg[50];
/* Kick watchdog */
if (UEV_ERROR == events) {
error:
fprintf(stderr, "pipe watcher failed, restarting ...\n");
uev_io_start(w);
return;
}
/* Kick watchdog */
if (watchdog)
uev_timer_set(watchdog, 1000, 0);
cnt = read(in, msg, sizeof(msg));
// fprintf(stderr, "READ %.*s %d\n", cnt, msg, cnt);
fprintf(stderr, "%.*s.%d ", cnt, msg, cnt);
/* Here we can read() from in or w->fd, either works. */
len = read(w->fd, msg, sizeof(msg));
if (len < 0) {
perror(__func__);
goto error;
}
if (len == 0 || UEV_HUP == events) {
fprintf(stderr, "Other end of pipe closed, no more data\n");
return;
}
// fprintf(stderr, "READ %.*s %d\n", len, msg, len);
fprintf(stderr, "%.*s.%d ", len, msg, len);
}
static void pipe_write_cb(uev_t *w, void *arg, int UNUSED(events))
@@ -78,10 +107,14 @@ static void pipe_write_cb(uev_t *w, void *arg, int UNUSED(events))
my_t *my = arg;
char *msg = "TESTING";
if (UEV_ERROR == events)
fprintf(stderr, "timer watcher failed, ignoring ...\n");
/* Here we *must* use out, not w->fd, since we're a timer callback */
if (write(out, msg, my->counter) < 0) {
perror("\nFailed writing to pipe");
return;
}
perror("\nFailed writing to pipe");
return;
}
// fprintf(stderr, "WRITE %.*s %d\n", my->counter, msg, my->counter);
fprintf(stderr, "%d ", my->counter);
+16 -5
View File
@@ -28,13 +28,17 @@
#define TIMEOUT 2
#define INTERVAL 2
int result = -1;
struct timeval tv;
static void cron_job(uev_t *w, void *UNUSED(arg), int UNUSED(events))
static void cron_job(uev_t *w, void *UNUSED(arg), int events)
{
static int laps = 3;
struct timeval now;
if (UEV_ERROR == events)
fprintf(stderr, "cron watcher failed, ignoring ...\n");
/* Update timer every lap */
tv.tv_sec += TIMEOUT;
@@ -42,12 +46,15 @@ static void cron_job(uev_t *w, void *UNUSED(arg), int UNUSED(events))
printf("Cron job HELO %s", ctime(&now.tv_sec));
fail_unless(now.tv_sec == tv.tv_sec);
if (!laps--)
if (!laps--) {
result = 0;
uev_exit(w->ctx);
}
}
int main(void)
{
int rc;
uev_t cron_watcher;
uev_ctx_t ctx;
time_t when, interval;
@@ -55,14 +62,18 @@ int main(void)
uev_init(&ctx);
gettimeofday(&tv, NULL);
when = tv.tv_sec + TIMEOUT;
printf("Start of test %s", ctime(&tv.tv_sec));
printf("Expected cron %s", ctime(&when));
when = tv.tv_sec + TIMEOUT;
interval = INTERVAL;
uev_cron_init(&ctx, &cron_watcher, cron_job, NULL, when, interval);
return uev_run(&ctx, 0);
rc = uev_run(&ctx, 0);
fail_unless(result == 0);
return rc;
}
/**
+13 -13
View File
@@ -63,7 +63,7 @@ static int callback(arg_t *arg, int event, void *foo)
printf("child: segfaulting failed!\n");
#endif
return 42;
return 42;
}
static void sigsegv_cb(uev_t *UNUSED(w), void *UNUSED(arg), int UNUSED(events))
@@ -74,27 +74,27 @@ static void sigsegv_cb(uev_t *UNUSED(w), void *UNUSED(arg), int UNUSED(events))
static void sigchld_cb(uev_t *UNUSED(w), void *UNUSED(arg), int UNUSED(events))
{
pid_t pid = waitpid(-1, NULL, WNOHANG);
pid_t pid = waitpid(-1, NULL, WNOHANG);
if (-1 != pid)
warnx("PID %d exited, bye.", pid);
if (-1 != pid)
warnx("PID %d exited, bye.", pid);
}
static void work_cb(uev_t *UNUSED(w), void *arg, int UNUSED(events))
{
int status = 0;
pid_t pid;
pid_t pid;
pid = fork();
if (-1 == pid)
err(1, "fork");
pid = fork();
if (-1 == pid)
err(1, "fork");
if (!pid) {
status = callback(arg, 6137, NULL);
exit(status);
}
exit(status);
}
if (waitpid(pid, &status, 0) == -1)
err(1, "waitpid");
if (waitpid(pid, &status, 0) == -1)
err(1, "waitpid");
if (WIFEXITED(status))
printf("Child exited normally => %d\n", WEXITSTATUS(status));
@@ -108,7 +108,7 @@ static void work_cb(uev_t *UNUSED(w), void *arg, int UNUSED(events))
static void exit_cb(uev_t *w, void *UNUSED(arg), int UNUSED(events))
{
printf("Process deadline reached, exiting!\n");
printf("Process deadline reached, exiting!\n");
uev_exit(w->ctx);
}
+19 -2
View File
@@ -3,20 +3,27 @@
#include <sys/time.h>
#define TIMEOUT 2 /* 2 sec */
int result = -1;
struct timeval start;
static void cb(uev_t *w, void *UNUSED(arg), int UNUSED(events))
static void cb(uev_t *w, void *UNUSED(arg), int events)
{
struct timeval now;
if (UEV_ERROR == events)
fprintf(stderr, "timer watcher failed, ignoring ...\n");
gettimeofday(&now, NULL);
fail_unless(now.tv_sec == start.tv_sec + TIMEOUT);
result = 0;
uev_exit(w->ctx);
}
int main(void)
{
int rc;
uev_t w;
uev_ctx_t ctx;
@@ -24,5 +31,15 @@ int main(void)
uev_timer_init(&ctx, &w, cb, NULL, TIMEOUT * 1000, 0);
gettimeofday(&start, NULL);
return uev_run(&ctx, 0);
rc = uev_run(&ctx, 0);
fail_unless(result == 0);
return rc;
}
/**
* Local Variables:
* indent-tabs-mode: t
* c-file-style: "linux"
* End:
*/