302 Commits
Author SHA1 Message Date
Joachim Wiberg c964bbe8fb .github: bump actions
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-04-28 08:35:10 +02:00
Joachim Wiberg faf7667012 Create SECURITY.md policy 2025-04-28 07:56:01 +02:00
Joachim Wiberg 332f28e5e1 .github: drop 'needs:' and set release variables
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2024-01-04 17:23:17 +01:00
Joachim Wiberg d3c021af42 Update changelog and bump version for v2.4.1 release
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2024-01-04 17:16:57 +01:00
Joachim Wiberg 0f59096154 Update copyright years
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2024-01-04 17:16:49 +01:00
Joachim Wiberg d67290c073 .github: update and drop dep install, not needed
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2024-01-04 17:12:54 +01:00
Joachim Wiberg c23100c3f0 .github: bump action versions
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2024-01-04 17:05:32 +01:00
Joachim Wiberg ff2396b973 Mention new Linux APIs we use
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2022-12-28 23:40:30 +01:00
Joachim Wiberg 70ef23b9e3 Open v2.4.1 release cycle
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2022-12-17 15:14:35 +01:00
Joachim Wiberg 568fe6a9e1 Update changelog for upcoming v2.4.1 release
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2022-12-17 15:14:01 +01:00
Joachim Wiberg ae048605db .github: bump actions to latest supported Node.JS
Prepare for next release by importing necessary changes to release.yml
from SMCroute.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2022-12-17 15:10:55 +01:00
Joachim Wiberg 2d9f1c9ce6 Fix #27: possible buffer overrun in uev_run()
If uev_init1() is called with maxevents > 10 the call to epoll_wait()
might cause buffer overflow.  Reported by Steve Palmer.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2022-12-17 15:02:21 +01:00
Joachim Wiberg f9c72a01c8 Minor, coding style
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2022-12-17 15:02:12 +01:00
Joachim Wiberg 270e270591 test: fix signed vs unsigned comparison
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2022-12-17 15:01:25 +01:00
Joachim Wiberg 3c3b37c9aa debian: update library ABI version in .symbols file
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-11-28 14:50:19 +01:00
Joachim Wiberg 0c92a564d8 debian: drop libtool dep and add doxygen
Apparently libtool is an implicit dependency and does not have to be
listed explicitly.

Add doxygen since we now have full doxygen docs to build.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-11-28 14:47:37 +01:00
Joachim Wiberg 53eadaa1c9 debian: fix copy-paste from libite in .symbols file
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-11-28 14:47:37 +01:00
Joachim Wiberg 9591ac7efb debian: Step library name to match SONAME
This patch fixes the lintian warning package-name-doesnt-match-sonames,
which is a reminder to step the library version to match the soname.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-10-03 09:03:44 +02:00
Joachim Wiberg 2ceec8e61c Check for tag with 'v' prefix in release-hook
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-10-03 08:32:45 +02:00
Joachim Wiberg fd72b75b1b Update changelogs and bump version for v2.4.0 release
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-10-03 08:29:27 +02:00
Joachim Wiberg 5c3801bb4a Bump ABI version 2.3.0 -> 3.0.0
The change in the uev_t means the stack space required, and used by
libuEv, is incompatible with previous releases.  So applications
need to be rebuild against the new header file.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-10-03 08:26:33 +02:00
Joachim Wiberg 739b9f451f debian: API.md has moved
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-10-03 08:18:35 +02:00
Joachim Wiberg 02832543e3 test: use AM_LDFLAGS for linker args to test programs
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-10-03 08:13:21 +02:00
Joachim Wiberg 0fe9868fc7 .github: drop dh-systemd from debian job, not needed
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-10-03 08:04:50 +02:00
Joachim Wiberg 292a222127 .github: drop release job dependency
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-10-03 08:01:36 +02:00
Joachim Wiberg 611f4ffd00 Update changelogs for v2.4.0 release
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-10-03 08:00:26 +02:00
Joachim Wiberg 7bde82fc93 Bump ABI version 2.2.0 --> 2.3.0
New siginfo member in uev_t

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-10-03 07:56:12 +02:00
Joachim Wiberg c8d1de10a3 test: prefix CFLAGS/CPPFLAGS with AM_ to avoid clash with Fedora
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-10-03 07:40:06 +02:00
Joachim Wiberg 2872628ef3 .github: verify package building for all builds
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-10-03 07:23:07 +02:00
Joachim Wiberg 9f5e359bc7 .github: add Release General
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-10-03 07:22:53 +02:00
Joachim Wiberg a4abbe8aea Drop package from release target, built separately
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-10-03 07:21:52 +02:00
Joachim Wiberg ff1a3eccd9 Check for full version in git tag before starting release build
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-10-03 07:19:34 +02:00
Joachim Wiberg 207e211214 Bump version for v2.4.0-rc1
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-10-02 17:30:29 +02:00
Joachim Wiberg c15e6f08e3 .github: enable hints for contributors
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-10-02 17:30:09 +02:00
Joachim Wiberg be4364236b .github: enable funding submissions for this project
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-10-02 17:27:59 +02:00
Joachim Wiberg 8aa549487f Update ChangeLog for upcoming v2.4.0 release
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-10-02 17:25:29 +02:00
Joachim Wiberg 0c8ff24353 Update .pc file with build reqs, issue #25
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-10-02 17:21:49 +02:00
Joachim Wiberg 0e0291f85e Fix #25: apps must be built with 64-bit time, just like the lib
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-10-02 17:21:17 +02:00
Joachim Wiberg 0f2e1521a8 Add MIT license badge
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-08-01 23:22:18 +02:00
Joachim Wiberg 6d56c8da98 Drop all notion of Travis-CI
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-08-01 23:20:12 +02:00
Joachim Wiberg 59dbc3260c .github: add coverity scan action
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-08-01 23:09:26 +02:00
Joachim Wiberg 44a8c08586 .github: initial build action to replace travis
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-08-01 22:59:51 +02:00
Joachim Wiberg caa62910db Relocate tests/ -> test/
For my own sanity, test/ is used in every other project of mine.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-08-01 22:40:35 +02:00
Joachim Wiberg d7a8c7895b Fix #25: glibc >= 2.33 requires _FILE_OFFSET_BITS=64 with _TIME_BITS=64
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-08-01 22:37:01 +02:00
Joachim Wiberg 3774473d96 codedocs.xyz: add paths to input, exclude and main page
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-06-14 17:37:10 +02:00
Joachim Wiberg 0038a3da18 Extra files from doxygen to clean up
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-06-14 00:25:22 +02:00
Joachim Wiberg a8fc8cae75 Generate Doxyfile from Doxyfile.in to get package version and paths
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-06-14 00:25:22 +02:00
Joachim Wiberg 5ff3f27806 Travis-CI: install tree + doxygen to build docs as well
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-06-13 23:33:16 +02:00
Joachim Wiberg 19d6c853e5 Initial codedocs.xyz integration
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-06-13 23:27:43 +02:00
Joachim Wiberg e626d080d7 Update doc comments to proper doxygen syntax
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-06-13 23:27:08 +02:00
Joachim Wiberg da080c886d Add doxygen to standard build flow, if found
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-06-13 23:26:37 +02:00
Joachim Wiberg 7b1e0eb551 Relocate most documentation to doc/
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-06-13 23:22:44 +02:00
Joachim Wiberg f207812854 doc: initial effort to enable doxygen
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-06-13 22:09:44 +02:00
Joachim Wiberg 241313a2bd tests: refactor signal test
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-06-08 21:29:05 +02:00
Joachim Wiberg 1db9b6eb8e examples: update .gitignore
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-06-08 20:28:59 +02:00
Joachim Wiberg 362670e149 Fix error handling in example callbacks
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-05-26 23:07:46 +02:00
Joachim Wiberg 18000a8ca0 Update changelogs, remember to bump ABI
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-05-26 23:03:42 +02:00
Joachim Wiberg edc4db38ce Bump version for v2.4.0 series, -beta1
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-05-26 22:58:32 +02:00
Joachim Wiberg 3d8ec02267 Update signal example with siginfo
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-05-26 22:56:25 +02:00
Joachim Wiberg e20d37228d New siginfo member in uev_t for signal watchers
This patch adds support for exporting the signalfd_siginfo struct read
from the signal fd descriptor on signals.  This allows watcher callbacks
to, e.g., figure out who sent a signal.  See signalfd(2) for details on
struct signalfd_siginfo.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-05-18 09:57:57 +02:00
Joachim Wiberg bfd8454a92 Merge pull request #24 from oturpe/fedora-fixes
Fix to build cleanly on Fedora build system
2021-04-22 15:51:06 +02:00
Otto Urpelainen 08aa7dfd76 Replace obsolete autotools macro with supported alternative
AM_CONFIG_HEADER is obsolete and should be replaced with
AC_CONFIG_HEADERS.
2021-04-21 20:46:01 +03:00
Otto Urpelainen 3e213b3792 Fix test invocation in README.md script
'make check' works, 'make test' does not.
2021-04-21 20:34:55 +03:00
Otto Urpelainen 9f3d892dcd Remove CFLAGS from tests/Makefile.am
Test are intended to be run from the root makefile, which delegates to
tests subfolder. If tests define their own CFLAGS, any configuration
from the root is overridden. This may result in a situation where the
tests fail to execute, because the library was compiled with
incompatible flags.

In particular, the starard LDFLAGS used by Fedora are incompatible with
the tests subfolder CFLAGS. Since there does not appear to be any
particular reason for forcing the tests subfolder CFLAGS, they are
removed here.
2021-04-21 20:24:46 +03:00
Joachim Wiberg ad2e71b2c5 TODO: Update with ref. to issue #20
Closes #20

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-04-07 08:50:43 +02:00
Joachim Wiberg 042f1b59bf examples: update comments
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-02-17 08:10:52 +01:00
Joachim Wiberg 8f96965d35 examples: add fork + signals + timer example
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-02-17 08:09:00 +01:00
Joachim Wiberg 53cad7bee2 examples: add timer + signal example
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-02-16 20:02:24 +01:00
Joachim Wiberg 3b3d6a3802 Update changelogs and bump version for v2.3.2 release
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-02-12 13:03:18 +01:00
Joachim Wiberg f819d658fb debian: update and relocate .symbols file
- Use v2.3.0 as minver, some were added earlier but this file wasn't

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-02-12 10:55:08 +01:00
Joachim Wiberg 5851282d1a debian: add .symbols file
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-02-12 10:44:58 +01:00
Joachim Wiberg deef49f85f debian: change -dev package priorty to optional, as per policy 4.0.1
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-02-12 09:54:29 +01:00
Joachim Wiberg b4b021b21f Update changelogs for v2.3.2 release
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-02-12 09:37:00 +01:00
Joachim Wiberg d7fd789378 Makefile: refactor and sync with libite
- Create .sha256 checksums for tarballs, in addition to the .md5
- Use debuild to build .deb package, runs lintian as well
- List all resulting build artifacts
- Call release-hook first, to check if tagged

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-02-12 09:35:05 +01:00
Joachim Wiberg b26eea6442 configure: enable tar.gz dist archives, by popular demand
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-02-12 09:35:05 +01:00
Joachim Wiberg 6c467cd594 debian: sync build-depends from libite
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-02-12 09:16:24 +01:00
Joachim Wiberg 86e01be26e Update copyright years and maintainer surname
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-02-12 09:15:40 +01:00
Joachim Nilsson 5fd29f7241 Clarify documentation of uev_timer_start()
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2020-04-20 15:27:12 +02:00
Joachim Nilsson 8d07cc616e Update changelogs and bump version for v2.3.1 release
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2020-02-22 15:51:16 +01:00
Joachim Nilsson 9db9daec07 Use separate aux/ dir for auxilliary files and check for install
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2020-02-22 15:48:11 +01:00
Joachim Nilsson af1a484c46 debian: Update Build-Depends, debhelper >= 10 is sufficient
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2020-02-22 15:45:08 +01:00
Joachim Nilsson 1e6395a85a debian: Step library name to match SONAME, fixes lintian warning
This patch fixes the lintian warning package-name-doesnt-match-sonames,
which is a reminder to step the library version to match the soname.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2020-02-22 15:44:36 +01:00
Joachim Nilsson 5c8a258c3f Update ChangeLog and bump version for v2.3.0 release
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2019-04-06 13:33:06 +02:00
Joachim Nilsson e79d25bb42 Bump ABI version 2.1.0 --> 2.2.0
New eventfd() API added.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2019-04-06 13:30:07 +02:00
Joachim Nilsson 6dccc05e0d debian: Update copyright to meet recommendations for machine parsing
Also, clarify copyright for main sources and debian/* files.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2019-04-06 13:25:03 +02:00
Joachim Nilsson de95022f44 debian: Update package description and include usr/share files
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2019-04-06 13:24:36 +02:00
Joachim Nilsson 041240a93d debian: Update to latest std version
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2019-04-06 13:24:13 +02:00
Joachim Nilsson 837d8c1e16 Maintenance and release checklist
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2019-04-06 12:51:44 +02:00
Joachim Nilsson a334d230a1 Update copyright years
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2019-04-06 12:45:50 +02:00
Joachim Nilsson 2a709f739d Reverse christmas tree and simplify a bit
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2019-04-06 12:45:29 +02:00
Joachim Nilsson d4096c8c0c Simplify ingress, example and origin
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2019-04-06 12:23:48 +02:00
Joachim Nilsson 38858488b9 Update ChangeLog with new eventfd support
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2019-04-05 06:48:43 +02:00
Joachim Nilsson 90048e5996 Add support for generic events using Linux eventfd
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2018-10-08 07:15:40 +02:00
Joachim Nilsson fd89af6ca1 Minor, fix old copy-paste error in comment
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2018-10-08 07:14:54 +02:00
Joachim Nilsson 399d75a05c Bump version for new release cycle
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2018-10-08 07:14:32 +02:00
Joachim Nilsson 6439a34670 Minor, reorder watchers a bit => same order in all functions
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2018-10-08 07:13:05 +02:00
Joachim Nilsson fac37512d5 Update ChangeLog and bump version for v2.2.0 release
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2018-10-04 21:06:51 +02:00
Joachim Nilsson 17a765b957 Bump ABI version 2.0.2 --> 2.1.0
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2018-10-04 21:06:32 +02:00
Joachim Nilsson 6fa88eacb4 Add new API; uev_init1(ctx, maxevents) to cap event cache size
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2018-10-02 17:49:32 +02:00
Joachim Nilsson 32d3842f8a Fix issue with library not being rebuilt when header files change
Add header files to list of library dependencies.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2018-10-02 17:48:30 +02:00
Joachim Nilsson 574c463c9a Enforce -std=gnu11, which enables typeof() in GCC 4.8
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2018-09-27 19:10:09 +02:00
Joachim Nilsson 2470d5bf88 Bump version for new release cycle, v2.2-beta1
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2018-09-25 23:38:53 +02:00
Joachim Nilsson e6b99da0f5 Refactor, replace BSD queue.h LIST_ macros with homegrown version
This patch replaces the BSD doubly linked list implementation with a
simplified homegrown version.  This not only reduces the dependency on
an external "library", but also greatly simplifies licensing and gives
us a clean name space that does not intrude on users who want to use
their own version of queue.h in their application that also includes
the libuEv header file.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2018-09-25 23:31:23 +02:00
Joachim Nilsson ebe3888d6f Minor, whitespace fixes
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2018-09-25 23:23:43 +02:00
Joachim Nilsson 99ef6eb884 Remove __attribute__ ((unused)), use -Wno-unused-parameter instead
The __attribute__ ((unused)) is useful sometimes to declare variables as
intended to be unused, e.g. in callback functions.  However, they tend
to clutter up the code making hard to read.  We therefore remove all
uses of it and instead set -Wno-unused-parameter.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2018-09-25 23:19:02 +02:00
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
Joachim Nilsson 5e24736652 Bump version for v1.6.0 release
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-09-22 08:01:04 +02:00
Joachim Nilsson c8c84d12cd Add standard README.debian
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-09-21 21:29:56 +02:00
Joachim Nilsson 0bc466d112 Minor, reorder build vars a bit
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-09-21 21:29:21 +02:00
Joachim Nilsson 199e38c8dc debian/rules: Don't compress README.md and API.md in -dev package
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-09-21 21:28:54 +02:00
Joachim Nilsson f70693fd87 debian/docs: Also install new API.md docs
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-09-21 21:28:32 +02:00
Joachim Nilsson 777810cc83 Spellcheck ChangeLog(s)
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-09-21 07:55:06 +02:00
Joachim Nilsson e0b0924135 Add src/* to distribution archive files
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-09-21 07:53:30 +02:00
Joachim Nilsson 31fabccf7f README: Fix obvious error in example
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-09-20 13:38:39 +02:00
Joachim Nilsson f2d5192aa2 Reword note on time_t and GLIBC and add URL after user feedback
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-09-20 09:24:45 +02:00
Joachim Nilsson 891e641abe Sectionalize API docs better and update README ToC
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-09-20 09:04:54 +02:00
Joachim Nilsson b67c62045f Improve documentation for event flags on init and callback
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-09-20 08:59:39 +02:00
Joachim Nilsson 649f40e5d3 Reduce indentation in all code + shell examples
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-09-20 08:41:47 +02:00
Joachim Nilsson d92b4ce2ae Reduce indentation for very wide API desc.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-09-20 08:39:25 +02:00
Joachim Nilsson 653f605c25 Update doc string for possible I/O watcher events
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-09-20 08:38:21 +02:00
Joachim Nilsson fd6a2b02d8 Simplify comment
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-09-20 08:38:05 +02:00
Joachim Nilsson 310e8a7607 Try quoute at top of text
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-09-20 08:18:48 +02:00
Joachim Nilsson f7f14a4a64 Reduce indentation and remove '$' in shell build example
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-09-20 08:18:05 +02:00
Joachim Nilsson a6e185d4e9 Minor refactor of layout
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-09-20 08:15:31 +02:00
Joachim Nilsson 2f96d2fcd4 Move quote back to README
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-09-20 08:15:11 +02:00
Joachim Nilsson 25701b4fc4 API.md: We handle Y2038 on GLIBC systems, but use relative timers
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-09-20 08:14:12 +02:00
Joachim Nilsson cc7fdc747a Simplify and correct project name
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-09-20 08:05:29 +02:00
Joachim Nilsson 16892b0673 Move caveat about using signalfd from README to API doc
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-09-20 08:05:01 +02:00
Joachim Nilsson b6b4afc11b Update copyright years
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-09-19 09:09:29 +02:00
Joachim Nilsson 8f6a0a6847 README: Move around text a bit to get a better flow
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-09-19 09:06:44 +02:00
Joachim Nilsson 36599097d5 README: Add a simple example
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-09-19 09:05:08 +02:00
Joachim Nilsson ca7a99aba3 README: Simplify origin a bit
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-09-19 09:04:46 +02:00
Joachim Nilsson 4e0bb82899 Remove MOTIVATION.md, wrote another blog post about it instead
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-09-19 08:59:15 +02:00
Joachim Nilsson 77738130e3 Relocate API.md, again, and add to distribution archive and doc/
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-09-19 08:59:15 +02:00
Joachim Nilsson 7a316468b5 Rename src/README.md --> src/API.md, add README symlink for GitHub
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-09-19 08:32:25 +02:00
Joachim Nilsson 10d69fdee7 Fix URLs in API document
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-09-19 08:30:47 +02:00
Joachim Nilsson 03ea12a41c Move background to a separate motivation document
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-09-19 08:29:43 +02:00
Joachim Nilsson 543b49fb08 Fix src/README.md URL
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-09-19 08:19:59 +02:00
Joachim Nilsson 17fd42fa87 Update and add ToC
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-09-19 08:18:29 +02:00
Joachim Nilsson 7d6a37e4c5 Move API documentation to src/README.md
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-09-19 08:16:20 +02:00
Joachim Nilsson ed5c9bb06c Relocate source fiiles to src/ subdirectory
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-09-19 08:12:21 +02:00
Joachim Nilsson aae505fb33 Bump version, v1.6.0-rc1
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-09-18 07:53:20 +02:00
Joachim Nilsson b290451eb0 Update ChangeLog(s) for upcoming v1.6.0 release
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-09-18 07:52:49 +02:00
Joachim Nilsson 1282e2e716 Fix #9: Y2038 fix for 32 bit GLIBC systems
This patch enables 64 bit time_t support on GLIBC based 32 bit systems.
See https://sourceware.org/glibc/wiki/Y2038ProofnessDesign for more on
this problem.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-09-18 07:51:59 +02:00
Joachim Nilsson 1d415cfd50 Refactor, further additions of syntax highlighting
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-05-27 17:52:41 +02:00
Joachim Nilsson 6ca04123e2 Try shell script highlighting
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-05-27 17:43:03 +02:00
Joachim Nilsson 0f5842e6fe Prettify verbatim text
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-05-27 17:42:01 +02:00
Joachim Nilsson 1450e7e48a Whitesapce fixes
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-05-27 17:39:02 +02:00
Joachim Nilsson ee74602502 Clarify 32 bit time_t limitations in libuEv
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-05-07 20:36:38 +02:00
Joachim Nilsson 37453b821a Minor, remove unnecessary braces for one-liner conditional
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-05-06 18:07:01 +02:00
Joachim Nilsson 00afc27e46 Merge pull request #10 from Martijn81/master
Add edgetrigger and oneshot event types
2017-05-06 18:03:46 +02:00
martijn81 48fc8a38bc indentation problem fixed. 2017-05-06 18:00:07 +02:00
martijn81 6354b33316 UEV_EVENT_MASK change 2017-05-06 17:48:05 +02:00
martijn81 e18d980606 Added some spaces. 2017-05-06 17:41:28 +02:00
martijn81 92cfe557ca Minor changes 2017-05-06 17:37:36 +02:00
martijn81 047cc44c83 Add edgetrigger and oneshot event types 2017-05-06 13:53:38 +02:00
Joachim Nilsson 2c675519a3 TODO: Generic UNIX backend
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-05-01 12:29:37 +02:00
Joachim Nilsson c136d199f4 Bump Debian revision
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-03-12 17:49:47 +01:00
Joachim Nilsson 4c648d23d6 Add make package to build .deb files
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-03-12 17:49:33 +01:00
Joachim Nilsson 163d7e06f7 debian/source/format: Change to native mode to allow building from GIT
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2017-03-12 17:49:17 +01:00
Joachim Nilsson f630ed7d4b bench.c: Include signal.h, not non-std sys/signal.h
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-12-15 23:34:45 +01:00
Joachim Nilsson 59542e3672 debian/: Update .gitignore file
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-11-29 08:32:19 +01:00
Joachim Nilsson d19cd6fd32 debian/: Support for building .deb packages
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-11-28 23:28:01 +01:00
Joachim Nilsson 2e6fac00bb Update ChangeLog and bump version for v1.5.2 release
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-11-27 20:33:01 +01:00
Joachim Nilsson 8a3ab17435 Fix make distcheck and missing tests/Makefile.in
This patch fixes the build regressions in libuev v1.5.1, which are due
to the new unit test framework.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-11-27 20:30:52 +01:00
Joachim Nilsson aa62e60137 Ensure check.h is included for all unit tests
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-11-27 20:30:19 +01:00
Joachim Nilsson 69c5b7f538 Update ChangeLog and bump version for v1.5.1 release
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-11-27 18:07:37 +01:00
Joachim Nilsson e765e42eb9 Verify that a timer can be stopped *before* uev_run()
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-11-25 17:28:15 +01:00
Joachim Nilsson 56a2e7ff30 Unit test for new active API
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-11-23 23:20:48 +01:00
Joachim Nilsson b6f92e2b15 New uev_*_active() API: check if watcher is active
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-11-23 23:18:33 +01:00
Joachim Nilsson 604afc6cec Travis-CI: Run new unit tests
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-11-22 01:33:17 +01:00
Joachim Nilsson 73ae8ba098 complete: Update test for unit test framework
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-11-22 01:30:40 +01:00
Joachim Nilsson 6a19fa7e93 cronrun: Update cron test to verify interval as well
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-11-22 01:27:49 +01:00
Joachim Nilsson 737ceb4398 Travis-CI: Minor cleanup
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-11-22 01:19:45 +01:00
Joachim Nilsson a8798ea6a7 configure: Remove --enable-examples option
Now unit tests and examples are separate things.  Unit tests build on
"make check" and examples must be built separately by the user.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-11-22 01:18:45 +01:00
Joachim Nilsson d976171a14 Minor cleanup
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-11-22 01:18:07 +01:00
Joachim Nilsson 398251ade6 Make bench a noinst program
Must now be run separately, but will be built along with the library.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-11-22 01:17:26 +01:00
Joachim Nilsson 628565b746 bench.c: Uncomment Xcount log message
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-11-22 01:13:03 +01:00
Joachim Nilsson de4d969ca0 Move complete test from examples/ --> tests/
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-11-22 01:12:47 +01:00
Joachim Nilsson 389c3b27ab Move cronrun test from examples/ --> tests/
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-11-22 01:09:38 +01:00
Joachim Nilsson 03a29440ef Move signal test from examples/ --> tests/
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-11-22 01:06:48 +01:00
Joachim Nilsson 9b3af80082 Add .gitignore for unit tests
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-11-22 00:37:39 +01:00
Joachim Nilsson 8f2c9f7f0e Add timer.c unit test
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-11-22 00:36:21 +01:00
Joachim Nilsson 6a21b7a90b Add unit testing framework from libite (-lite)
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-11-22 00:35:19 +01:00
Joachim Nilsson 847532f935 Update ChangeLog and bump version for v1.5 release
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-10-30 15:50:40 +01:00
Joachim Nilsson ec1290a46e ABI revision bump
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-10-30 15:50:09 +01:00
Joachim Nilsson 3bee117a85 Makefile.am: Add missing cron.c
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-10-30 15:29:22 +01:00
Joachim Nilsson 75f59b7b11 Bump version for v1.5.0-dev release cycle
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-10-30 15:09:51 +01:00
Joachim Nilsson 59e1d376db cron: New API for absolute timers
This patch adds support for at/cron-like jobs that need an absolute
timer.  The API supports waking up with an UEV_HUP callback event if the
wall clock changed due to NTP or user input while waiting.

- uev_cron_init()
- uev_cron_set()
- uev_cron_start()
- uev_cron_stop()

A very simple cronrun example/test program is also included.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-10-30 15:08:34 +01:00
Joachim Nilsson 52d8d7109b uev_timer_set(): Check return value of timerfd API
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-10-30 14:49:49 +01:00
Joachim Nilsson 7e38c11b87 Signal handlers require signo to be public
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-10-30 11:20:36 +01:00
Joachim Nilsson e5bc49a8e6 Refactor: move private watcher members to a union
This will save a few bytes of stack/heap for users.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-10-30 10:58:29 +01:00
Joachim Nilsson 1f6fa93314 Bump version for v1.4.3 dev
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-08-22 01:38:52 +02:00
Joachim Nilsson fe9b7264d0 Remove pointer casting, not needed and forbidden in ISO C
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-08-22 01:37:46 +02:00
Joachim Nilsson 6447c74722 Update .gitignore
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-07-01 01:00:20 +02:00
Joachim Nilsson f2148d41a4 Add sudo to install and ldconfig
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-06-30 18:54:23 +02:00
Joachim Nilsson 0cb4416280 Add ldconfig to build instructions, thanks rooth!
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-06-30 18:52:56 +02:00
Joachim Nilsson 4255ebb9c6 Update ChangeLog and bump version for v1.4.2 release
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-06-25 11:38:26 +02:00
Joachim Nilsson 930cce21fa Add reference to Mark Heily's libkqueue
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-06-22 14:49:54 +02:00
Joachim Nilsson addd60db22 Merge pull request #8 from westermo/master
Check timer period and timeout arguments
2016-06-17 13:51:02 +02:00
Joachim Nilsson e3d40ef010 Check timer period and timeout arguments
The uev_timer_init() and uev_timer_set() functions allow timeout and
period to be set < 0, which is not supported.  This patch adds a very
simple range check.

Signed-off-by: Joachim Nilsson <joachim.nilsson@westermo.se>
2016-06-17 13:45:11 +02:00
Joachim Nilsson 618b50ee88 Play around a bit more with the intro.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-04-25 22:17:47 +02:00
Joachim Nilsson f64301194a Move rant to end of README and simplify intro
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-04-25 20:23:03 +02:00
Joachim Nilsson bdbfe809ab Start planning for uEv 1.5 -- support Lua bindings
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-04-23 15:01:19 +02:00
Joachim Nilsson 2742adfe98 Add missing Markdown link to v1.4.1 release
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-04-22 14:57:16 +02:00
Joachim Nilsson 35d3a0f185 Update ChangeLog for v1.4.1 bug fix release
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-04-22 14:54:53 +02:00
Joachim Nilsson 441d53e46e Bump ABI revision, v1.0.1, slight semantic change (CLOEXEC)
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-04-22 14:53:29 +02:00
Joachim Nilsson 0b19880f80 Bump version to v1.4.1 for CLOEXEC fix
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-04-22 14:37:48 +02:00
Joachim Nilsson 852bd506e8 Fix Markdown syntax in older releases
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-04-22 14:34:46 +02:00
Joachim Nilsson 98c8e9f8b1 Fix leaking descriptors, use CLOEXEC
The signal and timer fd's used in libuEv were not created properly with
the CLOEXEC flag.  Hence, all forked off children calling exec*() could
access all file descriptor, sockets, etc., used by the parent process.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-04-22 14:31:51 +02:00
Joachim Nilsson 9fc5227343 Update copyright years
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-04-22 14:30:56 +02:00
Joachim Nilsson e613248392 Minor style changes and whitespace fixes
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-04-22 14:30:07 +02:00
Joachim Nilsson ac5f01ea22 Remove Emacs version-control handling
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-04-22 14:29:19 +02:00
Joachim Nilsson a0ddb4eae3 Simplify configure script
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-04-17 00:42:43 +02:00
Joachim Nilsson 1e7720735f Remove bogus autoconf version requirement
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-04-17 00:42:25 +02:00
Joachim Nilsson 8010d76133 Remove superfluous space
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-04-17 00:41:32 +02:00
Joachim Nilsson 73459ca609 Add some integration tips when using GNU autotools
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-04-17 00:27:54 +02:00
70 changed files with 6687 additions and 1633 deletions

No files matched your search

+193
View File
@@ -0,0 +1,193 @@
# CodeDocs.xyz Configuration File
#
# Rename this example to '.codedocs' and put it in the root directory of your
# repository. This file is optional, documentation will still be generated
# without it using sensible defaults.
#---------------------------------------------------------------------------
# CodeDocs Configuration
#---------------------------------------------------------------------------
# Include the Doxygen configuration from another file.
# The file must be a relative path with respect to the root of the repository.
# If any of the options in this doxyfile include a path (ie, INPUT), these
# paths will be considered relative to the root of the repository, not the
# location of the DOXYFILE.
DOXYFILE = doc/Doxyfile
# Specify external repository to link documentation with.
# This is similar to Doxygen's TAGFILES option, but will automatically link to
# tags of other repositories already using CodeDocs. List each repository to
# link with by giving its location in the form of owner/repository.
# For example:
# TAGLINKS = doxygen/doxygen CodeDocs/osg
# Note: these repositories must already be built on CodeDocs.
TAGLINKS =
#---------------------------------------------------------------------------
# Doxygen Configuration
#---------------------------------------------------------------------------
# Doxygen configuration may also be placed in this file.
# Currently, the following Doxygen configuration options are available. Refer
# to http://doxygen.org/manual/config.html for detailed explanation of the
# options. To request support for more options, contact support@codedocs.xyz.
#
# ABBREVIATE_BRIEF =
# ALIASES =
# ALLEXTERNALS =
# ALLOW_UNICODE_NAMES =
# ALPHABETICAL_INDEX =
# ALWAYS_DETAILED_SEC =
# AUTOLINK_SUPPORT =
# BRIEF_MEMBER_DESC =
# BUILTIN_STL_SUPPORT =
# CALLER_GRAPH =
# CALL_GRAPH =
# CASE_SENSE_NAMES =
# CITE_BIB_FILES =
# CLASS_DIAGRAMS =
# CLASS_GRAPH =
# COLLABORATION_GRAPH =
# COLS_IN_ALPHA_INDEX =
# CPP_CLI_SUPPORT =
# DIAFILE_DIRS =
# DIRECTORY_GRAPH =
# DISABLE_INDEX =
# DISTRIBUTE_GROUP_DOC =
# DOTFILE_DIRS =
# DOT_FONTNAME =
# DOT_FONTSIZE =
# DOT_GRAPH_MAX_NODES =
# DOT_IMAGE_FORMAT =
# DOT_TRANSPARENT =
# DOXYFILE_ENCODING =
# ENABLED_SECTIONS =
# ENABLE_PREPROCESSING =
# ENUM_VALUES_PER_LINE =
# EXAMPLE_PATH =
# EXAMPLE_PATTERNS =
# EXAMPLE_RECURSIVE =
EXCLUDE = src/bench.c src/private.h src/README.md
# EXCLUDE_PATTERNS =
# EXCLUDE_SYMBOLS =
# EXPAND_AS_DEFINED =
# EXPAND_ONLY_PREDEF =
# EXTENSION_MAPPING =
# EXTERNAL_GROUPS =
# EXTERNAL_PAGES =
# EXTRACT_ALL =
# EXTRACT_ANON_NSPACES =
# EXTRACT_LOCAL_CLASSES =
# EXTRACT_LOCAL_METHODS =
# EXTRACT_PACKAGE =
# EXTRACT_PRIVATE =
# EXTRACT_STATIC =
# EXT_LINKS_IN_WINDOW =
# FILE_PATTERNS =
# FORCE_LOCAL_INCLUDES =
# FORMULA_FONTSIZE =
# FORMULA_TRANSPARENT =
# FULL_PATH_NAMES =
# GENERATE_BUGLIST =
# GENERATE_DEPRECATEDLIST =
# GENERATE_LEGEND =
# GENERATE_TESTLIST =
# GENERATE_TODOLIST =
# GENERATE_TREEVIEW =
# GRAPHICAL_HIERARCHY =
# GROUP_GRAPHS =
# GROUP_NESTED_COMPOUNDS =
# HIDE_COMPOUND_REFERENCE= =
# HIDE_FRIEND_COMPOUNDS =
# HIDE_IN_BODY_DOCS =
# HIDE_SCOPE_NAMES =
# HIDE_UNDOC_CLASSES =
# HIDE_UNDOC_MEMBERS =
# HIDE_UNDOC_RELATIONS =
# HTML_COLORSTYLE_GAMMA =
# HTML_COLORSTYLE_HUE =
# HTML_COLORSTYLE_SAT =
# HTML_DYNAMIC_SECTIONS =
# HTML_EXTRA_FILES =
# HTML_EXTRA_STYLESHEET =
# HTML_FOOTER =
# HTML_HEADER =
# HTML_INDEX_NUM_ENTRIES =
# HTML_STYLESHEET =
# HTML_TIMESTAMP =
# IDL_PROPERTY_SUPPORT =
# IGNORE_PREFIX =
# IMAGE_PATH =
# INCLUDED_BY_GRAPH =
# INCLUDE_FILE_PATTERNS =
# INCLUDE_GRAPH =
# INCLUDE_PATH =
# INHERIT_DOCS =
# INLINE_GROUPED_CLASSES =
# INLINE_INFO =
# INLINE_INHERITED_MEMB =
# INLINE_SIMPLE_STRUCTS =
# INLINE_SOURCES =
INPUT = src/ README.md doc/API.md
# INPUT_ENCODING =
# INTERACTIVE_SVG =
# INTERNAL_DOCS =
# JAVADOC_AUTOBRIEF =
# LAYOUT_FILE =
# MACRO_EXPANSION =
# MARKDOWN_SUPPORT =
# MAX_DOT_GRAPH_DEPTH =
# MSCFILE_DIRS =
# MULTILINE_CPP_IS_BRIEF =
# OPTIMIZE_FOR_FORTRAN =
# OPTIMIZE_OUTPUT_FOR_C =
# OPTIMIZE_OUTPUT_JAVA =
# OPTIMIZE_OUTPUT_VHDL =
# OUTPUT_LANGUAGE =
# PLANTUML_JAR_PATH =
# PREDEFINED =
# PROJECT_BRIEF =
# PROJECT_LOGO =
# PROJECT_NAME =
# PROJECT_NUMBER =
# QT_AUTOBRIEF =
# RECURSIVE =
# REFERENCED_BY_RELATION =
# REFERENCES_LINK_SOURCE =
# REFERENCES_RELATION =
# REPEAT_BRIEF =
# SEARCHENGINE =
# SEARCH_INCLUDES =
# SEPARATE_MEMBER_PAGES =
# SHORT_NAMES =
# SHOW_FILES =
# SHOW_GROUPED_MEMB_INC =
# SHOW_INCLUDE_FILES =
# SHOW_NAMESPACES =
# SHOW_USED_FILES =
# SIP_SUPPORT =
# SKIP_FUNCTION_MACROS =
# SORT_BRIEF_DOCS =
# SORT_BY_SCOPE_NAME =
# SORT_GROUP_NAMES =
# SORT_MEMBERS_CTORS_1ST =
# SORT_MEMBER_DOCS =
# SOURCE_BROWSER =
# SOURCE_TOOLTIPS =
# STRICT_PROTO_MATCHING =
# STRIP_CODE_COMMENTS =
# STRIP_FROM_INC_PATH =
# STRIP_FROM_PATH =
# SUBGROUPING =
# TAB_SIZE =
# TEMPLATE_RELATIONS =
# TREEVIEW_WIDTH =
# TYPEDEF_HIDES_STRUCT =
# UML_LIMIT_NUM_FIELDS =
# UML_LOOK =
USE_MDFILE_AS_MAINPAGE = doc/API.md
# VERBATIM_HEADERS =
#
+90
View File
@@ -0,0 +1,90 @@
Contributing to the Project
===========================
Thank you for considering contributing back to [Free Software][1]!
There are a few things we would like you to consider when filing an
issue or pull request with this project:
1. If you are filing a bug report or feature request
Please take the time to check if an issue already has been filed
matching your problem
2. What version are you running, have you tried the latest release?
UNIX distributions often package and test software for their
particular brand. If you are using a pre-packaged version,
then please file a bug with that distribution instead.
3. Coding Style
Lines are allowed to be longer than 72 characters these days, there
is no enforced max. length.
> **Tip:** Always submit code that follows the style of surrounding code!
The coding style itself is strictly Linux [KNF][], like GIT it is
becoming a de facto standard for C programming
https://www.kernel.org/doc/Documentation/CodingStyle
4. Logical Change Sets
Changes should be broken down into logical units that add a feature
or fix a bug. Keep changes separate from each other and do not mix a
bug fix with a whitespace cleanup or a new feature addition.
This is important not only for readilibity, or for the possibility of
maintainers to revert changes, but does also increase your chances of
having a change accepted.
5. Commit messages
Commit messages exist to track *why* a change was made. Try to be as
clear and concise as possible in your commit messages, and always, be
proud of your work and set up a proper GIT identity for your commits:
git config --global user.name "J. Random Hacker"
git config --global user.email random.j.hacker@example.com
See this helpful guide for how to write simple, readable commit
messages, or have at least a look at the below example.
http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html
Example
-------
Example commit message from the [Pro Git][gitbook] online book, notice
how `git commit -s` is used to automatically add a `Signed-off-by`:
Capitalized, short (50 chars or less) summary
More detailed explanatory text, if necessary. Wrap it to about 72
characters or so. In some contexts, the first line is treated as the
subject of an email and the rest of the text as the body. The blank
line separating the summary from the body is critical (unless you omit
the body entirely); tools like rebase can get confused if you run the
two together.
Write your commit message in the imperative: "Fix bug" and not "Fixed bug"
or "Fixes bug." This convention matches up with commit messages generated
by commands like git merge and git revert.
Further paragraphs come after blank lines.
- Bullet points are okay, too
- Typically a hyphen or asterisk is used for the bullet, followed by a
single space, with blank lines in between, but conventions vary here
- Use a hanging indent
Signed-off-by: J. Random Hacker <random.j.hacker@example.com>
[1]: http://www.gnu.org/philosophy/free-sw.en.html
[KNF]: https://en.wikipedia.org/wiki/Kernel_Normal_Form
[gitbook]: https://git-scm.com/book/ch5-2.html
+3
View File
@@ -0,0 +1,3 @@
# These are supported funding model platforms
github: [troglobit]
+12
View File
@@ -0,0 +1,12 @@
# Security Policy
## Supported Versions
libuEv is a small project, as such we have no possibility to support older versions.
The only supported version is the latest released on GitHub:
<https://github.com/troglobit/libuev/releases>
## Reporting a Vulnerability
Contact the project's main author and owner to report and discuss vulnerabilities.
+68
View File
@@ -0,0 +1,68 @@
name: Bob the Builder
# Run on all branches, including all pull requests, except the 'dev'
# branch since that's where we run Coverity Scan (limited tokens/day)
on:
push:
branches:
- '**'
- '!dev'
pull_request:
branches:
- '**'
jobs:
build:
# Verify we can build on latest Ubuntu with both gcc and clang
name: ${{ matrix.compiler }}
runs-on: ubuntu-latest
strategy:
matrix:
compiler: [gcc, clang]
fail-fast: false
env:
MAKEFLAGS: -j3
CC: ${{ matrix.compiler }}
steps:
- name: Install dependencies
run: |
sudo apt-get -y update
sudo apt-get -y install tree doxygen
- uses: actions/checkout@v4
- name: Configure
run: |
./autogen.sh
./configure --prefix= --enable-examples --disable-silent-rules
- name: Build
run: |
make
- name: Install to ~/tmp and Inspect
run: |
DESTDIR=~/tmp make install-strip
tree ~/tmp
- name: Run Unit Tests
run: |
make check || (cat test/test-suite.log; false)
- name: Upload Test Results
uses: actions/upload-artifact@v4
with:
name: libuev-test-${{ matrix.compiler }}
path: test/*
debian:
name: Verify Debian Package
runs-on: ubuntu-latest
container: debian:stable
steps:
- uses: actions/checkout@v4
- name: Installing dependencies
run: |
apt-get update
apt-get install -y build-essential autoconf automake pkg-config doxygen \
dpkg-dev debhelper devscripts
- name: Building Debian package
run: |
./autogen.sh
./configure
make distcheck
make package
cat ../*.changes
+76
View File
@@ -0,0 +1,76 @@
name: Coverity Scan
on:
push:
branches:
- 'dev'
env:
PROJECT_NAME: libuev
CONTACT_EMAIL: troglobit@gmail.com
COVERITY_NAME: troglobit-libuev
COVERITY_PROJ: troglobit%2Flibuev
jobs:
coverity:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Fetch latest Coverity Scan MD5
id: var
env:
TOKEN: ${{ secrets.COVERITY_SCAN_TOKEN }}
run: |
wget -q https://scan.coverity.com/download/cxx/linux64 \
--post-data "token=$TOKEN&project=${COVERITY_PROJ}&md5=1" \
-O coverity-latest.tar.gz.md5
echo "md5=$(cat coverity-latest.tar.gz.md5)" | tee -a $GITHUB_OUTPUT
- uses: actions/cache@v4
id: cache
with:
path: coverity-latest.tar.gz
key: ${{ runner.os }}-coverity-${{ steps.var.outputs.md5 }}
restore-keys: |
${{ runner.os }}-coverity-${{ steps.var.outputs.md5 }}
${{ runner.os }}-coverity-
${{ runner.os }}-coverity
- name: Download Coverity Scan
env:
TOKEN: ${{ secrets.COVERITY_SCAN_TOKEN }}
run: |
if [ ! -f coverity-latest.tar.gz ]; then
wget -q https://scan.coverity.com/download/cxx/linux64 \
--post-data "token=$TOKEN&project=${COVERITY_PROJ}" \
-O coverity-latest.tar.gz
else
echo "Latest Coverity Scan available from cache :-)"
md5sum coverity-latest.tar.gz
fi
mkdir coverity
tar xzf coverity-latest.tar.gz --strip 1 -C coverity
- name: Configure
run: |
./autogen.sh
./configure --prefix= --enable-examples
- name: Build
run: |
export PATH=`pwd`/coverity/bin:$PATH
cov-build --dir cov-int make
- name: Submit results to Coverity Scan
env:
TOKEN: ${{ secrets.COVERITY_SCAN_TOKEN }}
run: |
tar czvf ${PROJECT_NAME}.tgz cov-int
curl \
--form project=${COVERITY_NAME} \
--form token=$TOKEN \
--form email=${CONTACT_EMAIL} \
--form file=@${PROJECT_NAME}.tgz \
--form version=trunk \
--form description="${PROJECT_NAME} $(git rev-parse HEAD)" \
https://scan.coverity.com/builds?project=${COVERITY_PROJ}
- name: Upload build.log
uses: actions/upload-artifact@v4
with:
name: coverity-build.log
path: cov-int/build-log.txt
+57
View File
@@ -0,0 +1,57 @@
name: Release General
on:
push:
tags:
- 'v*'
jobs:
release:
name: Build and upload release tarball
if: startsWith(github.ref, 'refs/tags/')
runs-on: ubuntu-latest
env:
MAKEFLAGS: -j3
steps:
- uses: actions/checkout@v4
- name: Installing dependencies ...
run: |
sudo apt-get -y update
sudo apt-get -y install tree doxygen
- name: Setting release variables ...
id: build
run: |
ver=${GITHUB_REF#refs/tags/}
echo "ver=${ver}" >> $GITHUB_OUTPUT
if echo $ver | grep -qE '^[0-9]+\.[0-9]+(\.[0-9]+)?(-alpha|-beta|-rc)[0-9]*$'; then
echo "pre=true" >> $GITHUB_OUTPUT
else
echo "pre=false" >> $GITHUB_OUTPUT
fi
if echo $ver | grep -qE '^[0-9.]+\.[0-9.]+(\.[0-9]+)?$'; then
echo "latest=true" >> $GITHUB_OUTPUT
else
echo "latest=false" >> $GITHUB_OUTPUT
fi
- name: Creating Makefiles ...
run: |
./autogen.sh
./configure
- name: Build release ...
run: |
make release || (cat test/test-suite.log; false)
ls -lF ../
mkdir -p artifacts/
mv ../*.tar.* artifacts/
- name: Extract ChangeLog entry ...
run: |
awk '/-----*/{if (x == 1) exit; x=1;next}x' ChangeLog.md \
|head -n -1 > release.md
cat release.md
- uses: ncipollo/release-action@v1
with:
name: libuEv ${{ github.ref_name }}
prerelease: ${{ steps.build.outputs.pre }}
makeLatest: ${{ steps.build.outputs.latest }}
bodyFile: "release.md"
artifacts: "artifacts/*"
+8 -1
View File
@@ -6,8 +6,15 @@
*.a *.a
*.la *.la
*.lo *.lo
*.html
.config
.deps .deps
.libs .libs
.unpacked
ID
GTAGS
GRTAGS
GPATH
compile compile
config.* config.*
configure configure
@@ -23,7 +30,7 @@ aclocal.m4
ar-lib ar-lib
autom4te.cache autom4te.cache
bench bench
test
libuev*.tar.* libuev*.tar.*
libuev.pc libuev.pc
!libuev.pc.in !libuev.pc.in
test-driver
-30
View File
@@ -1,30 +0,0 @@
# Travis CI integration -- https://travis-ci.org/troglobit/libuev
# Defaults to GNU GCC and autotools: ./configure && make && make test
language: c
# We don't need to install packages, use dockerized build, quicker
sudo: false
env:
global:
# The next declaration is the encrypted COVERITY_SCAN_TOKEN, created
# via the "travis encrypt" command using the project repo's public key
- secure: "ikQcWMCLFoxq0+wMiqrNT5HRn0d4e3AxuF8VzNUNFrk6jUvHIufC/OKvr8VWPTjCaAQXZjWfdQAAARUXzJV10WZ7xpiv5qt4bt26Qih2AwMPMJeUOYrqXgQqhTPBp05iLYpo4ybICteXRI3zKKUA1wkdDC0jyu3rl+Fbveekbe0="
addons:
coverity_scan:
project:
name: "troglobit/libuev"
description: "libuEv | Simple event loop for Linux"
notification_email: troglobit@gmail.com
build_command_prepend: "./autogen && ./configure --enable-examples"
build_command: "make clean all"
branch_pattern: dev
# We don't use configure, so we must define our own build script.
script:
- ./autogen.sh
- ./configure --disable-silent-rules --enable-examples
- make clean
- make -j5
- make test
+1 -1
View File
@@ -1,5 +1,5 @@
Current maintainer of libuEv: Current maintainer of libuEv:
Joachim Nilsson <troglobit()gmail!com> Joachim Wiberg <troglobit()gmail!com>
Original LibUEvent author: Original LibUEvent author:
Flemming Madsen <flemming!madsen()madsensoft!dk> Flemming Madsen <flemming!madsen()madsensoft!dk>
+259 -12
View File
@@ -4,6 +4,242 @@ Change Log
All notable changes to the project are documented in this file. All notable changes to the project are documented in this file.
[v2.4.1][] - 2024-01-04
-----------------------
### Changes
- Update README with list of moden Linux APIs used
### Fixes
- Fix #27: possible buffer overrun in `uev_run()`, found by Steve Palmer
[v2.4.0][] - 2021-10-03
-----------------------
Please note, this release is a major ABI bump due to changes in `uev_t`
which requires recompiling all programs that use libuEv.
Also, libuEv is built for 64 bit `time_t`, this means all applications
that link with libuEv also must be built with the same build flags.
This applies in particular to systems with GLIBC v2.34, which now
require applications to add the following to their `CPPFLAGS`:
CPPFLAGS += -D_TIME_BITS=64 -D_FILE_OFFSET_BITS=64
Applications that use `pkg-config` will get these extra flags from the
`libuev.pc` file in the distribution archive.
### Changes
- More examples added for fork + signals + timer
- Add `struct signalfd_siginfo` to `uev_t`, valid for signal watchers.
Now more metadata is available to signal callbacks
### Fixes
- Fix #24: Replace obsolete autotools macro, by Otto Urpelainen
- Fix #25: GLIBC v2.34 require `-D_FILE_OFFSET_BITS=64` for applications
and libraries that want a 64-bit `time_t`. Affects library and test
programs used for `make check`, as well as all other applications that
link with libuEv, so the `libuev.pc` file is also updated
- Fix error handling in callbacks in examples
[v2.3.2][] - 2021-02-12
-----------------------
### Changes
- Copyright updates, including LICENSE file, year + author last name
- Add tar.gz archives to distribution
- Enable .sha256 checksums for all tarballs
### Fixes
- Debian packaging fixes only
[v2.3.1][] - 2020-02-22
-----------------------
### Fixes
- Debian packaging fixes only
[v2.3.0][] - 2019-04-06
-----------------------
### Changes
- Support for Linux eventfd, `uev_event_*()` see [API.md][] for details
[v2.2.0][] - 2018-10-04
-----------------------
**NOTE:** You now have to explicitly include `sys/queue.h`, or provide a
local version of `queue.h`, if your application depends on it.
### Changes
- Replaced BSD `queue.h` doubly-linked lst API with own implementation.
Making libuEv stand-alone, no longer imposing any particular version
of `queue.h` on the user
- Enforce `-std=gnu11` to unlock `typeof()` in older GCC versions
- Code cleanup
### Fixes
- Fix missing header deps. in `Makefile.am`, library did not rebuild
properly if any of the local header files were changed
[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
-----------------------
### Changes
- Support for edge triggered and oneshot event types
- Add `make package` build target to trigger a `.deb` package build
- Support 64 bit `time_t` on 32 bit GLIBC systems
### Fixes
- `bench.c`: Use `signal.h`, not non-standard `sys/signal.h`
[v1.5.2][] - 2016-11-27
-----------------------
### Fixes
- Fix build regression in v1.5.1
[v1.5.1][] - 2016-11-27
-----------------------
### Changes
- Add support for checking if a watcher is active.
- Refactor unit testing framework
[v1.5.0][] - 2016-10-30
-----------------------
### Changes
- Add support for absolute timers with the `uev_cron_*()` API.
- Update build & install instructions in [README.md][]
### Fixes
- Fix `uev_timer_set()` so that it returns error in case the underlying
Linux timerfd API fails.
[v1.4.2][] - 2016-06-25
-----------------------
### Changes
- Add range checks for `period` and `timeout` to `uev_timer_init()` and
`uev_timer_set()`. If either on is `< 0` libuEv now return `ERANGE`.
[v1.4.1][] - 2016-04-22
-----------------------
### Changes
- Add some `pkg-config` integration tips for developers using libuEv
with GNU autotools in their projects.
### Fixes
- Add missing `SFD_CLOEXEC` and `TFD_CLOEXEC` to signal and timer file
descriptors. This prevents these file descriptors from "leaking" into
sub-processes of the parent thread. The kernel will atomically close
these descriptors for forked-off children calling the exec*() family
of syscalls.
- Minor coding style fixes and simplification of build scripts.
[v1.4.0][] - 2016-03-22 [v1.4.0][] - 2016-03-22
----------------------- -----------------------
@@ -11,12 +247,11 @@ This release changes the header file namespace, which was silently
introduced in [v1.2.1][]. Apologies for any problems this may cause! introduced in [v1.2.1][]. Apologies for any problems this may cause!
### Changes ### Changes
- Change namespace for header files: `libuev/` to `uev/`, e.g. using - Change namespace for header files: `libuev/` to `uev/`, e.g. using
`pkg-config` your C program must now `#include <uev/uev.h>` `pkg-config` your C program must now `#include <uev/uev.h>`
- Support for EPOLLPRI events for I/O watchers, thanks to Markus Svilans - Support for `EPOLLPRI` events for I/O watchers, thanks to Markus Svilans
- Simplified joystick example - Simplified joystick example
- Updated README slightly - Updated [README.md][] slightly
[v1.3.1][] - 2016-02-02 [v1.3.1][] - 2016-02-02
@@ -24,7 +259,7 @@ introduced in [v1.2.1][]. Apologies for any problems this may cause!
### Fixes ### Fixes
- Remove symlinks to Markdown files from GIT - 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 [v1.3.0][] - 2016-01-22
@@ -60,7 +295,7 @@ Very minor release.
- Dropped [TODO.md][] from distribution archives, only for devs - Dropped [TODO.md][] from distribution archives, only for devs
### Fixes ### 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 - Silence annoying warning from newer GNU ar in Ubuntu 15.10
@@ -218,7 +453,24 @@ v0.0.1 - 2012-03-17
Lua users mailing list. Lua users mailing list.
[UNRELEASED]: https://github.com/troglobit/libuev/compare/v1.4.0...HEAD [UNRELEASED]: https://github.com/troglobit/libuev/compare/v2.4.0...HEAD
[v2.4.1]: https://github.com/troglobit/libuev/compare/v2.4.0...v2.4.1
[v2.4.0]: https://github.com/troglobit/libuev/compare/v2.3.2...v2.4.0
[v2.3.2]: https://github.com/troglobit/libuev/compare/v2.3.1...v2.3.2
[v2.3.1]: https://github.com/troglobit/libuev/compare/v2.3.0...v2.3.1
[v2.3.0]: https://github.com/troglobit/libuev/compare/v2.2.0...v2.3.0
[v2.2.0]: https://github.com/troglobit/libuev/compare/v2.1.3...v2.2.0
[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 [v1.4.0]: https://github.com/troglobit/libuev/compare/v1.3.1...v1.4.0
[v1.3.1]: https://github.com/troglobit/libuev/compare/v1.3.0...v1.3.1 [v1.3.1]: https://github.com/troglobit/libuev/compare/v1.3.0...v1.3.1
[v1.3.0]: https://github.com/troglobit/libuev/compare/v1.2.3...v1.3.0 [v1.3.0]: https://github.com/troglobit/libuev/compare/v1.2.3...v1.3.0
@@ -234,6 +486,7 @@ Lua users mailing list.
[v1.0.1]: https://github.com/troglobit/libuev/compare/v1.0.0...v1.0.1 [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 [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 [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 [README.md]: https://github.com/troglobit/libuev/blob/master/README.md
[ChangeLog.md]: https://github.com/troglobit/libuev/blob/master/ChangeLog.md [ChangeLog.md]: https://github.com/troglobit/libuev/blob/master/ChangeLog.md
[joystick.c]: https://github.com/troglobit/libuev/blob/master/joystick.c [joystick.c]: https://github.com/troglobit/libuev/blob/master/joystick.c
@@ -243,9 +496,3 @@ Lua users mailing list.
[libuevent]: https://code.google.com/p/libuevent/ [libuevent]: https://code.google.com/p/libuevent/
[Flemming Madsen]: http://www.madsensoft.dk [Flemming Madsen]: http://www.madsensoft.dk
[Initial announcement]: http://lua-users.org/lists/lua-l/2012-03/msg00510.html [Initial announcement]: http://lua-users.org/lists/lua-l/2012-03/msg00510.html
<!--
-- Local Variables:
-- mode: markdown
-- End:
-->
+1 -1
View File
@@ -1,5 +1,5 @@
Copyright (c) 2012 Flemming Madsen <flemming!madsen()madsensoft!dk> Copyright (c) 2012 Flemming Madsen <flemming!madsen()madsensoft!dk>
Copyright (c) 2013-2015 Joachim Nilsson <troglobit()gmail!com> Copyright (c) 2013-2024 Joachim Wiberg <troglobit()gmail!com>
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
+33 -39
View File
@@ -1,50 +1,29 @@
ACLOCAL_AMFLAGS = -I m4 ACLOCAL_AMFLAGS = -I m4
SUBDIRS = src test
lib_LTLIBRARIES = libuev.la DIST_SUBDIRS = doc src examples test
pkgincludedir = $(includedir)/uev
pkginclude_HEADERS = uev.h private.h queue.h
libuev_la_SOURCES = uev.c io.c timer.c signal.c
check_PROGRAMS = bench
bench_CPPFLAGS = -D_GNU_SOURCE
bench_LDADD = $(top_srcdir)/libuev.la
libuev_la_CPPFLAGS = -D_GNU_SOURCE
libuev_la_CFLAGS = -W -Wall -Wextra
libuev_la_LDFLAGS = $(AM_LDFLAGS) -version-info 1:0:0
pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = libuev.pc
doc_DATA = README.md LICENSE doc_DATA = README.md LICENSE
EXTRA_DIST = README.md LICENSE AUTHORS ChangeLog.md EXTRA_DIST = README.md LICENSE AUTHORS ChangeLog.md
DIST_SUBDIRS = examples
SUBDIRS = .
if ENABLE_EXAMPLES if ENABLE_EXAMPLES
SUBDIRS += examples SUBDIRS += examples
endif endif
test joystick: all-recursive if ENABLE_DOXYGEN
./examples/$@ SUBDIRS += doc
.PHONY: doc
doc:
$(MAKE) -C @top_builddir@/doc $@
check-local: ## The distribution should include man pages, which are generated
@echo " BENCH $(PACKAGE)" dist-hook: doc
@./bench else
if ENABLE_EXAMPLES doc:
@echo " TEST $(PACKAGE)" @echo "Doxygen documentation (html + man) disabled, skipping ..."
@./examples/test
endif endif
## Generate MD5 checksum file
MD5 = md5sum
md5-dist:
@for file in $(DIST_ARCHIVES); do \
$(MD5) $$file > $$file.md5; \
done
## Check if tagged in git ## Check if tagged in git
release-hook: release-hook:
if [ ! `git tag | grep $(PACKAGE_VERSION)` ]; then \ @if [ ! `git tag -l v$(PACKAGE_VERSION) | grep v$(PACKAGE_VERSION)` ]; then \
echo; \ echo; \
printf "\e[1m\e[41mCannot find release tag $(PACKAGE_VERSION)\e[0m\n"; \ printf "\e[1m\e[41mCannot find release tag $(PACKAGE_VERSION)\e[0m\n"; \
printf "\e[1m\e[5mDo release anyway?\e[0m "; read yorn; \ printf "\e[1m\e[5mDo release anyway?\e[0m "; read yorn; \
@@ -60,10 +39,25 @@ release-hook:
echo; \ echo; \
fi fi
## Generate .deb package
package:
@debuild -uc -us -B --lintian-opts --profile debian -i -I --show-overrides
## Target to run when building a release ## Target to run when building a release
release: dist release-hook md5-dist release: release-hook distcheck
@for file in $(DIST_ARCHIVES); do \ @for file in $(DIST_ARCHIVES); do \
printf "$$file \tDistribution tarball\n"; \ md5sum $$file > ../$$file.md5; \
printf "$$file.md5\t"; cat $$file.md5 | cut -f1 -d' '; \ sha256sum $$file > ../$$file.sha256; \
mv $$file* ../; \ done
@mv $(DIST_ARCHIVES) ../
@echo
@echo "Resulting release files:"
@echo "================================================================="
@for file in $(DIST_ARCHIVES); do \
printf "%-32s Distribution tarball\n" $$file; \
printf "%-32s " $$file.md5; cat ../$$file.md5 | cut -f1 -d' '; \
printf "%-32s " $$file.sha256; cat ../$$file.sha256 | cut -f1 -d' '; \
done
@for file in `cd ..; ls $(PACKAGE)*_$(VERSION)*`; do \
printf "%-32s Debian/Ubuntu package\n" $$file; \
done done
+85 -300
View File
@@ -1,347 +1,132 @@
libuEv | Simple event loop for Linux µEv | Simple event loop for Linux
==================================== ==================================
[![Travis Status][]][Travis] [![Coverity Status][]][Coverity Scan] [![License Badge][]][License] [![GitHub Status][]][GitHub] [![Coverity Status][]][Coverity Scan]
Table of Contents
-----------------
* [Introduction](#introduction) * [Introduction](#introduction)
* [API](#api) * [API](doc/API.md#overview)
* [Create an Event Context](#create-an-event-context) * [Create an Event Context](doc/API.md#create-an-event-context)
* [Register an Event Watcher](#register-an-event-watcher) * [Register an Event Watcher](doc/API.md#register-an-event-watcher)
* [Start Event Loop](#start-event-loop) * [Start Event Loop](doc/API.md#start-event-loop)
* [Summary](#summary) * [Summary](doc/API.md#summary)
* [Using -luev](#using--luev) * [Using -luev](doc/API.md#using--luev)
* [Joystick Example](#joystick-example) * [Joystick Example](doc/API.md#joystick-example)
* [Build & Install](#build--install) * [Build & Install](#build--install)
* [Origin & References](#origin--references) * [Origin & References](#origin--references)
> **NOTE:** Incompatible failure mode changes in v2.0 compared to v1.x!
Introduction Introduction
------------ ------------
> “Why an event loop, why not use threads?” [libuEv][] is a small event loop that wraps the Linux `epoll()` family
of APIs. It is similar to the more established [libevent][], [libev][]
and the venerable [Xt(3)][] event loop. The *µ* in the name refers to
both its limited feature set and the size impact of the library.
With the advent of light-weight processes (threads) programmers these Linux APIs supported and wrapped for ease-of-use:
days have a [golden hammer](http://c2.com/cgi/wiki?GoldenHammer) they
often swing without consideration. Event loops and non-blocking I/O is
often a far easier approach, as well as less error prone.
The purpose of many applications is, with a little logic sprinkled on - `epoll(2)`
top, to act on network packets entering an interface, timeouts expiring, - `eventfd(2)`
mouse clicks, or other types of events. Such applications are often - `signalfd(2)`
very well suited to use an event loop. - `timerfd(2)`
Applications that need to churn massively parallel algorithms are more Failure mode changes introduced in v2.0 may affect users of v1.x, See
suitable for running multiple (independent) threads on several CPU the [ChangeLog][] for the full details.
cores. However, threaded applications must deal with the side effects
of concurrency, like race conditions, deadlocks, live locks, etc.
Writing error free threaded applications is hard, debugging them can be
even harder.
Sometimes the combination of multiple threads *and* an event loop per The [API documentation](doc/API.md) is available as a separate document.
thread can be the best approach, but each application of course needs to
be broken down individually to find the most optimal approach. Do keep
in mind, however, that not all systems your application will run on have
multiple CPU cores -- some small embedded systems still use a single CPU
core, even though they run Linux, with multiple threads a program may
actually run slower! Always profile your program, and if possible, test
it on different architectures.
[libuEv][] is a simple event loop in the style of the more established
[libevent][1], [libev][2] and the venerable [Xt(3)][3] event loop. The
*u* (micro) in the name refers to both the small feature set and the
small size overhead impact of the library. The primary target of
[libuEv][] is a modern Linux system.
Experienced developers may appreciate that [libuEv][] is built on top of
modern Linux APIs: epoll, timerfd and signalfd. Note, a certain amount
of care is needed when dealing with APIs that employ signalfd. For
details, see [this article][4] at [lwn.net](http://lwn.net).
> “Event driven software improves concurrency” -- [Dave Zarzycki, Apple][]
API Example
--- -------
The C interface to [libuEv][] is listed in `uev.h`. It handles three Notice how watcher conditions like `UEV_ERROR` must be handled by each
different types of events: I/O (files, sockets, message queues, etc.), callback. I/O watchers must also check for `UEV_HUP`. Both errors are
timers, and signals. With a slight caveat on signals detailed below usually fatal, libuEv makes sure to stop each watcher before a callback
in the [Summary](#summary). runs, leaving it up to the callback to take appropriate action.
```C ```C
/* Set up a timer watcher to call cb() every other second */
#include <stdio.h>
#include <uev/uev.h>
/* static void cb(uev_t *w, void *arg, int events)
* Callback example, arg is passed from watcher's *_init() {
* w->fd holds the file descriptor, events is set by libuEv if (UEV_ERROR == events) {
* to indicate if any of UEV_READ and/or UEV_WRITE is ready. puts("Problem with timer, attempting to restart.");
*/ uev_timer_start(w);
void callback (uev_t *w, void *arg, int events); return;
/* Event loop: Notice the use of flags! */
int uev_init (uev_ctx_t *ctx);
int uev_exit (uev_ctx_t *ctx);
int uev_run (uev_ctx_t *ctx, int flags); /* UEV_NONE, UEV_ONCE, and/or UEV_NONBLOCK */
/* I/O watcher: fd is non-blocking, events is UEV_READ and/or UEV_WRITE */
int uev_io_init (uev_ctx_t *ctx, uev_t *w, uev_cb_t *cb, void *arg, int fd, int events);
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: timeout 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 */
int uev_timer_stop (uev_t *w); /* Stop a timer */
/* Signal watcher: signo is the signal to wait for, e.g., SIGTERM */
int uev_signal_init (uev_ctx_t *ctx, uev_t *w, uev_cb_t *cb, void *arg, int signo);
int uev_signal_set (uev_t *w, int signo); /* Change signal to wait for */
int uev_signal_start(uev_t *w); /* Restart a stopped signal watcher */
int uev_signal_stop (uev_t *w); /* Stop signal watcher */
```
### Create an Event Context
To monitor events the developer first creates an *event context*, this
is achieved by calling `uev_init()` with a pointer to a (thread) local
`uev_ctx_t` variable.
```C
uev_ctx_t ctx;
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.
Here is a signal example:
```C
void cleanup_exit(uev_t *w, void *arg, int events)
{
/* Graceful exit, with optional cleanup ... */
uev_exit(w->ctx);
}
int main(void)
{
uev_t sigterm_watcher;
.
.
.
uev_signal_init(&ctx, &sigterm_watcher, cleanup_exit, NULL, SIGTERM);
.
.
.
}
```
### Start Event Loop
When all watchers are registered, call the *event loop* with `uev_run()`
and the argument to the event context. The `flags` parameter can be
used to integrate [libuEv][] into another event loop.
In this example we set `flags` to none:
```C
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.
**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.
### Summary
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
**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
opened in blocking mode. Be careful out there!
**Note 2:** When closing a descriptor or socket, make sure to first stop
your watcher, if possible. This will help prevent any nasty side
effects on your program.
**Note 3:** As mentioned above, a certain amount of care is needed when
dealing with signalfd. If your application use `system()` you replace
that with `fork()`, and then in the child, unblock all signals blocked
by your parent process, before you run `exec()`. This because Linux
does not unblock signals for your children, and neither does most (all?)
C-libraries. See the [finit][6] project's implementation of `run()` for
an example of this.
Using -luev
-----------
LibuEv is by default installed as a library with a few header files, you
should only ever need to include one:
#include <uev/uev.h>
The output from the `pkg-config` tool holds no surprises:
$ pkg-config --libs --static --cflags libuev
-I/usr/local/include -L/usr/local/lib -luev
The prefix path `/usr/local/` shown here is only the default. Use the
`configure` script to select a different prefix when installing libuEv.
Joystick Example
----------------
Here follows a very brief example to illustrate how one can use libuEv
to act upon joystick input.
```C
#include <err.h>
#include <errno.h>
#include <stdio.h>
#include <stdint.h>
#include <fcntl.h>
#include <unistd.h>
#include <uev/uev.h>
struct js_event {
uint32_t time; /* event timestamp in milliseconds */
int16_t value; /* value */
uint8_t type; /* event type */
uint8_t number; /* axis/button number */
} e;
static void joystick_cb(uev_t *w, void *arg, int events)
{
read(w->fd, &e, sizeof(e));
switch (e.type) {
case 1:
printf("Button %d %s\n", e.number, e.value ? "pressed" : "released");
break;
case 2:
printf("Joystick axis %d moved, value %d!\n", e.number, e.value);
break;
} }
}
puts("Every other second");
int main(void) }
{
int fd; int main(void)
uev_t watcher; {
uev_ctx_t ctx; uev_ctx_t ctx;
uev_t timer;
fd = open("/dev/input/js1", O_RDONLY, O_NONBLOCK);
if (fd < 0)
errx(errno, "Cannot find a joystick attached.");
uev_init(&ctx); uev_init(&ctx);
uev_io_init(&ctx, &watcher, joystick_cb, NULL, fd, UEV_READ); uev_timer_init(&ctx, &timer, cb, NULL, 2 * 1000, 2 * 1000);
puts("Starting, press Ctrl-C to exit.");
return uev_run(&ctx, 0); return uev_run(&ctx, 0);
} }
``` ```
To build the example, follow installation instructions below, then save
the code as `joystick.c` and call GCC
gcc `pkg-config --libs --static --cflags libuev` -o joystick joystick.c
Alternatively, call the `Makefile` with <kbd>make joystick</kbd> from
the unpacked [libuEv][] distribution.
More complete and relevant example uses of [libuEv][] is the FTP/TFTP
server [uftpd][5], and the Linux `/sbin/init` replacement [finit][6].
Both successfully employ [libuEv][].
Also see the `bench.c` program (<kbd>make bench</kbd> from within the
library) for [reference benchmarks][7] against [libevent][1] and
[libev][2].
Build & Install Build & Install
--------------- ---------------
The library is built for and developed on GNU/Linux systems, patches to
support *BSD and its kqueue interface are most welcome.
libuEv use the GNU configure and build system. To try out the bundled libuEv use the GNU configure and build system. To try out the bundled
examples, use the `--enable-examples` switch to the `configure` script. examples, use the `--enable-examples` switch to the `configure` script.
There is also a limited unit test suite that can be useful to learn how
the library works.
./configure ```sh
make all ./configure
make test make -j5
make install make check
sudo make install-strip
sudo ldconfig
```
The resulting .so file is ~14 kiB (<kbd>make install-strip</kbd>). The resulting .so library is ~23 kiB.
To build from GIT sources; clone the repository and run the `autogen.sh`
script. This requires GNU `automake`, `autoconf` amd `libtool` to be
installed on your system. (If you build from a released tarball you do
not need them.)
Origin & References Origin & References
------------------- -------------------
[libuEv][] was originally based on [LibUEvent][8] by [Flemming Madsen][] [libuEv][] is developed and maintained by [Joachim Wiberg][] on GitHub.
but has been completely rewritten with a much clearer API. Now more It is primarily built for and developed on GNU/Linux systems, patches to
similar to the famous [libev][2] by [Mark Lehmann][]. Another small support the BSD [kqueue][] interface are most welcome.
event library used for inspiration is the very small [Picoev][9] by
[Oku Kazuho][].
[libuEv][] is developed and maintained by [Joachim Nilsson][]. Originally based on [LibUEvent][] by [Flemming Madsen][], uEv has since
evolved to support all of the Linux `epoll()` family APIs. It is now
more similar to the excellent [libev][] by [Mark Lehmann][], with some
inspiration also from [picoev][] by [Oku Kazuho][].
[1]: http://libevent.org
[2]: http://software.schmorp.de/pkg/libev.html [ChangeLog]: https://github.com/troglobit/libuev/blob/master/ChangeLog.md
[3]: http://unix.com/man-page/All/3x/XtDispatchEvent [License]: https://en.wikipedia.org/wiki/MIT_License
[4]: http://lwn.net/Articles/415684/ [License Badge]: https://img.shields.io/badge/License-MIT-teal.svg
[5]: https://github.com/troglobit/uftpd [GitHub]: https://github.com/troglobit/libuev/actions/workflows/build.yml/
[6]: https://github.com/troglobit/finit [GitHub Status]: https://github.com/troglobit/libuev/actions/workflows/build.yml/badge.svg
[7]: http://libev.schmorp.de/bench.html
[8]: http://code.google.com/p/libuevent/
[9]: https://github.com/kazuho/picoev
[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 [Coverity Scan]: https://scan.coverity.com/projects/3846
[Coverity Status]: https://scan.coverity.com/projects/3846/badge.svg [Coverity Status]: https://scan.coverity.com/projects/3846/badge.svg
[libevent]: https://libevent.org
[Xt(3)]: https://unix.com/man-page/All/3x/XtDispatchEvent
[LibUEvent]: https://code.google.com/p/libuevent/
[picoev]: https://github.com/kazuho/picoev
[libev]: http://software.schmorp.de/pkg/libev.html
[LibuEv]: https://github.com/troglobit/libuev [LibuEv]: https://github.com/troglobit/libuev
[kqueue]: https://github.com/mheily/libkqueue
[Oku Kazuho]: https://github.com/kazuho [Oku Kazuho]: https://github.com/kazuho
[Mark Lehmann]: http://software.schmorp.de [Mark Lehmann]: http://software.schmorp.de
[Joachim Nilsson]: http://troglobit.com [Joachim Wiberg]: http://troglobit.com
[Flemming Madsen]: http://www.madsensoft.dk [Flemming Madsen]: http://www.madsensoft.dk
[Dave Zarzycki, Apple]: http://www.youtube.com/watch?v=cD_s6Fjdri8
<!--
-- Local Variables:
-- mode: markdown
-- End:
-->
-5
View File
@@ -1,5 +0,0 @@
LibuEv TODO
===========
* Make port to *BSD kqueue API, http://en.wikipedia.org/wiki/Kqueue
+28 -12
View File
@@ -1,24 +1,40 @@
# Use v2.61 for backwards compat with Ubuntu 12.04 LTS AC_INIT(libuev, 2.4.1, https://github.com/troglobit/libuev/issues)
AC_PREREQ([2.61]) AC_CONFIG_AUX_DIR(aux)
AC_INIT(libuEv, 1.4.0, https://github.com/troglobit/libuev/issues, libuev) AM_INIT_AUTOMAKE([1.11 foreign dist-xz])
AM_INIT_AUTOMAKE([1.11 foreign no-dist-gzip dist-xz])
AM_SILENT_RULES([yes]) AM_SILENT_RULES([yes])
AC_CONFIG_SRCDIR(uev.c) AC_CONFIG_SRCDIR(src/uev.c)
AM_CONFIG_HEADER(config.h) AC_CONFIG_HEADERS(config.h)
AC_CONFIG_FILES([Makefile libuev.pc examples/Makefile]) AC_CONFIG_FILES([Makefile doc/Makefile doc/Doxyfile examples/Makefile
src/libuev.pc src/Makefile test/Makefile])
AC_CONFIG_MACRO_DIR([m4]) AC_CONFIG_MACRO_DIR([m4])
AC_PROG_CC AC_PROG_CC
AM_PROG_AR AC_PROG_INSTALL
m4_ifdef([AM_PROG_AR], [AM_PROG_AR])
LT_INIT LT_INIT
# Optional features
AC_ARG_ENABLE([examples], AC_ARG_ENABLE([examples],
[AS_HELP_STRING([--enable-examples], [build examples])], [AC_HELP_STRING([--enable-examples], [Build libuEv examples/ directory])],
[enable_examples=yes], []) [], [enable_examples=no])
AM_CONDITIONAL([ENABLE_EXAMPLES], [test "$enable_examples" = yes]) AM_CONDITIONAL([ENABLE_EXAMPLES], [test "$enable_examples" = yes])
AC_HEADER_STDC # Check for Doxygen and enable its features.
AC_C_CONST # For details, see m4/ax_prog_doxygen.m4 and
# http://www.bioinf.uni-freiburg.de/~mmann/HowTo/automake.html#doxygenSupport
DX_DOXYGEN_FEATURE(ON)
DX_DOT_FEATURE(OFF)
DX_CHI_FEATURE(OFF)
DX_RTF_FEATURE(OFF)
DX_XML_FEATURE(OFF)
DX_PDF_FEATURE(OFF)
DX_PS_FEATURE(OFF)
DX_CHM_FEATURE(OFF)
DX_HTML_FEATURE(ON)
DX_MAN_FEATURE(OFF)
DX_INIT_DOXYGEN(${PACKAGE_NAME}, [${top_builddir}/doc/Doxyfile], [${top_builddir}/doc])
AM_CONDITIONAL(ENABLE_DOXYGEN,[test "x${DX_FLAG_doc}" = x1])
AM_CONDITIONAL(ENABLE_HTML,[test "x${DX_FLAG_html}" = x1])
AC_OUTPUT AC_OUTPUT
+8
View File
@@ -0,0 +1,8 @@
tmp/*
libuev/*
libuev*
autoreconf*
debhelper*
files
!*.dirs
!*.install
+14
View File
@@ -0,0 +1,14 @@
libuEv for Debian
-----------------
This is the upstream pre-packaged version of libuEv. It consists of two
.deb packages: one with only the .so library and one -dev package with
headers and the .a library for static linking. It builds on any Debian
based operating system, e.g. Debian, Ubuntu, Linux Mint, etc.
Recommended reading is the upstream README and API docs.
less /usr/share/doc/libuev-dev/README.md
less /usr/share/doc/libuev-dev/API.md
-- Joachim Nilsson <troglobit@gmail.com> Sat, 6 Apr 13:18, 2019
+108
View File
@@ -0,0 +1,108 @@
libuev (2.4.0) stable; urgency=medium
* Add 'struct signalfd_siginfo' to uev_t, valid for signal watchers
* Updated libuev.pc to include GLIBC 2.32 CPPFLAGS for 64-bit time_t
* ABI bump, 2.2.0 -> 3.0.0
-- Joachim Wiberg <troglobit@gmail.com> Sun, 03 Oct 2021 08:28:01 +0200
libuev (2.3.2) stable; urgency=low
* Copyright updates, including LICENSE file, year + author last name
* Debian packaging fixes, including a .symbols file
-- Joachim Wiberg <troglobit@gmail.com> Fri, 12 Feb 2021 09:36:39 +0100
libuev (2.3.1) stable; urgency=high
* Step library name to match SONAME, found by lintian
* Update Build-Depends to debhelper >= 10, drop other deps
-- Joachim Nilsson <troglobit@gmail.com> Sat, 22 Feb 2020 15:50:06 +0100
libuev (2.3.0) unstable; urgency=medium
* Support for Linux eventfd, uev_event_*(), see API.md for details.
-- Joachim Nilsson <troglobit@gmail.com> Thu, 06 Apr 2019 13:09:31 +0200
libuev (2.2.0) unstable; urgency=medium
* Replaced BSD queue.h with own linked list implementation. This means
applications relying on any of the queue.h APIs now need to provide
their own version, or use the system sys/queue.h
-- Joachim Nilsson <troglobit@gmail.com> Thu, 04 Oct 2018 21:03:48 +0200
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
* Support for 64 bit time_t on 32 bit GLIBC systems
-- Joachim Nilsson <troglobit@gmail.com> Mon, 18 Sep 2017 07:49:23 +0200
libuev (1.5.2-2) unstable; urgency=low
* Minor packaging fixes.
-- Joachim Nilsson <troglobit@gmail.com> Sun, 12 Mar 2017 17:48:00 +0100
libuev (1.5.2-1) unstable; urgency=low
* Initial release.
-- Joachim Nilsson <troglobit@gmail.com> Mon, 28 Nov 2016 22:53:35 +0100
+1
View File
@@ -0,0 +1 @@
config.log
+1
View File
@@ -0,0 +1 @@
10
+41
View File
@@ -0,0 +1,41 @@
Source: libuev
Section: libs
Priority: optional
Maintainer: Joachim Wiberg <troglobit@gmail.com>
Build-Depends: debhelper (>= 10)
Build-Depends-Indep: doxygen
Standards-Version: 4.3.0
Homepage: https://github.com/troglobit/libuev/
Vcs-Browser: https://github.com/troglobit/libuev/
Vcs-Git: https://github.com/troglobit/libuev.git
Package: libuev-dev
Priority: optional
Section: libdevel
Architecture: any
Depends: ${misc:Depends}, libuev3 (= ${binary:Version})
Description: static library, header files, and docs for libuev
Static library, header files, and documentation for libuEv
.
libuEv is a small event loop that wraps the Linux epoll() family of APIs.
It is similar to the more established libevent, libev and the venerable
Xt(3) event loop. The u (micro) in the name refers to both its limited
feature set and the small size impact of the library.
.
Experienced developers may appreciate libuEv is built on top of modern
Linux APIs like epoll, eventfd, timerf, and signalfd.
Package: libuev3
Replaces: libuev, libuev2
Conflicts: libuev, libuev2
Provides: libuev, libuev2
Architecture: any
Depends: ${misc:Depends}, ${shlibs:Depends}
Description: Lightweight event loop library for Linux
libuEv is a small event loop that wraps the Linux epoll() family of APIs.
It is similar to the more established libevent, libev and the venerable
Xt(3) event loop. The u (micro) in the name refers to both its limited
feature set and the small size impact of the library.
.
Experienced developers may appreciate libuEv is built on top of modern
Linux APIs like epoll, eventfd, timerfd, and signalfd.
+35
View File
@@ -0,0 +1,35 @@
Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
Upstream-Name: libuEv
Upstream-Contact: troglobit@gmail.com
Source: https.//github.com/troglobit/libuev/
Comment: Debianized by upstream on Mon, Nov 28 2016 23:23:17 +0100
Files: *
Copyright: 2012 Flemming Madsen <flemming.madsen@madsensoft.dk>
2013-2021 Joachim Wiberg <troglobit@gmail.com>
License: MIT
Files: debian/*
Copyright: 2016-2021 Joachim Wiberg <troglobit@gmail.com>
License: MIT
Copyright (c) 2012 Flemming Madsen <flemming!madsen()madsensoft!dk>
Copyright (c) 2013-2024 Joachim Wiberg <troglobit()gmail!com>
.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
.
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
Vendored
+2
View File
@@ -0,0 +1,2 @@
doc/API.md
README.md
+2
View File
@@ -0,0 +1,2 @@
usr/lib
usr/include
+4
View File
@@ -0,0 +1,4 @@
usr/include/uev/*.h
usr/lib/*/libuev.a
usr/lib/*/libuev.so
usr/lib/*/pkgconfig/lib*.pc
+2
View File
@@ -0,0 +1,2 @@
usr/lib
usr/share
+1
View File
@@ -0,0 +1 @@
usr/lib/*/lib*.so.*
+30
View File
@@ -0,0 +1,30 @@
libuev.so.3 libuev3 #MINVER#
* Build-Depends-Package: libuev-dev
_uev_watcher_active@Base 2.3.0
_uev_watcher_init@Base 2.3.0
_uev_watcher_rearm@Base 2.3.0
_uev_watcher_start@Base 2.3.0
_uev_watcher_stop@Base 2.3.0
uev_cron_init@Base 2.3.0
uev_cron_set@Base 2.3.0
uev_cron_start@Base 2.3.0
uev_cron_stop@Base 2.3.0
uev_event_init@Base 2.3.0
uev_event_post@Base 2.3.0
uev_event_stop@Base 2.3.0
uev_exit@Base 2.3.0
uev_init1@Base 2.3.0
uev_init@Base 2.3.0
uev_io_init@Base 2.3.0
uev_io_set@Base 2.3.0
uev_io_start@Base 2.3.0
uev_io_stop@Base 2.3.0
uev_run@Base 2.3.0
uev_signal_init@Base 2.3.0
uev_signal_set@Base 2.3.0
uev_signal_start@Base 2.3.0
uev_signal_stop@Base 2.3.0
uev_timer_init@Base 2.3.0
uev_timer_set@Base 2.3.0
uev_timer_start@Base 2.3.0
uev_timer_stop@Base 2.3.0
Vendored Executable
+17
View File
@@ -0,0 +1,17 @@
#!/usr/bin/make -f
# Uncomment this to turn on verbose mode.
#export DH_VERBOSE=1
export DEB_BUILD_MAINT_OPTIONS = hardening=+all
%:
dh $@ --with autoreconf
override_dh_compress:
dh_compress -A -X.md
override_dh_installchangelogs:
dh_installchangelogs ChangeLog.md
override_dh_auto_install:
dh_auto_install
find debian -name LICENSE -delete
+1
View File
@@ -0,0 +1 @@
3.0 (native)
+3
View File
@@ -0,0 +1,3 @@
html/*
libuev.tag
Doxyfile
+364
View File
@@ -0,0 +1,364 @@
API Documentation
=================
* [Introduction](#introduction)
* [Overview](#overview)
* [Create an Event Context](#create-an-event-context)
* [Register an Event Watcher](#register-an-event-watcher)
* [Start Event Loop](#start-event-loop)
* [Summary](#summary)
* [Using -luev](#using--luev)
* [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 (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
the wall clock changes, either via NTP or user input.
**NOTE:** On some systems, embedded in particular, `time_t` is a 32-bit
integer that wraps around in the year 2038. A [GLIBC workaround][]
(`-D_TIME_BITS=64`) protects those systems, but users of other C
libraries have no known workarounds. It is strongly recommended to
use relative timers as often as possible.
Overview
--------
```C
/*
* Callback example, arg comes from the watcher's *_init() function,
* 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);
/* Event loop: Notice the use of flags! */
int uev_init (uev_ctx_t *ctx);
int uev_init1 (uev_ctx_t *ctx, int maxevents);
int uev_exit (uev_ctx_t *ctx);
int uev_run (uev_ctx_t *ctx, int flags); /* UEV_NONE, UEV_ONCE, and/or UEV_NONBLOCK */
/* I/O watcher: fd *MUST* be non-blocking!
* events combination of the main flags: UEV_READ, UEV_WRITE,
* UEV_EDGE, UEV_ONESHOT
*/
int uev_io_init (uev_ctx_t *ctx, uev_t *w, uev_cb_t *cb, void *arg, int fd, int events);
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 (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 */
int uev_timer_stop (uev_t *w); /* Stop a timer */
/* Cron watcher: schedule an absolute timer, when and period in time_t seconds */
int uev_cron_init (uev_ctx_t *ctx, uev_t *w, uev_cb_t *cb, void *arg, time_t when, time_t period);
int uev_cron_set (uev_t *w, int when, time_t period); /* Change when or period */
int uev_cron_start (uev_t *w); /* Restart a stopped cron */
int uev_cron_stop (uev_t *w); /* Stop a cron */
/* Signal watcher: signo is the signal to wait for, e.g., SIGTERM */
int uev_signal_init (uev_ctx_t *ctx, uev_t *w, uev_cb_t *cb, void *arg, int signo);
int uev_signal_set (uev_t *w, int signo); /* Change signal to wait for */
int uev_signal_start(uev_t *w); /* Restart a stopped signal watcher */
int uev_signal_stop (uev_t *w); /* Stop signal watcher */
/* Generic event watcher, post events for later processing, or from forked child */
int uev_event_init (uev_ctx_t *ctx, uev_t *w, uev_cb_t *cb, void *arg);
int uev_event_post (uev_t *w);
int uev_event_stop (uev_t *w);
```
### Create an Event Context
To monitor events the developer first creates an *event context*, this
is achieved by calling `uev_init()` with a pointer to a (thread) local
`uev_ctx_t` variable.
```C
uev_ctx_t ctx;
uev_init(&ctx);
```
### Register an Event Watcher
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 ...");
else
printf("Got signal (signo %d) from PID %d\n",
w->siginfo.ssi_signo, w->siginfo.ssi_pid);
/* Graceful exit, with optional cleanup ... */
uev_exit(w->ctx);
}
int main(void)
{
uev_t sigterm_watcher;
.
.
uev_signal_init(&ctx, &sigterm_watcher, cleanup_exit, NULL, SIGTERM);
.
.
}
```
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
When all watchers are registered, call the *event loop* with `uev_run()`
and the argument to the event context. The `flags` parameter can be
used to integrate [libuEv][] into another event loop.
In this example we set `flags` to none:
```C
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.
### Summary
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. 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
opened in blocking mode. Be careful out there!
**Note 2:** When closing a descriptor or socket, make sure to first stop
your watcher, if possible. This will help prevent any nasty side
effects on your program.
**Note 3:** a certain amount of care is needed when dealing with APIs
that employ signalfd. If your application use `system()` you replace
that with `fork()`, and then in the child, unblock all signals blocked
by your parent process, before you run `exec()`. This because Linux
does not unblock signals for your children, and neither does most
(all?) C-libraries. See the [finit][6] project's implementation of
`run()` for an example of this. For more details on this issue, see
[this article][4] at [lwn.net](http://lwn.net).
Using -luev
-----------
libuEv is by default installed as a library with a few header files, you
should only ever need to include one:
```C
#include <uev/uev.h>
```
The output from the `pkg-config` tool holds no surprises:
```sh
$ pkg-config --libs --static --cflags libuev
-I/usr/local/include -L/usr/local/lib -luev
```
The prefix path `/usr/local/` shown here is only the default. Use the
`configure` script to select a different prefix when installing libuEv.
For GNU autotools based projects, use the following in `configure.ac`:
```sh
# Check for required libraries
PKG_CHECK_MODULES([uev], [libuev >= 1.4.0])
```
and in your `Makefile.am`:
```sh
proggy_CFLAGS = $(uev_CFLAGS)
proggy_LDADD = $(uev_LIBS)
```
Joystick Example
----------------
Here follows a very brief example to illustrate how one can use libuEv
to act upon joystick input.
```C
#include <err.h>
#include <errno.h>
#include <stdio.h>
#include <stdint.h>
#include <fcntl.h>
#include <unistd.h>
#include <uev/uev.h>
struct js_event {
uint32_t time; /* event timestamp in milliseconds */
int16_t value; /* value */
uint8_t type; /* event type */
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)
{
ssize_t cnt;
if (UEV_ERROR == events) {
/* Possibly joystick was unplugged */
warnx("Spurious problem with the joystick watcher, restarting.");
uev_io_start(w);
return;
}
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:
printf("Button %d %s\n", e.number, e.value ? "pressed" : "released");
break;
case 2:
printf("Joystick axis %d moved, value %d!\n", e.number, e.value);
break;
}
}
int main(void)
{
uev_ctx_t ctx;
uev_t js;
int fd;
fd = open("/dev/input/js0", O_RDONLY, O_NONBLOCK);
if (fd < 0)
errx(errno, "Cannot find a joystick attached.");
uev_init(&ctx);
uev_io_init(&ctx, &js, joystick_cb, NULL, fd, UEV_READ);
puts("Starting, press Ctrl-C to exit.");
return uev_run(&ctx, 0);
}
```
To build the example, follow installation instructions below, then save
the code as `joystick.c` and call GCC
```sh
$ gcc `pkg-config --libs --static --cflags libuev` -o joystick joystick.c
```
Alternatively, call the `Makefile` with <kbd>make joystick</kbd> from
the unpacked [libuEv][] distribution.
More complete and relevant example uses of [libuEv][] is the FTP/TFTP
server [uftpd][5], and the Linux `/sbin/init` replacement [finit][6].
Both successfully employ [libuEv][].
Also see the `bench.c` program (<kbd>make bench</kbd> from within the
library) for [reference benchmarks][7] against [libevent][1] and
[libev][2].
[1]: http://libevent.org
[2]: http://software.schmorp.de/pkg/libev.html
[4]: http://lwn.net/Articles/415684/
[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
[GLIBC workaround]: https://sourceware.org/glibc/wiki/Y2038ProofnessDesign
[Dave Zarzycki, Apple]: http://www.youtube.com/watch?v=cD_s6Fjdri8
+2579
View File
File diff suppressed because it is too large. Load diff
+106
View File
@@ -0,0 +1,106 @@
Maintenance and Release Checklist
=================================
Maintenance
-----------
* Encourage contributors to write tests, in particular for new features
* Run tests regularly, use GitHub Actions to do this automatically
* Leverage GitHub issues for milestone planning
* Reference issues from GitHub pull requests to alert issue subscribers
* Bump library ABI version just before release!
Release Checklist
-----------------
* Update ChangeLog, follow http://keepachangelog.com/ loosely
- Inform users in a plain language of changes and bug fixes
- Do *not* copy-paste GIT commit logs!
- Order entries according to importance, most relevant first
* Run unit tests: `make check`
* Make at least one `-rcN` release and test it in an actual real project
* **REMEMBER:** bump ABI version according to below rules
* Tag
* Push last commit(s) *and* tags to GitHub
* Make release
make distclean
./autogen.sh
./configure
make release
* Create new release in GitHub releases page
* Copy and paste ChangeLog entry, check any stale links!
* Upload release tarball and MD5 files
Library Versioning
------------------
libuEv relies on GNU Libtool for building the library. For users of the
library it is important to maintain a clear ABI versioning scheme. This
is not the same as the libuEv version, but rather its "compatibility
level".
The libuEv ABI version is specified in `src/Makefile.am`:
libuev_la_LDFLAGS = -version-info 0:0:0
\ \ `-- age
\ `--- revision
`---- current
It must be updated according to the [GNU Libtool recommendations][1]:
1. Start with version information of `0:0:0` for each libtool library.
2. Update the version information only immediately before a public
release of your software. More frequent updates are unnecessary, and
only guarantee that the current interface number gets larger faster.
3. If the library *source code has changed at all* since the last update,
then increment revision (`c:r:a` becomes `c:r+1:a`).
4. If any *interfaces have been added, removed, or changed* since the
last update, increment current, and set revision to 0.
5. If any *interfaces have been added* since the last public release,
then increment age.
6. If any *interfaces have been removed or changed* since the last
public release, then set age to 0.
The libtool ABI versioning logic is very confusing but works if you just
disable your brain and follow the rules, one by one.
**Example #1:** a new function has been added, none of the existing ones
have changed. The initial version is 1:0:0, we follow the rules above to
the letter: increase revision, increase current and set revision to zero,
and finally increase age. This, rather confusingly, gives us 2:0:1 which
libtool then translates to `libuev.so.1.1.0`.
**Example #2:** some existing functions are changed, they now return an
`int` instead of `void`. The initial version is 0:0:0, and we follow the
rules again: increment revision, increment current and set revision to
zero, set age to zero. This gives us 1:0:0, which is then translated to
`libuev.so.1.0.0`.
### Note
Usually, non-developers have no interest in running development versions
(releases are frequent enough), and developers are expected to know how
to juggle versions. In such an ideal world, it is good enough to bump
the library version just prior to a release, point 2.
However, if releases are few and far between, distributors may start to
use snapshots. When a distributor uses a snapshot, the distributor has
to handle the library version manually. Things can get ugly when the
distributor has released an intermediate version with a bumped library
version, and when the official release is bumped to that version, the
distributor will then have to bump the library version for the official
release, and it can be confusing if someone reports bugs on versions
that you didn't even know existed.
The problem with bumping the version with every change is that if your
interface is not finished, the version number might run away, and it
looks pretty bad if a library is at version 262. It kind of tells the
user that the library interface is volatile, which is not good for
business.
[1]: https://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html
+22
View File
@@ -0,0 +1,22 @@
dist_doc_DATA = API.md
EXTRA_DIST = Doxyfile.in
DISTCLEANFILES = libuev.tag
if ENABLE_HTML
pkghtmldir = $(docdir)/html
pkghtml_DATA = html/*
#
# Doxygen rules from m4/ax_prog_doxygen.m4
#
@DX_RULES@
$(pkghtml_DATA): doxygen-doc
all-local: doc
clean-local:
-rm -rf html
doc: doxygen-doc
endif
+11
View File
@@ -0,0 +1,11 @@
LibuEv TODO
===========
* Add standard UNIX backend with `select()` and `timer_create()`
See SMCRoute and toolbox for examples
* Port to *BSD kqueue API, <http://en.wikipedia.org/wiki/Kqueue>
Also in UNIX Network Progamming, by W. Richard Stevens 3rd ed.
More porting ideas and help, see the following GitHub issue;
<https://github.com/troglobit/libuev/issues/20>
* Restore Lua bindings now that libuEv itself has stabilized
+8
View File
@@ -0,0 +1,8 @@
cronrun
ctrl
forky
hej.txt
joystick
redirect
signal
test
+3 -5
View File
@@ -1,5 +1,3 @@
noinst_PROGRAMS = signal test joystick noinst_PROGRAMS = ctrl forky joystick redirect
AM_CPPFLAGS = -I$(top_srcdir) AM_CPPFLAGS = -I$(top_srcdir)/src
AM_LDFLAGS = -L$(top_srcdir) LDADD = $(top_srcdir)/src/libuev.la
LIBS = $(LTLIBINTL)
LDADD = $(top_srcdir)/libuev.la
+74
View File
@@ -0,0 +1,74 @@
/* Example of how to handle signal, in this case Ctrl-C
*
* A common problem for users of libuEV is how to combine it with the
* traditional aspects of UNIX. Since libuEV is just a wrapper for
* signalfd() and epoll(), in this case, it can be worth a dedicated
* example. After all, command line use with Ctrl-C is one of the most
* common use-cases.
*/
#include <stdio.h>
#include <signal.h>
#include "src/uev.h"
void timeout(uev_t *w, void *arg, int events)
{
(void)arg;
if (UEV_ERROR == events)
puts("Ignoring timer watcher error ...");
puts("Zero Wing was the pinnacle of gaming https://en.wikipedia.org/wiki/Zero_Wing");
}
void teaser(uev_t *w, void *arg, int events)
{
(void)arg;
if (UEV_ERROR == events)
puts("Ignoring SIGINT watcher error ...");
puts("\nCaught SIGINT ...");
puts("Sorry, you actually need to press Ctrl-\\ to exit.");
}
void cleanup(uev_t *w, void *arg, int events)
{
(void)arg;
if (UEV_ERROR == events)
puts("Ignoring signal watcher error ...");
/* Graceful exit, with optional cleanup ... */
puts("\nCaught SIGQUIT, exiting.");
uev_exit(w->ctx);
}
int main(int argc, char **argv)
{
uev_ctx_t ctx;
uev_t timerw;
uev_t sig1w;
uev_t sig2w;
uev_init(&ctx);
/* example worker, a timer callback */
uev_timer_init(&ctx, &timerw, timeout, NULL, 100, 2000);
/* the owls are not what they seem ... */
uev_signal_init(&ctx, &sig1w, teaser, NULL, SIGINT);
uev_signal_init(&ctx, &sig2w, cleanup, NULL, SIGQUIT);
puts("Starting, press Ctrl-C to exit.");
return uev_run(&ctx, 0);
}
/**
* Local Variables:
* compile-command: "make ctrl; ./ctrl"
* c-file-style: "linux"
* End:
*/
+89
View File
@@ -0,0 +1,89 @@
/* Example with fork and signals, in this case Ctrl-C, from terminal
*
* A common problem for users of libuEV is how to combine it with the
* traditional aspects of UNIX. Since libuEV is just a wrapper for
* signalfd() and epoll(), in this case, it can be worth a dedicated
* example. After all, command line use with Ctrl-C is one of the most
* common use-cases.
*/
#include <stdio.h>
#include <signal.h>
#include <sys/types.h>
#include <unistd.h>
#include "src/uev.h"
void timeout(uev_t *w, void *arg, int events)
{
char *id = (char *)arg;
if (UEV_ERROR == events)
puts("Ignoring timer watcher error ...");
printf("I am the %s robot\n", id);
}
void teaser(uev_t *w, void *arg, int events)
{
(void)arg;
if (UEV_ERROR == events)
puts("Ignoring SIGINT watcher error ...");
puts("\nWe are here to protect you ...");
puts("Sorry, you actually need to press Ctrl-\\ to exit.");
}
void cleanup(uev_t *w, void *arg, int events)
{
(void)arg;
if (UEV_ERROR == events)
puts("Ignoring signal watcher error ...");
/* Graceful exit, with optional cleanup ... */
puts("\nAgainst the terrible secret of space.");
uev_exit(w->ctx);
}
int main(int argc, char **argv)
{
uev_ctx_t ctx;
uev_t timerw;
uev_t sig1w;
uev_t sig2w;
char *robot;
pid_t pid;
pid = fork();
if (pid == -1)
return 1;
if (pid > 0)
robot = "Shover";
else
robot = "Pusher";
setsid(); /* puts child in new process group */
uev_init(&ctx);
/* example worker, a timer callback */
uev_timer_init(&ctx, &timerw, timeout, robot, 100, 2000);
/* the owls are not what they seem ... */
uev_signal_init(&ctx, &sig1w, teaser, NULL, SIGINT);
uev_signal_init(&ctx, &sig2w, cleanup, NULL, SIGQUIT);
puts("Starting, press Ctrl-C to exit.");
return uev_run(&ctx, 0);
}
/**
* Local Variables:
* compile-command: "make forky; ./forky"
* c-file-style: "linux"
* End:
*/
+26 -8
View File
@@ -1,6 +1,6 @@
/* Simple example of how to use libuEv with Linux joystick API /* Simple example of how to use libuEv with Linux joystick API
* *
* Copyright (c) 2014-2016 Joachim Nilsson <troglobit()gmail!com> * Copyright (c) 2014-2024 Joachim Wiberg <troglobit()gmail!com>
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
@@ -37,10 +37,29 @@ struct js_event {
uint8_t number; /* axis/button number */ uint8_t number; /* axis/button number */
} e; } e;
/*
* Always check for UEV_ERROR in watcher callback!
* Possibly joystick was unplugged
*/
static void joystick_cb(uev_t *w, void *arg, int events) static void joystick_cb(uev_t *w, void *arg, int events)
{ {
if (read(w->fd, &e, sizeof(e)) < 0) ssize_t len;
errx(errno, "Failed reading joystick event");
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) { switch (e.type) {
case 1: case 1:
@@ -55,16 +74,16 @@ static void joystick_cb(uev_t *w, void *arg, int events)
int main(void) int main(void)
{ {
int fd;
uev_t js1_watcher;
uev_ctx_t ctx; uev_ctx_t ctx;
uev_t js1;
int fd;
fd = open("/dev/input/js1", O_RDONLY, O_NONBLOCK); fd = open("/dev/input/js0", O_RDONLY, O_NONBLOCK);
if (fd < 0) if (fd < 0)
errx(errno, "Cannot find a joystick attached."); errx(errno, "Cannot find a joystick attached.");
uev_init(&ctx); uev_init(&ctx);
uev_io_init(&ctx, &js1_watcher, joystick_cb, NULL, fd, UEV_READ); uev_io_init(&ctx, &js1, joystick_cb, NULL, fd, UEV_READ);
puts("Starting, press Ctrl-C to exit."); puts("Starting, press Ctrl-C to exit.");
@@ -74,7 +93,6 @@ int main(void)
/** /**
* Local Variables: * Local Variables:
* compile-command: "make joystick" * compile-command: "make joystick"
* version-control: t
* indent-tabs-mode: t * indent-tabs-mode: t
* c-file-style: "linux" * c-file-style: "linux"
* End: * End:
+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)
{
uev_ctx_t ctx;
uev_t watcher;
int ret;
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:
*/
+5 -1
View File
@@ -1 +1,5 @@
*.m4 libtool.m4
ltoptions.m4
ltsugar.m4
ltversion.m4
lt~obsolete.m4
+585
View File
@@ -0,0 +1,585 @@
# ===========================================================================
# http://www.gnu.org/software/autoconf-archive/ax_prog_doxygen.html
# ===========================================================================
#
# SYNOPSIS
#
# DX_INIT_DOXYGEN(PROJECT-NAME, [DOXYFILE-PATH], [OUTPUT-DIR], ...)
# DX_DOXYGEN_FEATURE(ON|OFF)
# DX_DOT_FEATURE(ON|OFF)
# DX_HTML_FEATURE(ON|OFF)
# DX_CHM_FEATURE(ON|OFF)
# DX_CHI_FEATURE(ON|OFF)
# DX_MAN_FEATURE(ON|OFF)
# DX_RTF_FEATURE(ON|OFF)
# DX_XML_FEATURE(ON|OFF)
# DX_PDF_FEATURE(ON|OFF)
# DX_PS_FEATURE(ON|OFF)
#
# DESCRIPTION
#
# The DX_*_FEATURE macros control the default setting for the given
# Doxygen feature. Supported features are 'DOXYGEN' itself, 'DOT' for
# generating graphics, 'HTML' for plain HTML, 'CHM' for compressed HTML
# help (for MS users), 'CHI' for generating a seperate .chi file by the
# .chm file, and 'MAN', 'RTF', 'XML', 'PDF' and 'PS' for the appropriate
# output formats. The environment variable DOXYGEN_PAPER_SIZE may be
# specified to override the default 'a4wide' paper size.
#
# By default, HTML, PDF and PS documentation is generated as this seems to
# be the most popular and portable combination. MAN pages created by
# Doxygen are usually problematic, though by picking an appropriate subset
# and doing some massaging they might be better than nothing. CHM and RTF
# are specific for MS (note that you can't generate both HTML and CHM at
# the same time). The XML is rather useless unless you apply specialized
# post-processing to it.
#
# The macros mainly control the default state of the feature. The use can
# override the default by specifying --enable or --disable. The macros
# ensure that contradictory flags are not given (e.g.,
# --enable-doxygen-html and --enable-doxygen-chm,
# --enable-doxygen-anything with --disable-doxygen, etc.) Finally, each
# feature will be automatically disabled (with a warning) if the required
# programs are missing.
#
# Once all the feature defaults have been specified, call DX_INIT_DOXYGEN
# with the following parameters: a one-word name for the project for use
# as a filename base etc., an optional configuration file name (the
# default is '$(srcdir)/Doxyfile', the same as Doxygen's default), and an
# optional output directory name (the default is 'doxygen-doc'). To run
# doxygen multiple times for different configuration files and output
# directories provide more parameters: the second, forth, sixth, etc
# parameter are configuration file names and the third, fifth, seventh,
# etc parameter are output directories. No checking is done to catch
# duplicates.
#
# Automake Support
#
# The DX_RULES substitution can be used to add all needed rules to the
# Makefile. Note that this is a substitution without being a variable:
# only the @DX_RULES@ syntax will work.
#
# The provided targets are:
#
# doxygen-doc: Generate all doxygen documentation.
#
# doxygen-run: Run doxygen, which will generate some of the
# documentation (HTML, CHM, CHI, MAN, RTF, XML)
# but will not do the post processing required
# for the rest of it (PS, PDF).
#
# doxygen-ps: Generate doxygen PostScript documentation.
#
# doxygen-pdf: Generate doxygen PDF documentation.
#
# Note that by default these are not integrated into the automake targets.
# If doxygen is used to generate man pages, you can achieve this
# integration by setting man3_MANS to the list of man pages generated and
# then adding the dependency:
#
# $(man3_MANS): doxygen-doc
#
# This will cause make to run doxygen and generate all the documentation.
#
# The following variable is intended for use in Makefile.am:
#
# DX_CLEANFILES = everything to clean.
#
# Then add this variable to MOSTLYCLEANFILES.
#
# LICENSE
#
# Copyright (c) 2009 Oren Ben-Kiki <oren@ben-kiki.org>
# Copyright (c) 2015 Olaf Mandel <olaf@mandel.name>
#
# Copying and distribution of this file, with or without modification, are
# permitted in any medium without royalty provided the copyright notice
# and this notice are preserved. This file is offered as-is, without any
# warranty.
#serial 20
## ----------##
## Defaults. ##
## ----------##
DX_ENV=""
AC_DEFUN([DX_FEATURE_doc], ON)
AC_DEFUN([DX_FEATURE_dot], OFF)
AC_DEFUN([DX_FEATURE_man], OFF)
AC_DEFUN([DX_FEATURE_html], ON)
AC_DEFUN([DX_FEATURE_chm], OFF)
AC_DEFUN([DX_FEATURE_chi], OFF)
AC_DEFUN([DX_FEATURE_rtf], OFF)
AC_DEFUN([DX_FEATURE_xml], OFF)
AC_DEFUN([DX_FEATURE_pdf], ON)
AC_DEFUN([DX_FEATURE_ps], ON)
## --------------- ##
## Private macros. ##
## --------------- ##
# DX_ENV_APPEND(VARIABLE, VALUE)
# ------------------------------
# Append VARIABLE="VALUE" to DX_ENV for invoking doxygen and add it
# as a substitution (but not a Makefile variable). The substitution
# is skipped if the variable name is VERSION.
AC_DEFUN([DX_ENV_APPEND],
[AC_SUBST([DX_ENV], ["$DX_ENV $1='$2'"])dnl
m4_if([$1], [VERSION], [], [AC_SUBST([$1], [$2])dnl
AM_SUBST_NOTMAKE([$1])])dnl
])
# DX_DIRNAME_EXPR
# ---------------
# Expand into a shell expression prints the directory part of a path.
AC_DEFUN([DX_DIRNAME_EXPR],
[[expr ".$1" : '\(\.\)[^/]*$' \| "x$1" : 'x\(.*\)/[^/]*$']])
# DX_IF_FEATURE(FEATURE, IF-ON, IF-OFF)
# -------------------------------------
# Expands according to the M4 (static) status of the feature.
AC_DEFUN([DX_IF_FEATURE], [ifelse(DX_FEATURE_$1, ON, [$2], [$3])])
# DX_REQUIRE_PROG(VARIABLE, PROGRAM)
# ----------------------------------
# Require the specified program to be found for the DX_CURRENT_FEATURE to work.
AC_DEFUN([DX_REQUIRE_PROG], [
AC_PATH_TOOL([$1], [$2])
if test "$DX_FLAG_[]DX_CURRENT_FEATURE$$1" = 1; then
AC_MSG_WARN([$2 not found - will not DX_CURRENT_DESCRIPTION])
AC_SUBST(DX_FLAG_[]DX_CURRENT_FEATURE, 0)
fi
])
# DX_TEST_FEATURE(FEATURE)
# ------------------------
# Expand to a shell expression testing whether the feature is active.
AC_DEFUN([DX_TEST_FEATURE], [test "$DX_FLAG_$1" = 1])
# DX_CHECK_DEPEND(REQUIRED_FEATURE, REQUIRED_STATE)
# -------------------------------------------------
# Verify that a required features has the right state before trying to turn on
# the DX_CURRENT_FEATURE.
AC_DEFUN([DX_CHECK_DEPEND], [
test "$DX_FLAG_$1" = "$2" \
|| AC_MSG_ERROR([doxygen-DX_CURRENT_FEATURE ifelse([$2], 1,
requires, contradicts) doxygen-DX_CURRENT_FEATURE])
])
# DX_CLEAR_DEPEND(FEATURE, REQUIRED_FEATURE, REQUIRED_STATE)
# ----------------------------------------------------------
# Turn off the DX_CURRENT_FEATURE if the required feature is off.
AC_DEFUN([DX_CLEAR_DEPEND], [
test "$DX_FLAG_$1" = "$2" || AC_SUBST(DX_FLAG_[]DX_CURRENT_FEATURE, 0)
])
# DX_FEATURE_ARG(FEATURE, DESCRIPTION,
# CHECK_DEPEND, CLEAR_DEPEND,
# REQUIRE, DO-IF-ON, DO-IF-OFF)
# --------------------------------------------
# Parse the command-line option controlling a feature. CHECK_DEPEND is called
# if the user explicitly turns the feature on (and invokes DX_CHECK_DEPEND),
# otherwise CLEAR_DEPEND is called to turn off the default state if a required
# feature is disabled (using DX_CLEAR_DEPEND). REQUIRE performs additional
# requirement tests (DX_REQUIRE_PROG). Finally, an automake flag is set and
# DO-IF-ON or DO-IF-OFF are called according to the final state of the feature.
AC_DEFUN([DX_ARG_ABLE], [
AC_DEFUN([DX_CURRENT_FEATURE], [$1])
AC_DEFUN([DX_CURRENT_DESCRIPTION], [$2])
AC_ARG_ENABLE(doxygen-$1,
[AS_HELP_STRING(DX_IF_FEATURE([$1], [--disable-doxygen-$1],
[--enable-doxygen-$1]),
DX_IF_FEATURE([$1], [don't $2], [$2]))],
[
case "$enableval" in
#(
y|Y|yes|Yes|YES)
AC_SUBST([DX_FLAG_$1], 1)
$3
;; #(
n|N|no|No|NO)
AC_SUBST([DX_FLAG_$1], 0)
;; #(
*)
AC_MSG_ERROR([invalid value '$enableval' given to doxygen-$1])
;;
esac
], [
AC_SUBST([DX_FLAG_$1], [DX_IF_FEATURE([$1], 1, 0)])
$4
])
if DX_TEST_FEATURE([$1]); then
$5
:
fi
if DX_TEST_FEATURE([$1]); then
$6
:
else
$7
:
fi
])
## -------------- ##
## Public macros. ##
## -------------- ##
# DX_XXX_FEATURE(DEFAULT_STATE)
# -----------------------------
AC_DEFUN([DX_DOXYGEN_FEATURE], [AC_DEFUN([DX_FEATURE_doc], [$1])])
AC_DEFUN([DX_DOT_FEATURE], [AC_DEFUN([DX_FEATURE_dot], [$1])])
AC_DEFUN([DX_MAN_FEATURE], [AC_DEFUN([DX_FEATURE_man], [$1])])
AC_DEFUN([DX_HTML_FEATURE], [AC_DEFUN([DX_FEATURE_html], [$1])])
AC_DEFUN([DX_CHM_FEATURE], [AC_DEFUN([DX_FEATURE_chm], [$1])])
AC_DEFUN([DX_CHI_FEATURE], [AC_DEFUN([DX_FEATURE_chi], [$1])])
AC_DEFUN([DX_RTF_FEATURE], [AC_DEFUN([DX_FEATURE_rtf], [$1])])
AC_DEFUN([DX_XML_FEATURE], [AC_DEFUN([DX_FEATURE_xml], [$1])])
AC_DEFUN([DX_XML_FEATURE], [AC_DEFUN([DX_FEATURE_xml], [$1])])
AC_DEFUN([DX_PDF_FEATURE], [AC_DEFUN([DX_FEATURE_pdf], [$1])])
AC_DEFUN([DX_PS_FEATURE], [AC_DEFUN([DX_FEATURE_ps], [$1])])
# DX_INIT_DOXYGEN(PROJECT, [CONFIG-FILE], [OUTPUT-DOC-DIR], ...)
# --------------------------------------------------------------
# PROJECT also serves as the base name for the documentation files.
# The default CONFIG-FILE is "$(srcdir)/Doxyfile" and OUTPUT-DOC-DIR is
# "doxygen-doc".
# More arguments are interpreted as interleaved CONFIG-FILE and
# OUTPUT-DOC-DIR values.
AC_DEFUN([DX_INIT_DOXYGEN], [
# Files:
AC_SUBST([DX_PROJECT], [$1])
AC_SUBST([DX_CONFIG], ['ifelse([$2], [], [$(srcdir)/Doxyfile], [$2])'])
AC_SUBST([DX_DOCDIR], ['ifelse([$3], [], [doxygen-doc], [$3])'])
m4_if(m4_eval(3 < m4_count($@)), 1, [m4_for([DX_i], 4, m4_count($@), 2,
[AC_SUBST([DX_CONFIG]m4_eval(DX_i[/2]),
'm4_default_nblank_quoted(m4_argn(DX_i, $@),
[$(srcdir)/Doxyfile])')])])dnl
m4_if(m4_eval(3 < m4_count($@)), 1, [m4_for([DX_i], 5, m4_count($@,), 2,
[AC_SUBST([DX_DOCDIR]m4_eval([(]DX_i[-1)/2]),
'm4_default_nblank_quoted(m4_argn(DX_i, $@),
[doxygen-doc])')])])dnl
m4_define([DX_loop], m4_dquote(m4_if(m4_eval(3 < m4_count($@)), 1,
[m4_for([DX_i], 4, m4_count($@), 2, [, m4_eval(DX_i[/2])])],
[])))dnl
# Environment variables used inside doxygen.cfg:
DX_ENV_APPEND(SRCDIR, $srcdir)
DX_ENV_APPEND(PROJECT, $DX_PROJECT)
DX_ENV_APPEND(VERSION, $PACKAGE_VERSION)
# Doxygen itself:
DX_ARG_ABLE(doc, [generate any doxygen documentation],
[],
[],
[DX_REQUIRE_PROG([DX_DOXYGEN], doxygen)
DX_REQUIRE_PROG([DX_PERL], perl)],
[DX_ENV_APPEND(PERL_PATH, $DX_PERL)])
# Dot for graphics:
DX_ARG_ABLE(dot, [generate graphics for doxygen documentation],
[DX_CHECK_DEPEND(doc, 1)],
[DX_CLEAR_DEPEND(doc, 1)],
[DX_REQUIRE_PROG([DX_DOT], dot)],
[DX_ENV_APPEND(HAVE_DOT, YES)
DX_ENV_APPEND(DOT_PATH, [`DX_DIRNAME_EXPR($DX_DOT)`])],
[DX_ENV_APPEND(HAVE_DOT, NO)])
# Man pages generation:
DX_ARG_ABLE(man, [generate doxygen manual pages],
[DX_CHECK_DEPEND(doc, 1)],
[DX_CLEAR_DEPEND(doc, 1)],
[],
[DX_ENV_APPEND(GENERATE_MAN, YES)],
[DX_ENV_APPEND(GENERATE_MAN, NO)])
# RTF file generation:
DX_ARG_ABLE(rtf, [generate doxygen RTF documentation],
[DX_CHECK_DEPEND(doc, 1)],
[DX_CLEAR_DEPEND(doc, 1)],
[],
[DX_ENV_APPEND(GENERATE_RTF, YES)],
[DX_ENV_APPEND(GENERATE_RTF, NO)])
# XML file generation:
DX_ARG_ABLE(xml, [generate doxygen XML documentation],
[DX_CHECK_DEPEND(doc, 1)],
[DX_CLEAR_DEPEND(doc, 1)],
[],
[DX_ENV_APPEND(GENERATE_XML, YES)],
[DX_ENV_APPEND(GENERATE_XML, NO)])
# (Compressed) HTML help generation:
DX_ARG_ABLE(chm, [generate doxygen compressed HTML help documentation],
[DX_CHECK_DEPEND(doc, 1)],
[DX_CLEAR_DEPEND(doc, 1)],
[DX_REQUIRE_PROG([DX_HHC], hhc)],
[DX_ENV_APPEND(HHC_PATH, $DX_HHC)
DX_ENV_APPEND(GENERATE_HTML, YES)
DX_ENV_APPEND(GENERATE_HTMLHELP, YES)],
[DX_ENV_APPEND(GENERATE_HTMLHELP, NO)])
# Seperate CHI file generation.
DX_ARG_ABLE(chi, [generate doxygen seperate compressed HTML help index file],
[DX_CHECK_DEPEND(chm, 1)],
[DX_CLEAR_DEPEND(chm, 1)],
[],
[DX_ENV_APPEND(GENERATE_CHI, YES)],
[DX_ENV_APPEND(GENERATE_CHI, NO)])
# Plain HTML pages generation:
DX_ARG_ABLE(html, [generate doxygen plain HTML documentation],
[DX_CHECK_DEPEND(doc, 1) DX_CHECK_DEPEND(chm, 0)],
[DX_CLEAR_DEPEND(doc, 1) DX_CLEAR_DEPEND(chm, 0)],
[],
[DX_ENV_APPEND(GENERATE_HTML, YES)],
[DX_TEST_FEATURE(chm) || DX_ENV_APPEND(GENERATE_HTML, NO)])
# PostScript file generation:
DX_ARG_ABLE(ps, [generate doxygen PostScript documentation],
[DX_CHECK_DEPEND(doc, 1)],
[DX_CLEAR_DEPEND(doc, 1)],
[DX_REQUIRE_PROG([DX_LATEX], latex)
DX_REQUIRE_PROG([DX_MAKEINDEX], makeindex)
DX_REQUIRE_PROG([DX_DVIPS], dvips)
DX_REQUIRE_PROG([DX_EGREP], egrep)])
# PDF file generation:
DX_ARG_ABLE(pdf, [generate doxygen PDF documentation],
[DX_CHECK_DEPEND(doc, 1)],
[DX_CLEAR_DEPEND(doc, 1)],
[DX_REQUIRE_PROG([DX_PDFLATEX], pdflatex)
DX_REQUIRE_PROG([DX_MAKEINDEX], makeindex)
DX_REQUIRE_PROG([DX_EGREP], egrep)])
# LaTeX generation for PS and/or PDF:
if DX_TEST_FEATURE(ps) || DX_TEST_FEATURE(pdf); then
DX_ENV_APPEND(GENERATE_LATEX, YES)
else
DX_ENV_APPEND(GENERATE_LATEX, NO)
fi
# Paper size for PS and/or PDF:
AC_ARG_VAR(DOXYGEN_PAPER_SIZE,
[a4wide (default), a4, letter, legal or executive])
case "$DOXYGEN_PAPER_SIZE" in
#(
"")
AC_SUBST(DOXYGEN_PAPER_SIZE, "")
;; #(
a4wide|a4|letter|legal|executive)
DX_ENV_APPEND(PAPER_SIZE, $DOXYGEN_PAPER_SIZE)
;; #(
*)
AC_MSG_ERROR([unknown DOXYGEN_PAPER_SIZE='$DOXYGEN_PAPER_SIZE'])
;;
esac
# Rules:
AS_IF([[test $DX_FLAG_html -eq 1]],
[[DX_SNIPPET_html="## ------------------------------- ##
## Rules specific for HTML output. ##
## ------------------------------- ##
DX_CLEAN_HTML = \$(DX_DOCDIR)/html]dnl
m4_foreach([DX_i], [m4_shift(DX_loop)], [[\\
\$(DX_DOCDIR]DX_i[)/html]])[
"]],
[[DX_SNIPPET_html=""]])
AS_IF([[test $DX_FLAG_chi -eq 1]],
[[DX_SNIPPET_chi="
DX_CLEAN_CHI = \$(DX_DOCDIR)/\$(PACKAGE).chi]dnl
m4_foreach([DX_i], [m4_shift(DX_loop)], [[\\
\$(DX_DOCDIR]DX_i[)/\$(PACKAGE).chi]])["]],
[[DX_SNIPPET_chi=""]])
AS_IF([[test $DX_FLAG_chm -eq 1]],
[[DX_SNIPPET_chm="## ------------------------------ ##
## Rules specific for CHM output. ##
## ------------------------------ ##
DX_CLEAN_CHM = \$(DX_DOCDIR)/chm]dnl
m4_foreach([DX_i], [m4_shift(DX_loop)], [[\\
\$(DX_DOCDIR]DX_i[)/chm]])[\
${DX_SNIPPET_chi}
"]],
[[DX_SNIPPET_chm=""]])
AS_IF([[test $DX_FLAG_man -eq 1]],
[[DX_SNIPPET_man="## ------------------------------ ##
## Rules specific for MAN output. ##
## ------------------------------ ##
DX_CLEAN_MAN = \$(DX_DOCDIR)/man]dnl
m4_foreach([DX_i], [m4_shift(DX_loop)], [[\\
\$(DX_DOCDIR]DX_i[)/man]])[
"]],
[[DX_SNIPPET_man=""]])
AS_IF([[test $DX_FLAG_rtf -eq 1]],
[[DX_SNIPPET_rtf="## ------------------------------ ##
## Rules specific for RTF output. ##
## ------------------------------ ##
DX_CLEAN_RTF = \$(DX_DOCDIR)/rtf]dnl
m4_foreach([DX_i], [m4_shift(DX_loop)], [[\\
\$(DX_DOCDIR]DX_i[)/rtf]])[
"]],
[[DX_SNIPPET_rtf=""]])
AS_IF([[test $DX_FLAG_xml -eq 1]],
[[DX_SNIPPET_xml="## ------------------------------ ##
## Rules specific for XML output. ##
## ------------------------------ ##
DX_CLEAN_XML = \$(DX_DOCDIR)/xml]dnl
m4_foreach([DX_i], [m4_shift(DX_loop)], [[\\
\$(DX_DOCDIR]DX_i[)/xml]])[
"]],
[[DX_SNIPPET_xml=""]])
AS_IF([[test $DX_FLAG_ps -eq 1]],
[[DX_SNIPPET_ps="## ----------------------------- ##
## Rules specific for PS output. ##
## ----------------------------- ##
DX_CLEAN_PS = \$(DX_DOCDIR)/\$(PACKAGE).ps]dnl
m4_foreach([DX_i], [m4_shift(DX_loop)], [[\\
\$(DX_DOCDIR]DX_i[)/\$(PACKAGE).ps]])[
DX_PS_GOAL = doxygen-ps
doxygen-ps: \$(DX_CLEAN_PS)
]m4_foreach([DX_i], [DX_loop],
[[\$(DX_DOCDIR]DX_i[)/\$(PACKAGE).ps: \$(DX_DOCDIR]DX_i[)/\$(PACKAGE).tag
\$(DX_V_LATEX)cd \$(DX_DOCDIR]DX_i[)/latex; \\
rm -f *.aux *.toc *.idx *.ind *.ilg *.log *.out; \\
\$(DX_LATEX) refman.tex; \\
\$(DX_MAKEINDEX) refman.idx; \\
\$(DX_LATEX) refman.tex; \\
countdown=5; \\
while \$(DX_EGREP) 'Rerun (LaTeX|to get cross-references right)' \\
refman.log > /dev/null 2>&1 \\
&& test \$\$countdown -gt 0; do \\
\$(DX_LATEX) refman.tex; \\
countdown=\`expr \$\$countdown - 1\`; \\
done; \\
\$(DX_DVIPS) -o ../\$(PACKAGE).ps refman.dvi
]])["]],
[[DX_SNIPPET_ps=""]])
AS_IF([[test $DX_FLAG_pdf -eq 1]],
[[DX_SNIPPET_pdf="## ------------------------------ ##
## Rules specific for PDF output. ##
## ------------------------------ ##
DX_CLEAN_PDF = \$(DX_DOCDIR)/\$(PACKAGE).pdf]dnl
m4_foreach([DX_i], [m4_shift(DX_loop)], [[\\
\$(DX_DOCDIR]DX_i[)/\$(PACKAGE).pdf]])[
DX_PDF_GOAL = doxygen-pdf
doxygen-pdf: \$(DX_CLEAN_PDF)
]m4_foreach([DX_i], [DX_loop],
[[\$(DX_DOCDIR]DX_i[)/\$(PACKAGE).pdf: \$(DX_DOCDIR]DX_i[)/\$(PACKAGE).tag
\$(DX_V_LATEX)cd \$(DX_DOCDIR]DX_i[)/latex; \\
rm -f *.aux *.toc *.idx *.ind *.ilg *.log *.out; \\
\$(DX_PDFLATEX) refman.tex; \\
\$(DX_MAKEINDEX) refman.idx; \\
\$(DX_PDFLATEX) refman.tex; \\
countdown=5; \\
while \$(DX_EGREP) 'Rerun (LaTeX|to get cross-references right)' \\
refman.log > /dev/null 2>&1 \\
&& test \$\$countdown -gt 0; do \\
\$(DX_PDFLATEX) refman.tex; \\
countdown=\`expr \$\$countdown - 1\`; \\
done; \\
mv refman.pdf ../\$(PACKAGE).pdf
]])["]],
[[DX_SNIPPET_pdf=""]])
AS_IF([[test $DX_FLAG_ps -eq 1 -o $DX_FLAG_pdf -eq 1]],
[[DX_SNIPPET_latex="## ------------------------------------------------- ##
## Rules specific for LaTeX (shared for PS and PDF). ##
## ------------------------------------------------- ##
DX_V_LATEX = \$(_DX_v_LATEX_\$(V))
_DX_v_LATEX_ = \$(_DX_v_LATEX_\$(AM_DEFAULT_VERBOSITY))
_DX_v_LATEX_0 = @echo \" LATEX \" \$][@;
DX_CLEAN_LATEX = \$(DX_DOCDIR)/latex]dnl
m4_foreach([DX_i], [m4_shift(DX_loop)], [[\\
\$(DX_DOCDIR]DX_i[)/latex]])[
"]],
[[DX_SNIPPET_latex=""]])
AS_IF([[test $DX_FLAG_doc -eq 1]],
[[DX_SNIPPET_doc="## --------------------------------- ##
## Format-independent Doxygen rules. ##
## --------------------------------- ##
${DX_SNIPPET_html}\
${DX_SNIPPET_chm}\
${DX_SNIPPET_man}\
${DX_SNIPPET_rtf}\
${DX_SNIPPET_xml}\
${DX_SNIPPET_ps}\
${DX_SNIPPET_pdf}\
${DX_SNIPPET_latex}\
DX_V_DXGEN = \$(_DX_v_DXGEN_\$(V))
_DX_v_DXGEN_ = \$(_DX_v_DXGEN_\$(AM_DEFAULT_VERBOSITY))
_DX_v_DXGEN_0 = @echo \" DXGEN \" \$<;
.PHONY: doxygen-run doxygen-doc \$(DX_PS_GOAL) \$(DX_PDF_GOAL)
.INTERMEDIATE: doxygen-run \$(DX_PS_GOAL) \$(DX_PDF_GOAL)
doxygen-run:]m4_foreach([DX_i], [DX_loop],
[[ \$(DX_DOCDIR]DX_i[)/\$(PACKAGE).tag]])[
doxygen-doc: doxygen-run \$(DX_PS_GOAL) \$(DX_PDF_GOAL)
]m4_foreach([DX_i], [DX_loop],
[[\$(DX_DOCDIR]DX_i[)/\$(PACKAGE).tag: \$(DX_CONFIG]DX_i[) \$(pkginclude_HEADERS)
\$(DX_V_DXGEN)\$(DX_ENV) DOCDIR=\$(DX_DOCDIR]DX_i[) \$(DX_DOXYGEN) \$(DX_CONFIG]DX_i[)
\$(A""M_V_at)echo Timestamp >\$][@
]])dnl
[DX_CLEANFILES = \\]
m4_foreach([DX_i], [DX_loop],
[[ \$(DX_DOCDIR]DX_i[)/doxygen_sqlite3.db \\
\$(DX_DOCDIR]DX_i[)/\$(PACKAGE).tag \\
]])dnl
[ -r \\
\$(DX_CLEAN_HTML) \\
\$(DX_CLEAN_CHM) \\
\$(DX_CLEAN_CHI) \\
\$(DX_CLEAN_MAN) \\
\$(DX_CLEAN_RTF) \\
\$(DX_CLEAN_XML) \\
\$(DX_CLEAN_PS) \\
\$(DX_CLEAN_PDF) \\
\$(DX_CLEAN_LATEX)"]],
[[DX_SNIPPET_doc=""]])
AC_SUBST([DX_RULES],
["${DX_SNIPPET_doc}"])dnl
AM_SUBST_NOTMAKE([DX_RULES])
#For debugging:
#echo DX_FLAG_doc=$DX_FLAG_doc
#echo DX_FLAG_dot=$DX_FLAG_dot
#echo DX_FLAG_man=$DX_FLAG_man
#echo DX_FLAG_html=$DX_FLAG_html
#echo DX_FLAG_chm=$DX_FLAG_chm
#echo DX_FLAG_chi=$DX_FLAG_chi
#echo DX_FLAG_rtf=$DX_FLAG_rtf
#echo DX_FLAG_xml=$DX_FLAG_xml
#echo DX_FLAG_pdf=$DX_FLAG_pdf
#echo DX_FLAG_ps=$DX_FLAG_ps
#echo DX_ENV=$DX_ENV
])
-648
View File
@@ -1,648 +0,0 @@
/* $OpenBSD: queue.h,v 1.38 2013/07/03 15:05:21 fgsch Exp $ */
/* $NetBSD: queue.h,v 1.11 1996/05/16 05:17:14 mycroft Exp $ */
/*
* Copyright (c) 1991, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)queue.h 8.5 (Berkeley) 8/20/94
*/
#ifndef _SYS_QUEUE_H_
#define _SYS_QUEUE_H_
/*
* This file defines five types of data structures: singly-linked lists,
* lists, simple queues, tail queues, and circular queues.
*
*
* A singly-linked list is headed by a single forward pointer. The elements
* are singly linked for minimum space and pointer manipulation overhead at
* the expense of O(n) removal for arbitrary elements. New elements can be
* added to the list after an existing element or at the head of the list.
* Elements being removed from the head of the list should use the explicit
* macro for this purpose for optimum efficiency. A singly-linked list may
* only be traversed in the forward direction. Singly-linked lists are ideal
* for applications with large datasets and few or no removals or for
* implementing a LIFO queue.
*
* A list is headed by a single forward pointer (or an array of forward
* pointers for a hash table header). The elements are doubly linked
* so that an arbitrary element can be removed without a need to
* traverse the list. New elements can be added to the list before
* or after an existing element or at the head of the list. A list
* may only be traversed in the forward direction.
*
* A simple queue is headed by a pair of pointers, one the head of the
* list and the other to the tail of the list. The elements are singly
* linked to save space, so elements can only be removed from the
* head of the list. New elements can be added to the list before or after
* an existing element, at the head of the list, or at the end of the
* list. A simple queue may only be traversed in the forward direction.
*
* A tail queue is headed by a pair of pointers, one to the head of the
* list and the other to the tail of the list. The elements are doubly
* linked so that an arbitrary element can be removed without a need to
* traverse the list. New elements can be added to the list before or
* after an existing element, at the head of the list, or at the end of
* the list. A tail queue may be traversed in either direction.
*
* A circle queue is headed by a pair of pointers, one to the head of the
* list and the other to the tail of the list. The elements are doubly
* linked so that an arbitrary element can be removed without a need to
* traverse the list. New elements can be added to the list before or after
* an existing element, at the head of the list, or at the end of the list.
* A circle queue may be traversed in either direction, but has a more
* complex end of list detection.
*
* For details on the use of these macros, see the queue(3) manual page.
*/
#if defined(QUEUE_MACRO_DEBUG) || (defined(_KERNEL) && defined(DIAGNOSTIC))
#define _Q_INVALIDATE(a) (a) = ((void *)-1)
#else
#define _Q_INVALIDATE(a)
#endif
/*
* Singly-linked List definitions.
*/
#define SLIST_HEAD(name, type) \
struct name { \
struct type *slh_first; /* first element */ \
}
#define SLIST_HEAD_INITIALIZER(head) \
{ NULL }
#define SLIST_ENTRY(type) \
struct { \
struct type *sle_next; /* next element */ \
}
/*
* Singly-linked List access methods.
*/
#define SLIST_FIRST(head) ((head)->slh_first)
#define SLIST_END(head) NULL
#define SLIST_EMPTY(head) (SLIST_FIRST(head) == SLIST_END(head))
#define SLIST_NEXT(elm, field) ((elm)->field.sle_next)
#define SLIST_FOREACH(var, head, field) \
for((var) = SLIST_FIRST(head); \
(var) != SLIST_END(head); \
(var) = SLIST_NEXT(var, field))
#define SLIST_FOREACH_SAFE(var, head, field, tvar) \
for ((var) = SLIST_FIRST(head); \
(var) && ((tvar) = SLIST_NEXT(var, field), 1); \
(var) = (tvar))
/*
* Singly-linked List functions.
*/
#define SLIST_INIT(head) { \
SLIST_FIRST(head) = SLIST_END(head); \
}
#define SLIST_INSERT_AFTER(slistelm, elm, field) do { \
(elm)->field.sle_next = (slistelm)->field.sle_next; \
(slistelm)->field.sle_next = (elm); \
} while (0)
#define SLIST_INSERT_HEAD(head, elm, field) do { \
(elm)->field.sle_next = (head)->slh_first; \
(head)->slh_first = (elm); \
} while (0)
#define SLIST_REMOVE_AFTER(elm, field) do { \
(elm)->field.sle_next = (elm)->field.sle_next->field.sle_next; \
} while (0)
#define SLIST_REMOVE_HEAD(head, field) do { \
(head)->slh_first = (head)->slh_first->field.sle_next; \
} while (0)
#define SLIST_REMOVE(head, elm, type, field) do { \
if ((head)->slh_first == (elm)) { \
SLIST_REMOVE_HEAD((head), field); \
} else { \
struct type *curelm = (head)->slh_first; \
\
while (curelm->field.sle_next != (elm)) \
curelm = curelm->field.sle_next; \
curelm->field.sle_next = \
curelm->field.sle_next->field.sle_next; \
_Q_INVALIDATE((elm)->field.sle_next); \
} \
} while (0)
/*
* List definitions.
*/
#define LIST_HEAD(name, type) \
struct name { \
struct type *lh_first; /* first element */ \
}
#define LIST_HEAD_INITIALIZER(head) \
{ NULL }
#define LIST_ENTRY(type) \
struct { \
struct type *le_next; /* next element */ \
struct type **le_prev; /* address of previous next element */ \
}
/*
* List access methods
*/
#define LIST_FIRST(head) ((head)->lh_first)
#define LIST_END(head) NULL
#define LIST_EMPTY(head) (LIST_FIRST(head) == LIST_END(head))
#define LIST_NEXT(elm, field) ((elm)->field.le_next)
#define LIST_FOREACH(var, head, field) \
for((var) = LIST_FIRST(head); \
(var)!= LIST_END(head); \
(var) = LIST_NEXT(var, field))
#define LIST_FOREACH_SAFE(var, head, field, tvar) \
for ((var) = LIST_FIRST(head); \
(var) && ((tvar) = LIST_NEXT(var, field), 1); \
(var) = (tvar))
/*
* List functions.
*/
#define LIST_INIT(head) do { \
LIST_FIRST(head) = LIST_END(head); \
} while (0)
#define LIST_INSERT_AFTER(listelm, elm, field) do { \
if (((elm)->field.le_next = (listelm)->field.le_next) != NULL) \
(listelm)->field.le_next->field.le_prev = \
&(elm)->field.le_next; \
(listelm)->field.le_next = (elm); \
(elm)->field.le_prev = &(listelm)->field.le_next; \
} while (0)
#define LIST_INSERT_BEFORE(listelm, elm, field) do { \
(elm)->field.le_prev = (listelm)->field.le_prev; \
(elm)->field.le_next = (listelm); \
*(listelm)->field.le_prev = (elm); \
(listelm)->field.le_prev = &(elm)->field.le_next; \
} while (0)
#define LIST_INSERT_HEAD(head, elm, field) do { \
if (((elm)->field.le_next = (head)->lh_first) != NULL) \
(head)->lh_first->field.le_prev = &(elm)->field.le_next;\
(head)->lh_first = (elm); \
(elm)->field.le_prev = &(head)->lh_first; \
} while (0)
#define LIST_REMOVE(elm, field) do { \
if ((elm)->field.le_next != NULL) \
(elm)->field.le_next->field.le_prev = \
(elm)->field.le_prev; \
*(elm)->field.le_prev = (elm)->field.le_next; \
_Q_INVALIDATE((elm)->field.le_prev); \
_Q_INVALIDATE((elm)->field.le_next); \
} while (0)
#define LIST_REPLACE(elm, elm2, field) do { \
if (((elm2)->field.le_next = (elm)->field.le_next) != NULL) \
(elm2)->field.le_next->field.le_prev = \
&(elm2)->field.le_next; \
(elm2)->field.le_prev = (elm)->field.le_prev; \
*(elm2)->field.le_prev = (elm2); \
_Q_INVALIDATE((elm)->field.le_prev); \
_Q_INVALIDATE((elm)->field.le_next); \
} while (0)
/*
* Simple queue definitions.
*/
#define SIMPLEQ_HEAD(name, type) \
struct name { \
struct type *sqh_first; /* first element */ \
struct type **sqh_last; /* addr of last next element */ \
}
#define SIMPLEQ_HEAD_INITIALIZER(head) \
{ NULL, &(head).sqh_first }
#define SIMPLEQ_ENTRY(type) \
struct { \
struct type *sqe_next; /* next element */ \
}
/*
* Simple queue access methods.
*/
#define SIMPLEQ_FIRST(head) ((head)->sqh_first)
#define SIMPLEQ_END(head) NULL
#define SIMPLEQ_EMPTY(head) (SIMPLEQ_FIRST(head) == SIMPLEQ_END(head))
#define SIMPLEQ_NEXT(elm, field) ((elm)->field.sqe_next)
#define SIMPLEQ_FOREACH(var, head, field) \
for((var) = SIMPLEQ_FIRST(head); \
(var) != SIMPLEQ_END(head); \
(var) = SIMPLEQ_NEXT(var, field))
#define SIMPLEQ_FOREACH_SAFE(var, head, field, tvar) \
for ((var) = SIMPLEQ_FIRST(head); \
(var) && ((tvar) = SIMPLEQ_NEXT(var, field), 1); \
(var) = (tvar))
/*
* Simple queue functions.
*/
#define SIMPLEQ_INIT(head) do { \
(head)->sqh_first = NULL; \
(head)->sqh_last = &(head)->sqh_first; \
} while (0)
#define SIMPLEQ_INSERT_HEAD(head, elm, field) do { \
if (((elm)->field.sqe_next = (head)->sqh_first) == NULL) \
(head)->sqh_last = &(elm)->field.sqe_next; \
(head)->sqh_first = (elm); \
} while (0)
#define SIMPLEQ_INSERT_TAIL(head, elm, field) do { \
(elm)->field.sqe_next = NULL; \
*(head)->sqh_last = (elm); \
(head)->sqh_last = &(elm)->field.sqe_next; \
} while (0)
#define SIMPLEQ_INSERT_AFTER(head, listelm, elm, field) do { \
if (((elm)->field.sqe_next = (listelm)->field.sqe_next) == NULL)\
(head)->sqh_last = &(elm)->field.sqe_next; \
(listelm)->field.sqe_next = (elm); \
} while (0)
#define SIMPLEQ_REMOVE_HEAD(head, field) do { \
if (((head)->sqh_first = (head)->sqh_first->field.sqe_next) == NULL) \
(head)->sqh_last = &(head)->sqh_first; \
} while (0)
#define SIMPLEQ_REMOVE_AFTER(head, elm, field) do { \
if (((elm)->field.sqe_next = (elm)->field.sqe_next->field.sqe_next) \
== NULL) \
(head)->sqh_last = &(elm)->field.sqe_next; \
} while (0)
/*
* XOR Simple queue definitions.
*/
#define XSIMPLEQ_HEAD(name, type) \
struct name { \
struct type *sqx_first; /* first element */ \
struct type **sqx_last; /* addr of last next element */ \
unsigned long sqx_cookie; \
}
#define XSIMPLEQ_ENTRY(type) \
struct { \
struct type *sqx_next; /* next element */ \
}
/*
* XOR Simple queue access methods.
*/
#define XSIMPLEQ_XOR(head, ptr) ((__typeof(ptr))((head)->sqx_cookie ^ \
(unsigned long)(ptr)))
#define XSIMPLEQ_FIRST(head) XSIMPLEQ_XOR(head, ((head)->sqx_first))
#define XSIMPLEQ_END(head) NULL
#define XSIMPLEQ_EMPTY(head) (XSIMPLEQ_FIRST(head) == XSIMPLEQ_END(head))
#define XSIMPLEQ_NEXT(head, elm, field) XSIMPLEQ_XOR(head, ((elm)->field.sqx_next))
#define XSIMPLEQ_FOREACH(var, head, field) \
for ((var) = XSIMPLEQ_FIRST(head); \
(var) != XSIMPLEQ_END(head); \
(var) = XSIMPLEQ_NEXT(head, var, field))
#define XSIMPLEQ_FOREACH_SAFE(var, head, field, tvar) \
for ((var) = XSIMPLEQ_FIRST(head); \
(var) && ((tvar) = XSIMPLEQ_NEXT(head, var, field), 1); \
(var) = (tvar))
/*
* XOR Simple queue functions.
*/
#define XSIMPLEQ_INIT(head) do { \
arc4random_buf(&(head)->sqx_cookie, sizeof((head)->sqx_cookie)); \
(head)->sqx_first = XSIMPLEQ_XOR(head, NULL); \
(head)->sqx_last = XSIMPLEQ_XOR(head, &(head)->sqx_first); \
} while (0)
#define XSIMPLEQ_INSERT_HEAD(head, elm, field) do { \
if (((elm)->field.sqx_next = (head)->sqx_first) == \
XSIMPLEQ_XOR(head, NULL)) \
(head)->sqx_last = XSIMPLEQ_XOR(head, &(elm)->field.sqx_next); \
(head)->sqx_first = XSIMPLEQ_XOR(head, (elm)); \
} while (0)
#define XSIMPLEQ_INSERT_TAIL(head, elm, field) do { \
(elm)->field.sqx_next = XSIMPLEQ_XOR(head, NULL); \
*(XSIMPLEQ_XOR(head, (head)->sqx_last)) = XSIMPLEQ_XOR(head, (elm)); \
(head)->sqx_last = XSIMPLEQ_XOR(head, &(elm)->field.sqx_next); \
} while (0)
#define XSIMPLEQ_INSERT_AFTER(head, listelm, elm, field) do { \
if (((elm)->field.sqx_next = (listelm)->field.sqx_next) == \
XSIMPLEQ_XOR(head, NULL)) \
(head)->sqx_last = XSIMPLEQ_XOR(head, &(elm)->field.sqx_next); \
(listelm)->field.sqx_next = XSIMPLEQ_XOR(head, (elm)); \
} while (0)
#define XSIMPLEQ_REMOVE_HEAD(head, field) do { \
if (((head)->sqx_first = XSIMPLEQ_XOR(head, \
(head)->sqx_first)->field.sqx_next) == XSIMPLEQ_XOR(head, NULL)) \
(head)->sqx_last = XSIMPLEQ_XOR(head, &(head)->sqx_first); \
} while (0)
#define XSIMPLEQ_REMOVE_AFTER(head, elm, field) do { \
if (((elm)->field.sqx_next = XSIMPLEQ_XOR(head, \
(elm)->field.sqx_next)->field.sqx_next) \
== XSIMPLEQ_XOR(head, NULL)) \
(head)->sqx_last = \
XSIMPLEQ_XOR(head, &(elm)->field.sqx_next); \
} while (0)
/*
* Tail queue definitions.
*/
#define TAILQ_HEAD(name, type) \
struct name { \
struct type *tqh_first; /* first element */ \
struct type **tqh_last; /* addr of last next element */ \
}
#define TAILQ_HEAD_INITIALIZER(head) \
{ NULL, &(head).tqh_first }
#define TAILQ_ENTRY(type) \
struct { \
struct type *tqe_next; /* next element */ \
struct type **tqe_prev; /* address of previous next element */ \
}
/*
* tail queue access methods
*/
#define TAILQ_FIRST(head) ((head)->tqh_first)
#define TAILQ_END(head) NULL
#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next)
#define TAILQ_LAST(head, headname) \
(*(((struct headname *)((head)->tqh_last))->tqh_last))
/* XXX */
#define TAILQ_PREV(elm, headname, field) \
(*(((struct headname *)((elm)->field.tqe_prev))->tqh_last))
#define TAILQ_EMPTY(head) \
(TAILQ_FIRST(head) == TAILQ_END(head))
#define TAILQ_FOREACH(var, head, field) \
for((var) = TAILQ_FIRST(head); \
(var) != TAILQ_END(head); \
(var) = TAILQ_NEXT(var, field))
#define TAILQ_FOREACH_SAFE(var, head, field, tvar) \
for ((var) = TAILQ_FIRST(head); \
(var) != TAILQ_END(head) && \
((tvar) = TAILQ_NEXT(var, field), 1); \
(var) = (tvar))
#define TAILQ_FOREACH_REVERSE(var, head, headname, field) \
for((var) = TAILQ_LAST(head, headname); \
(var) != TAILQ_END(head); \
(var) = TAILQ_PREV(var, headname, field))
#define TAILQ_FOREACH_REVERSE_SAFE(var, head, headname, field, tvar) \
for ((var) = TAILQ_LAST(head, headname); \
(var) != TAILQ_END(head) && \
((tvar) = TAILQ_PREV(var, headname, field), 1); \
(var) = (tvar))
/*
* Tail queue functions.
*/
#define TAILQ_INIT(head) do { \
(head)->tqh_first = NULL; \
(head)->tqh_last = &(head)->tqh_first; \
} while (0)
#define TAILQ_INSERT_HEAD(head, elm, field) do { \
if (((elm)->field.tqe_next = (head)->tqh_first) != NULL) \
(head)->tqh_first->field.tqe_prev = \
&(elm)->field.tqe_next; \
else \
(head)->tqh_last = &(elm)->field.tqe_next; \
(head)->tqh_first = (elm); \
(elm)->field.tqe_prev = &(head)->tqh_first; \
} while (0)
#define TAILQ_INSERT_TAIL(head, elm, field) do { \
(elm)->field.tqe_next = NULL; \
(elm)->field.tqe_prev = (head)->tqh_last; \
*(head)->tqh_last = (elm); \
(head)->tqh_last = &(elm)->field.tqe_next; \
} while (0)
#define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \
if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != NULL)\
(elm)->field.tqe_next->field.tqe_prev = \
&(elm)->field.tqe_next; \
else \
(head)->tqh_last = &(elm)->field.tqe_next; \
(listelm)->field.tqe_next = (elm); \
(elm)->field.tqe_prev = &(listelm)->field.tqe_next; \
} while (0)
#define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \
(elm)->field.tqe_prev = (listelm)->field.tqe_prev; \
(elm)->field.tqe_next = (listelm); \
*(listelm)->field.tqe_prev = (elm); \
(listelm)->field.tqe_prev = &(elm)->field.tqe_next; \
} while (0)
#define TAILQ_REMOVE(head, elm, field) do { \
if (((elm)->field.tqe_next) != NULL) \
(elm)->field.tqe_next->field.tqe_prev = \
(elm)->field.tqe_prev; \
else \
(head)->tqh_last = (elm)->field.tqe_prev; \
*(elm)->field.tqe_prev = (elm)->field.tqe_next; \
_Q_INVALIDATE((elm)->field.tqe_prev); \
_Q_INVALIDATE((elm)->field.tqe_next); \
} while (0)
#define TAILQ_REPLACE(head, elm, elm2, field) do { \
if (((elm2)->field.tqe_next = (elm)->field.tqe_next) != NULL) \
(elm2)->field.tqe_next->field.tqe_prev = \
&(elm2)->field.tqe_next; \
else \
(head)->tqh_last = &(elm2)->field.tqe_next; \
(elm2)->field.tqe_prev = (elm)->field.tqe_prev; \
*(elm2)->field.tqe_prev = (elm2); \
_Q_INVALIDATE((elm)->field.tqe_prev); \
_Q_INVALIDATE((elm)->field.tqe_next); \
} while (0)
/*
* Circular queue definitions.
*/
#define CIRCLEQ_HEAD(name, type) \
struct name { \
struct type *cqh_first; /* first element */ \
struct type *cqh_last; /* last element */ \
}
#define CIRCLEQ_HEAD_INITIALIZER(head) \
{ CIRCLEQ_END(&head), CIRCLEQ_END(&head) }
#define CIRCLEQ_ENTRY(type) \
struct { \
struct type *cqe_next; /* next element */ \
struct type *cqe_prev; /* previous element */ \
}
/*
* Circular queue access methods
*/
#define CIRCLEQ_FIRST(head) ((head)->cqh_first)
#define CIRCLEQ_LAST(head) ((head)->cqh_last)
#define CIRCLEQ_END(head) ((void *)(head))
#define CIRCLEQ_NEXT(elm, field) ((elm)->field.cqe_next)
#define CIRCLEQ_PREV(elm, field) ((elm)->field.cqe_prev)
#define CIRCLEQ_EMPTY(head) \
(CIRCLEQ_FIRST(head) == CIRCLEQ_END(head))
#define CIRCLEQ_FOREACH(var, head, field) \
for((var) = CIRCLEQ_FIRST(head); \
(var) != CIRCLEQ_END(head); \
(var) = CIRCLEQ_NEXT(var, field))
#define CIRCLEQ_FOREACH_SAFE(var, head, field, tvar) \
for ((var) = CIRCLEQ_FIRST(head); \
(var) != CIRCLEQ_END(head) && \
((tvar) = CIRCLEQ_NEXT(var, field), 1); \
(var) = (tvar))
#define CIRCLEQ_FOREACH_REVERSE(var, head, field) \
for((var) = CIRCLEQ_LAST(head); \
(var) != CIRCLEQ_END(head); \
(var) = CIRCLEQ_PREV(var, field))
#define CIRCLEQ_FOREACH_REVERSE_SAFE(var, head, headname, field, tvar) \
for ((var) = CIRCLEQ_LAST(head, headname); \
(var) != CIRCLEQ_END(head) && \
((tvar) = CIRCLEQ_PREV(var, headname, field), 1); \
(var) = (tvar))
/*
* Circular queue functions.
*/
#define CIRCLEQ_INIT(head) do { \
(head)->cqh_first = CIRCLEQ_END(head); \
(head)->cqh_last = CIRCLEQ_END(head); \
} while (0)
#define CIRCLEQ_INSERT_AFTER(head, listelm, elm, field) do { \
(elm)->field.cqe_next = (listelm)->field.cqe_next; \
(elm)->field.cqe_prev = (listelm); \
if ((listelm)->field.cqe_next == CIRCLEQ_END(head)) \
(head)->cqh_last = (elm); \
else \
(listelm)->field.cqe_next->field.cqe_prev = (elm); \
(listelm)->field.cqe_next = (elm); \
} while (0)
#define CIRCLEQ_INSERT_BEFORE(head, listelm, elm, field) do { \
(elm)->field.cqe_next = (listelm); \
(elm)->field.cqe_prev = (listelm)->field.cqe_prev; \
if ((listelm)->field.cqe_prev == CIRCLEQ_END(head)) \
(head)->cqh_first = (elm); \
else \
(listelm)->field.cqe_prev->field.cqe_next = (elm); \
(listelm)->field.cqe_prev = (elm); \
} while (0)
#define CIRCLEQ_INSERT_HEAD(head, elm, field) do { \
(elm)->field.cqe_next = (head)->cqh_first; \
(elm)->field.cqe_prev = CIRCLEQ_END(head); \
if ((head)->cqh_last == CIRCLEQ_END(head)) \
(head)->cqh_last = (elm); \
else \
(head)->cqh_first->field.cqe_prev = (elm); \
(head)->cqh_first = (elm); \
} while (0)
#define CIRCLEQ_INSERT_TAIL(head, elm, field) do { \
(elm)->field.cqe_next = CIRCLEQ_END(head); \
(elm)->field.cqe_prev = (head)->cqh_last; \
if ((head)->cqh_first == CIRCLEQ_END(head)) \
(head)->cqh_first = (elm); \
else \
(head)->cqh_last->field.cqe_next = (elm); \
(head)->cqh_last = (elm); \
} while (0)
#define CIRCLEQ_REMOVE(head, elm, field) do { \
if ((elm)->field.cqe_next == CIRCLEQ_END(head)) \
(head)->cqh_last = (elm)->field.cqe_prev; \
else \
(elm)->field.cqe_next->field.cqe_prev = \
(elm)->field.cqe_prev; \
if ((elm)->field.cqe_prev == CIRCLEQ_END(head)) \
(head)->cqh_first = (elm)->field.cqe_next; \
else \
(elm)->field.cqe_prev->field.cqe_next = \
(elm)->field.cqe_next; \
_Q_INVALIDATE((elm)->field.cqe_prev); \
_Q_INVALIDATE((elm)->field.cqe_next); \
} while (0)
#define CIRCLEQ_REPLACE(head, elm, elm2, field) do { \
if (((elm2)->field.cqe_next = (elm)->field.cqe_next) == \
CIRCLEQ_END(head)) \
(head)->cqh_last = (elm2); \
else \
(elm2)->field.cqe_next->field.cqe_prev = (elm2); \
if (((elm2)->field.cqe_prev = (elm)->field.cqe_prev) == \
CIRCLEQ_END(head)) \
(head)->cqh_first = (elm2); \
else \
(elm2)->field.cqe_prev->field.cqe_next = (elm2); \
_Q_INVALIDATE((elm)->field.cqe_prev); \
_Q_INVALIDATE((elm)->field.cqe_next); \
} while (0)
#endif /* !_SYS_QUEUE_H_ */
+14
View File
@@ -0,0 +1,14 @@
lib_LTLIBRARIES = libuev.la
libuev_la_SOURCES = uev.c uev.h private.h io.c timer.c signal.c cron.c event.c
libuev_la_CPPFLAGS = -D_GNU_SOURCE -D_TIME_BITS=64 -D_FILE_OFFSET_BITS=64
libuev_la_CFLAGS = -W -Wall -Wextra -std=gnu11
libuev_la_LDFLAGS = $(AM_LDFLAGS) -version-info 3:0:0
noinst_PROGRAMS = bench
bench_CPPFLAGS = -D_GNU_SOURCE
bench_LDADD = libuev.la
pkgconfigdir = $(libdir)/pkgconfig
pkgincludedir = $(includedir)/uev
pkgconfig_DATA = libuev.pc
pkginclude_HEADERS = uev.h private.h
+1
View File
@@ -0,0 +1 @@
../doc/API.md
+5 -7
View File
@@ -44,11 +44,11 @@
#include <errno.h> #include <errno.h>
#include <fcntl.h> #include <fcntl.h>
#include <signal.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <sys/resource.h> #include <sys/resource.h>
#include <sys/signal.h>
#include <sys/socket.h> #include <sys/socket.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/time.h> #include <sys/time.h>
@@ -57,8 +57,6 @@
#include "uev.h" #include "uev.h"
#define UNUSED(arg) arg __attribute__ ((unused))
typedef struct { typedef struct {
int index; int index;
} myarg_t; } myarg_t;
@@ -70,7 +68,7 @@ static int *pipes;
static uev_t *evio; static uev_t *evio;
static uev_t *evto; static uev_t *evto;
static void read_cb(uev_t *w, void *arg, int UNUSED(events)) static void read_cb(uev_t *w, void *arg, int events)
{ {
int idx, widx; int idx, widx;
u_char ch; u_char ch;
@@ -96,7 +94,7 @@ static void read_cb(uev_t *w, void *arg, int UNUSED(events))
} }
} }
static void timer_cb(uev_t UNUSED(*w), void UNUSED(*arg), int UNUSED(events)) static void timer_cb(uev_t *w, void *arg, int events)
{ {
/* nop */ /* nop */
} }
@@ -140,7 +138,8 @@ static struct timeval *run_once(uev_ctx_t *ctx)
gettimeofday(&te, NULL); gettimeofday(&te, NULL);
// if (xcount != count) fprintf(stderr, "Xcount: %d, Rcount: %d\n", xcount, count); if (xcount != count)
fprintf(stderr, "Xcount: %d, Rcount: %d\n", xcount, count);
} }
timersub(&te, &ta, &ta); timersub(&te, &ta, &ta);
@@ -229,7 +228,6 @@ int main(int argc, char **argv)
/** /**
* Local Variables: * Local Variables:
* version-control: t
* indent-tabs-mode: t * indent-tabs-mode: t
* c-file-style: "linux" * c-file-style: "linux"
* End: * End:
+166
View File
@@ -0,0 +1,166 @@
/* libuEv - Micro event loop library
*
* Copyright (c) 2012 Flemming Madsen <flemming!madsen()madsensoft!dk>
* Copyright (c) 2013-2024 Joachim Wiberg <troglobit()gmail!com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <errno.h>
#include <string.h> /* memset() */
#include <sys/timerfd.h>
#include <unistd.h> /* close(), read() */
#include "uev.h"
/* Missing defines in GLIBC <= 2.24 */
#ifndef TFD_TIMER_CANCEL_ON_SET
#define TFD_TIMER_CANCEL_ON_SET (1 << 1)
#endif
#ifndef TFD_SETTIME_FLAGS
#define TFD_SETTIME_FLAGS (TFD_TIMER_ABSTIME | TFD_TIMER_CANCEL_ON_SET)
#endif
/**
* At/Cron like timers.
* @file cron.c
*/
/**
* Create and start an at/cron job watcher
* @param ctx A valid libuEv context
* @param w Pointer to an uev_t watcher
* @param cb Callback function for cron job
* @param arg Optional callback argument
* @param when First point in time to call @p cb
* @param interval For an at job this is zero, for cron the offset interval
*
* For at jobs set @p interval to zero and only use @p when. For
* cron jobs, set @p interval to the offset. E.g., if the job should
* run every five minutes set the @p tm_min of struct tm to five.
*
* Use mktime() to create the time_t arguments. The special value zero
* may be used for @p when to denote 'now', where 'now' is when the
* event loop is started. You can also treat time_t simply as a signed
* integer. E.g., set @p interval to 3600 to create a cron job that
* runs every hour.
*
* @return POSIX OK(0) or non-zero with @p errno set on error.
*/
int uev_cron_init(uev_ctx_t *ctx, uev_t *w, uev_cb_t *cb, void *arg, time_t when, time_t interval)
{
int fd;
if (when < 0 || interval < 0) {
errno = ERANGE;
return -1;
}
fd = timerfd_create(CLOCK_REALTIME, TFD_NONBLOCK | TFD_CLOEXEC);
if (fd < 0)
return -1;
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);
exit:
close(fd);
return -1;
}
return 0;
}
/**
* Reset an at/cron job watcher
* @param w Watcher to reset
* @param when First point in time to call @p cb
* @param interval For an at job this is zero, for cron the offset interval
*
* @return POSIX OK(0) or non-zero with @p errno set on error.
*/
int uev_cron_set(uev_t *w, time_t when, time_t interval)
{
/* Every watcher must be registered to a context */
if (!w || !w->ctx) {
errno = EINVAL;
return -1;
}
if (when < 0 || interval < 0) {
errno = ERANGE;
return -1;
}
/* Handle stopped timers */
if (w->fd < 0) {
/* Timer already stopped */
if (!when && !interval)
return 0;
if (uev_cron_init(w->ctx, w, (uev_cb_t *)w->cb, w->arg, when, interval))
return -1;
}
w->u.c.when = when;
w->u.c.interval = interval;
if (w->ctx->running) {
struct itimerspec time;
memset(&time, 0, sizeof(time));
time.it_value.tv_sec = when;
time.it_interval.tv_sec = interval;
if (timerfd_settime(w->fd, TFD_SETTIME_FLAGS, &time, NULL) < 0)
return 1;
}
return _uev_watcher_start(w);
}
/**
* Start a stopped at/cron job watcher
* @param w Watcher to start (again)
*
* @return POSIX OK(0) or non-zero with @p errno set on error.
*/
int uev_cron_start(uev_t *w)
{
return uev_timer_start(w);
}
/**
* Stop and unregister an at/cron job watcher
* @param w Watcher to stop
*
* @return POSIX OK(0) or non-zero with @p errno set on error.
*/
int uev_cron_stop(uev_t *w)
{
return uev_timer_stop(w);
}
/**
* Local Variables:
* indent-tabs-mode: t
* c-file-style: "linux"
* End:
*/
+111
View File
@@ -0,0 +1,111 @@
/* libuEv - Micro event loop library
*
* Copyright (c) 2012 Flemming Madsen <flemming!madsen()madsensoft!dk>
* Copyright (c) 2013-2024 Joachim Wiberg <troglobit()gmail!com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <errno.h>
#include <sys/eventfd.h>
#include <unistd.h> /* close(), read() */
#include "uev.h"
/**
* Linux [eventfd(2)](https://man7.org/linux/man-pages/man2/eventfd.2.html).
* @file event.c
*/
/**
* Create a generic event watcher
* @param ctx A valid libuEv context
* @param w Pointer to an uev_t watcher
* @param cb Callback when an event is posted
* @param arg Optional callback argument
*
* @return POSIX OK(0) or non-zero with @p errno set on error.
*/
int uev_event_init(uev_ctx_t *ctx, uev_t *w, uev_cb_t *cb, void *arg)
{
int fd;
if (!w || !ctx) {
errno = EINVAL;
return -1;
}
w->fd = -1;
fd = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC);
if (fd < 0)
return -1;
return _uev_watcher_init(ctx, w, UEV_EVENT_TYPE, cb, arg, fd, UEV_READ)
|| _uev_watcher_start(w);
}
/**
* Post a generic event
* @param w Watcher to post to
*
* @return POSIX OK(0) or non-zero with @p errno set on error.
*/
int uev_event_post(uev_t *w)
{
uint64_t val = 1;
if (!w || -1 == w->fd) {
errno = EINVAL;
return -1;
}
if (write(w->fd, &val, sizeof(val)) != sizeof(val))
return -1;
return 0;
}
/**
* Stop a generic event watcher
* @param w Watcher to stop
*
* @return POSIX OK(0) or non-zero with @p errno set on error.
*/
int uev_event_stop(uev_t *w)
{
if (!_uev_watcher_active(w))
return 0;
if (_uev_watcher_stop(w))
return -1;
close(w->fd);
w->fd = -1;
return 0;
}
/**
* Local Variables:
* indent-tabs-mode: t
* c-file-style: "linux"
* End:
*/
+17 -12
View File
@@ -1,7 +1,7 @@
/* libuEv - Micro event loop library /* libuEv - Micro event loop library
* *
* Copyright (c) 2012 Flemming Madsen <flemming!madsen()madsensoft!dk> * Copyright (c) 2012 Flemming Madsen <flemming!madsen()madsensoft!dk>
* Copyright (c) 2013-2015 Joachim Nilsson <troglobit()gmail!com> * Copyright (c) 2013-2024 Joachim Wiberg <troglobit()gmail!com>
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
@@ -23,9 +23,12 @@
*/ */
#include <errno.h> #include <errno.h>
#include "uev.h" #include "uev.h"
/**
* Descriptor backend, capable of watching files, sockets, pipes, etc.
* @file io.c
*/
/** /**
* Create an I/O watcher * Create an I/O watcher
@@ -34,9 +37,9 @@
* @param cb I/O callback * @param cb I/O callback
* @param arg Optional callback argument * @param arg Optional callback argument
* @param fd File descriptor to watch, or -1 to register an empty watcher * @param fd File descriptor to watch, or -1 to register an empty watcher
* @param events Requested events to watch for, a mask of %UEV_READ, %UEV_WRITE and %UEV_PRI * @param events Events to watch for: ::UEV_READ, ::UEV_WRITE, ::UEV_EDGE, ::UEV_ONESHOT
* *
* @return POSIX OK(0) or non-zero with @param errno set on error. * @return POSIX OK(0) or non-zero with @p errno set on error.
*/ */
int uev_io_init(uev_ctx_t *ctx, uev_t *w, uev_cb_t *cb, void *arg, int fd, int events) int uev_io_init(uev_ctx_t *ctx, uev_t *w, uev_cb_t *cb, void *arg, int fd, int events)
{ {
@@ -45,22 +48,25 @@ int uev_io_init(uev_ctx_t *ctx, uev_t *w, uev_cb_t *cb, void *arg, int fd, int e
return -1; 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 -1;
return uev_watcher_start(w); return _uev_watcher_start(w);
} }
/** /**
* Reset an I/O watcher * Reset an I/O watcher
* @param w Pointer to an uev_t watcher * @param w Pointer to an uev_t watcher
* @param fd New file descriptor to monitor * @param fd New file descriptor to monitor
* @param events Requested events to watch for, a mask of %UEV_READ and %UEV_WRITE * @param events Requested events to watch for, a mask of ::UEV_READ and ::UEV_WRITE
* *
* @return POSIX OK(0) or non-zero with @param errno set on error. * @return POSIX OK(0) or non-zero with @p errno set on error.
*/ */
int uev_io_set(uev_t *w, int fd, int events) int uev_io_set(uev_t *w, int fd, int events)
{ {
if ((events & UEV_ONESHOT) && _uev_watcher_active(w))
return _uev_watcher_rearm(w);
/* Ignore any errors, only to clean up anything lingering ... */ /* Ignore any errors, only to clean up anything lingering ... */
uev_io_stop(w); uev_io_stop(w);
@@ -71,7 +77,7 @@ int uev_io_set(uev_t *w, int fd, int events)
* Start an I/O watcher * Start an I/O watcher
* @param w Watcher to start (again) * @param w Watcher to start (again)
* *
* @return POSIX OK(0) or non-zero with @param errno set on error. * @return POSIX OK(0) or non-zero with @p errno set on error.
*/ */
int uev_io_start(uev_t *w) int uev_io_start(uev_t *w)
{ {
@@ -82,16 +88,15 @@ int uev_io_start(uev_t *w)
* Stop an I/O watcher * Stop an I/O watcher
* @param w Watcher to stop * @param w Watcher to stop
* *
* @return POSIX OK(0) or non-zero with @param errno set on error. * @return POSIX OK(0) or non-zero with @p errno set on error.
*/ */
int uev_io_stop(uev_t *w) int uev_io_stop(uev_t *w)
{ {
return uev_watcher_stop(w); return _uev_watcher_stop(w);
} }
/** /**
* Local Variables: * Local Variables:
* version-control: t
* indent-tabs-mode: t * indent-tabs-mode: t
* c-file-style: "linux" * c-file-style: "linux"
* End: * End:
+1 -1
View File
@@ -8,5 +8,5 @@ Description: Simple event loop for Linux
Version: @VERSION@ Version: @VERSION@
Requires: Requires:
Libs: -L${libdir} -luev Libs: -L${libdir} -luev
Cflags: -I${includedir} Cflags: -I${includedir} -D_TIME_BITS=64 -D_FILE_OFFSET_BITS=64
+67 -22
View File
@@ -1,7 +1,7 @@
/* libuEv - Private methods and data types, do not use directly! /* libuEv - Private methods and data types, do not use directly!
* *
* Copyright (c) 2012 Flemming Madsen <flemming!madsen()madsensoft!dk> * Copyright (c) 2012 Flemming Madsen <flemming!madsen()madsensoft!dk>
* Copyright (c) 2013-2015 Joachim Nilsson <troglobit()gmail!com> * Copyright (c) 2013-2024 Joachim Wiberg <troglobit()gmail!com>
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
@@ -27,32 +27,68 @@
#include <stdio.h> #include <stdio.h>
#include <sys/epoll.h> #include <sys/epoll.h>
#include "queue.h" /* OpenBSD queue.h > old GLIBC version */ #include <sys/signalfd.h>
/*
* List functions.
*/
#define _UEV_FOREACH(node, list) \
for (typeof (node) next, node = list; \
node && (next = node->next, 1); \
node = next)
#define _UEV_INSERT(node, list) do { \
typeof (node) next; \
next = list; \
list = node; \
if (next) \
next->prev = node; \
node->next = next; \
node->prev = NULL; \
} while (0)
#define _UEV_REMOVE(node, list) do { \
typeof (node) prev, next; \
prev = node->prev; \
next = node->next; \
if (prev) \
prev->next = next; \
if (next) \
next->prev = prev; \
node->prev = NULL; \
node->next = NULL; \
if (list == node) \
list = next; \
} while (0)
/* I/O, timer, or signal watcher */ /* I/O, timer, or signal watcher */
typedef enum { typedef enum {
UEV_IO_TYPE = 1, UEV_IO_TYPE = 1,
UEV_TIMER_TYPE,
UEV_SIGNAL_TYPE, UEV_SIGNAL_TYPE,
UEV_TIMER_TYPE,
UEV_CRON_TYPE,
UEV_EVENT_TYPE,
} uev_type_t; } uev_type_t;
/* Event mask, used internally only. */ /* Event mask, used internally only. */
#define UEV_EVENT_MASK (UEV_READ | UEV_WRITE | UEV_PRI) #define UEV_EVENT_MASK (UEV_ERROR | UEV_READ | UEV_WRITE | UEV_PRI | \
UEV_RDHUP | UEV_HUP | UEV_EDGE | UEV_ONESHOT)
/* Main libuEv context type */ /* Main libuEv context type, internal use only! */
typedef struct { struct uev_ctx {
int running; int running;
int fd; /* For epoll() */ int fd; /* For epoll() */
uint32_t errors; int maxevents; /* For epoll() */
LIST_HEAD(,uev) watchers; struct uev *watchers;
} uev_ctx_t; uint32_t workaround; /* For workarounds, e.g. redirected stdin */
};
/* Forward declare due to dependencys, don't try this at home kids. */ /* Forward declare due to dependencys, don't try this at home kids. */
struct uev; struct uev;
/* This is used to hide all private data members in uev_t */ /* This is used to hide all private data members in uev_t */
#define uev_private_t \ #define uev_private_t \
LIST_ENTRY(uev) link; /* For queue.h linked list */ \ struct uev *next, *prev; \
\ \
int active; \ int active; \
int events; \ int events; \
@@ -61,28 +97,37 @@ struct uev;
void (*cb)(struct uev *, void *, int); \ void (*cb)(struct uev *, void *, int); \
void *arg; \ void *arg; \
\ \
/* Timer watchers, time in milliseconds */ \ /* Arguments for different watchers */ \
int timeout; \ union { \
int period; \ /* Cron watchers */ \
struct { \
time_t when; \
time_t interval; \
} c; \
\ \
/* Signal watchers */ \ /* Timer watchers, time in milliseconds */ \
int signo; \ struct { \
int timeout; \
int period; \
} t; \
} u; \
\ \
/* Watcher type */ \ /* Watcher type */ \
uev_type_t uev_type_t
/* Internal API for dealing with generic watchers */ /* Internal API for dealing with generic watchers */
int uev_watcher_init (uev_ctx_t *ctx, struct uev *w, uev_type_t type, int _uev_watcher_init (struct uev_ctx *ctx, struct uev *w, uev_type_t type,
void (*cb)(struct uev *, void *, int), void *arg, void (*cb)(struct uev *, void *, int), void *arg,
int fd, int events); int fd, int events);
int uev_watcher_start(struct uev *w); int _uev_watcher_start (struct uev *w);
int uev_watcher_stop (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_ */ #endif /* LIBUEV_PRIVATE_H_ */
/** /**
* Local Variables: * Local Variables:
* version-control: t
* indent-tabs-mode: t * indent-tabs-mode: t
* c-file-style: "linux" * c-file-style: "linux"
* End: * End:
+24 -16
View File
@@ -1,7 +1,7 @@
/* libuEv - Micro event loop library /* libuEv - Micro event loop library
* *
* Copyright (c) 2012 Flemming Madsen <flemming!madsen()madsensoft!dk> * Copyright (c) 2012 Flemming Madsen <flemming!madsen()madsensoft!dk>
* Copyright (c) 2013-2015 Joachim Nilsson <troglobit()gmail!com> * Copyright (c) 2013-2024 Joachim Wiberg <troglobit()gmail!com>
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
@@ -29,21 +29,30 @@
#include "uev.h" #include "uev.h"
/**
* @file signal.c
* Linux [signalfd(2)](https://man7.org/linux/man-pages/man2/signalfd.2.html).
*
* Notice how uev::siginfo returns a `struct signalfd_siginfo` with useful data
* on the sender of the signal, this information is only available to signal
* callbacks.
*/
/** /**
* Create a signal watcher * Create a signal watcher
* @param ctx A valid libuEv context * @param ctx A valid libuEv context
* @param w Pointer to an uev_t watcher * @param w Pointer to an uev_t watcher
* @param cb Timer callback * @param cb Signal callback
* @param arg Optional callback argument * @param arg Optional callback argument
* @param signo Signal to watch for * @param signo Signal to watch for
* *
* @return POSIX OK(0) or non-zero with @param errno set on error. * @return POSIX OK(0) or non-zero with @p errno set on error.
*/ */
int uev_signal_init(uev_ctx_t *ctx, uev_t *w, uev_cb_t *cb, void *arg, int signo) int uev_signal_init(uev_ctx_t *ctx, uev_t *w, uev_cb_t *cb, void *arg, int signo)
{ {
int fd;
sigset_t mask; sigset_t mask;
int fd;
if (!w || !ctx) { if (!w || !ctx) {
errno = EINVAL; errno = EINVAL;
@@ -52,15 +61,15 @@ int uev_signal_init(uev_ctx_t *ctx, uev_t *w, uev_cb_t *cb, void *arg, int signo
w->fd = -1; w->fd = -1;
sigemptyset(&mask); sigemptyset(&mask);
fd = signalfd(-1, &mask, SFD_NONBLOCK); fd = signalfd(-1, &mask, SFD_NONBLOCK | SFD_CLOEXEC);
if (fd < 0) if (fd < 0)
return -1; 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; goto exit;
if (uev_signal_set(w, signo)) { if (uev_signal_set(w, signo)) {
uev_watcher_stop(w); _uev_watcher_stop(w);
exit: exit:
close(fd); close(fd);
return -1; return -1;
@@ -74,7 +83,7 @@ int uev_signal_init(uev_ctx_t *ctx, uev_t *w, uev_cb_t *cb, void *arg, int signo
* @param w Watcher to reset * @param w Watcher to reset
* @param signo New signal to watch for * @param signo New signal to watch for
* *
* @return POSIX OK(0) or non-zero with @param errno set on error. * @return POSIX OK(0) or non-zero with @p errno set on error.
*/ */
int uev_signal_set(uev_t *w, int signo) int uev_signal_set(uev_t *w, int signo)
{ {
@@ -91,9 +100,6 @@ int uev_signal_set(uev_t *w, int signo)
/* Handle stopped signal watchers */ /* Handle stopped signal watchers */
if (w->fd < 0) { if (w->fd < 0) {
/* Remove from internal list */
LIST_REMOVE(w, link);
if (uev_signal_init(w->ctx, w, (uev_cb_t *)w->cb, w->arg, signo)) if (uev_signal_init(w->ctx, w, (uev_cb_t *)w->cb, w->arg, signo))
return -1; return -1;
} }
@@ -109,7 +115,7 @@ int uev_signal_set(uev_t *w, int signo)
if (signalfd(w->fd, &mask, SFD_NONBLOCK) < 0) if (signalfd(w->fd, &mask, SFD_NONBLOCK) < 0)
return -1; return -1;
return uev_watcher_start(w); return _uev_watcher_start(w);
} }
@@ -117,7 +123,7 @@ int uev_signal_set(uev_t *w, int signo)
* Start a stopped signal watcher * Start a stopped signal watcher
* @param w Watcher to start (again) * @param w Watcher to start (again)
* *
* @return POSIX OK(0) or non-zero with @param errno set on error. * @return POSIX OK(0) or non-zero with @p errno set on error.
*/ */
int uev_signal_start(uev_t *w) int uev_signal_start(uev_t *w)
{ {
@@ -136,11 +142,14 @@ int uev_signal_start(uev_t *w)
* Stop a signal watcher * Stop a signal watcher
* @param w Watcher to stop * @param w Watcher to stop
* *
* @return POSIX OK(0) or non-zero with @param errno set on error. * @return POSIX OK(0) or non-zero with @p errno set on error.
*/ */
int uev_signal_stop(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; return -1;
close(w->fd); close(w->fd);
@@ -151,7 +160,6 @@ int uev_signal_stop(uev_t *w)
/** /**
* Local Variables: * Local Variables:
* version-control: t
* indent-tabs-mode: t * indent-tabs-mode: t
* c-file-style: "linux" * c-file-style: "linux"
* End: * End:
+55 -33
View File
@@ -1,7 +1,7 @@
/* libuEv - Micro event loop library /* libuEv - Micro event loop library
* *
* Copyright (c) 2012 Flemming Madsen <flemming!madsen()madsensoft!dk> * Copyright (c) 2012 Flemming Madsen <flemming!madsen()madsensoft!dk>
* Copyright (c) 2013-2015 Joachim Nilsson <troglobit()gmail!com> * Copyright (c) 2013-2024 Joachim Wiberg <troglobit()gmail!com>
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
@@ -28,6 +28,11 @@
#include "uev.h" #include "uev.h"
/**
* Monotonic timers, Linux [timerfd(2)](https://man7.org/linux/man-pages/man2/timerfd_create.2.html)
* @file timer.c
*/
static void msec2tspec(int msec, struct timespec *ts) static void msec2tspec(int msec, struct timespec *ts)
{ {
@@ -46,38 +51,50 @@ static void msec2tspec(int msec, struct timespec *ts)
* @param w Pointer to an uev_t watcher * @param w Pointer to an uev_t watcher
* @param cb Callback function * @param cb Callback function
* @param arg Optional callback argument * @param arg Optional callback argument
* @param timeout Timeout in milliseconds before @param cb is called * @param timeout Timeout in milliseconds before @p cb is called
* @param period For periodic timers this is the period time that @param timeout is reset to * @param period For periodic timers this is the period time that @p timeout is reset to
* *
* For one-shot timers you set @param period to zero and only use @param * This function creates, and optionally starts, a timer watcher. There
* timeout. For periodic timers you likely set @param timeout to either * are two types of timers: one-shot and periodic.
* zero, to call it as soon as the event loop starts, or to the same *
* value as @param period. When the timer expires, the @param cb * One-shot timers only use @p timeout, @p period is zero.
* is called, with the optional @param arg argument. A non-periodic *
* timer ends its life there, while a periodic task's @param timeout is * Periodic timers can either start their life disabled, with @p timeout
* reset to the @param period and restarted. * set to zero, or with the same value as @p period.
*
* When the timeout expires, for either of the two types, @p cb is
* called, with the optional @p arg argument. A one-shot timer ends its
* life there, while a periodic task's @p timeout is reset to the @p
* period and restarted.
* *
* A timer is automatically started if the event loop is already * A timer is automatically started if the event loop is already
* running, otherwise it is kept on hold until triggered by calling * running, otherwise it is kept on hold until triggered by calling
* uev_run(). * uev_run().
* *
* @return POSIX OK(0) or non-zero with @param errno set on error. * @see uev_timer_set
* @return POSIX OK(0) or non-zero with @p errno set on error.
*/ */
int uev_timer_init(uev_ctx_t *ctx, uev_t *w, uev_cb_t *cb, void *arg, int timeout, int period) int uev_timer_init(uev_ctx_t *ctx, uev_t *w, uev_cb_t *cb, void *arg, int timeout, int period)
{ {
int fd; int fd;
fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK); if (timeout < 0 || period < 0) {
errno = ERANGE;
return -1;
}
fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK | TFD_CLOEXEC);
if (fd < 0) if (fd < 0)
return -1; 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; goto exit;
if (uev_timer_set(w, timeout, period)) { if (uev_timer_set(w, timeout, period)) {
uev_watcher_stop(w); _uev_watcher_stop(w);
exit: exit:
close(fd); close(fd);
w->fd = -1;
return -1; return -1;
} }
@@ -87,10 +104,14 @@ int uev_timer_init(uev_ctx_t *ctx, uev_t *w, uev_cb_t *cb, void *arg, int timeou
/** /**
* Reset a timer * Reset a timer
* @param w Watcher to reset * @param w Watcher to reset
* @param timeout Timeout in milliseconds before @param cb is called * @param timeout Timeout in milliseconds before @p cb is called, zero disarms timer
* @param period For periodic timers this is the period time that @param timeout is reset to * @param period For periodic timers this is the period time that @p timeout is reset to
* *
* @return POSIX OK(0) or non-zero with @param errno set on error. * Note, the @p timeout value must be non-zero. Setting it to zero
* disarms the timer. This is the behavior of the underlying Linux
* function [timerfd_settimer(2)](https://man7.org/linux/man-pages/man2/timerfd_settime.2.html)
*
* @return POSIX OK(0) or non-zero with @p errno set on error.
*/ */
int uev_timer_set(uev_t *w, int timeout, int period) int uev_timer_set(uev_t *w, int timeout, int period)
{ {
@@ -100,38 +121,41 @@ int uev_timer_set(uev_t *w, int timeout, int period)
return -1; return -1;
} }
if (timeout < 0 || period < 0) {
errno = ERANGE;
return -1;
}
/* Handle stopped timers */ /* Handle stopped timers */
if (w->fd < 0) { if (w->fd < 0) {
/* Timer already stopped */ /* Timer already stopped */
if (!timeout && !period) if (!timeout && !period)
return 0; return 0;
/* Remove from internal list */
LIST_REMOVE(w, link);
if (uev_timer_init(w->ctx, w, (uev_cb_t *)w->cb, w->arg, timeout, period)) if (uev_timer_init(w->ctx, w, (uev_cb_t *)w->cb, w->arg, timeout, period))
return -1; return -1;
} }
w->timeout = timeout; w->u.t.timeout = timeout;
w->period = period; w->u.t.period = period;
if (w->ctx->running) { if (w->ctx->running) {
struct itimerspec time; struct itimerspec time;
msec2tspec(timeout, &time.it_value); msec2tspec(timeout, &time.it_value);
msec2tspec(period, &time.it_interval); msec2tspec(period, &time.it_interval);
timerfd_settime(w->fd, 0, &time, NULL); if (timerfd_settime(w->fd, 0, &time, NULL) < 0)
return 1;
} }
return uev_watcher_start(w); return _uev_watcher_start(w);
} }
/** /**
* Start a stopped timer watcher * Start a stopped timer watcher
* @param w Watcher to start (again) * @param w Watcher to start (again)
* *
* @return POSIX OK(0) or non-zero with @param errno set on error. * @return POSIX OK(0) or non-zero with @p errno set on error.
*/ */
int uev_timer_start(uev_t *w) int uev_timer_start(uev_t *w)
{ {
@@ -141,26 +165,25 @@ int uev_timer_start(uev_t *w)
} }
if (-1 != w->fd) if (-1 != w->fd)
uev_watcher_stop(w); _uev_watcher_stop(w);
return uev_timer_set(w, w->timeout, w->period); return uev_timer_set(w, w->u.t.timeout, w->u.t.period);
} }
/** /**
* Stop and unregister a timer watcher * Stop and unregister a timer watcher
* @param w Watcher to stop * @param w Watcher to stop
* *
* @return POSIX OK(0) or non-zero with @param errno set on error. * @return POSIX OK(0) or non-zero with @p errno set on error.
*/ */
int uev_timer_stop(uev_t *w) int uev_timer_stop(uev_t *w)
{ {
/* Stop kernel timer */ if (!_uev_watcher_active(w))
uev_timer_set(w, 0, 0); return 0;
if (uev_watcher_stop(w)) if (_uev_watcher_stop(w))
return -1; return -1;
/* Close timerfd, will have to be reopened again on reset */
close(w->fd); close(w->fd);
w->fd = -1; w->fd = -1;
@@ -169,7 +192,6 @@ int uev_timer_stop(uev_t *w)
/** /**
* Local Variables: * Local Variables:
* version-control: t
* indent-tabs-mode: t * indent-tabs-mode: t
* c-file-style: "linux" * c-file-style: "linux"
* End: * End:
+445
View File
@@ -0,0 +1,445 @@
/* libuEv - Micro event loop library
*
* Copyright (c) 2012 Flemming Madsen <flemming!madsen()madsensoft!dk>
* Copyright (c) 2013-2024 Joachim Wiberg <troglobit()gmail!com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
/** Micro event loop library
* @file uev.c
*
*/
#include <errno.h>
#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() */
#include "uev.h"
static int _init(uev_ctx_t *ctx, int close_old)
{
int fd;
fd = epoll_create1(EPOLL_CLOEXEC);
if (fd < 0)
return -1;
if (close_old)
close(ctx->fd);
ctx->fd = fd;
return 0;
}
/* Used by file i/o workaround when epoll => EPERM */
static int has_data(int fd)
{
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)
{
if (!ctx || !w) {
errno = EINVAL;
return -1;
}
w->ctx = ctx;
w->type = type;
w->active = 0;
w->fd = fd;
w->cb = cb;
w->arg = arg;
w->events = events;
return 0;
}
/* Private to libuEv, do not use directly! */
int _uev_watcher_start(uev_t *w)
{
struct epoll_event ev;
if (!w || w->fd < 0 || !w->ctx) {
errno = EINVAL;
return -1;
}
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) {
if (errno != EPERM)
return -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 */
_UEV_INSERT(w, w->ctx->watchers);
return 0;
}
/* Private to libuEv, do not use directly! */
int _uev_watcher_stop(uev_t *w)
{
if (!w) {
errno = EINVAL;
return -1;
}
if (!_uev_watcher_active(w))
return 0;
w->active = 0;
/* Remove from internal list */
_UEV_REMOVE(w, w->ctx->watchers);
/* Remove from kernel */
if (epoll_ctl(w->ctx->fd, EPOLL_CTL_DEL, w->fd, NULL) < 0)
return -1;
return 0;
}
/* Private to libuEv, do not use directly! */
int _uev_watcher_active(uev_t *w)
{
if (!w)
return 0;
return w->active > 0;
}
/* Private to libuEv, do not use directly! */
int _uev_watcher_rearm(uev_t *w)
{
struct epoll_event ev;
if (!w || w->fd < 0) {
errno = EINVAL;
return -1;
}
ev.events = w->events | EPOLLRDHUP;
ev.data.ptr = w;
if (epoll_ctl(w->ctx->fd, EPOLL_CTL_MOD, w->fd, &ev) < 0)
return -1;
return 0;
}
/**
* Create an event loop context
* @param ctx Pointer to an uev_ctx_t context to be initialized
*
* This function calls uev_init1() with @p maxevents set to
* ::UEV_MAX_EVENTS
*
* @return POSIX OK(0) on success, or non-zero on error.
*/
int uev_init(uev_ctx_t *ctx)
{
return uev_init1(ctx, UEV_MAX_EVENTS);
}
/**
* Create an event loop context
* @param ctx Pointer to an uev_ctx_t context to be initialized
* @param maxevents Maximum number of events in event cache [1, 10]
*
* This function is the same as uev_init() except for the @p maxevents
* argument, max ::UEV_MAX_EVENTS, which controls the number of events
* in the event cache returned to the main loop.
*
* In cases where you have multiple events pending in the cache and some
* event may cause later ones, already sent by the kernel to userspace,
* to be deleted the pointer returned to the event loop for this later
* event may be deleted.
*
* There are two ways around this (accessing deleted memory):
* -# use this function to initialize your event loop and set
* @p maxevents to 1
* -# use a free list in you application that you garbage collect
* at intervals relevant to your application
*
* @return POSIX OK(0) on success, or non-zero on error.
*/
int uev_init1(uev_ctx_t *ctx, int maxevents)
{
if (!ctx || maxevents < 1) {
errno = EINVAL;
return -1;
}
if (maxevents > UEV_MAX_EVENTS)
maxevents = UEV_MAX_EVENTS;
memset(ctx, 0, sizeof(*ctx));
ctx->maxevents = maxevents;
return _init(ctx, 0);
}
/**
* Terminate the event loop
* @param ctx A valid libuEv context
*
* @return POSIX OK(0) or non-zero with @p errno set on error.
*/
int uev_exit(uev_ctx_t *ctx)
{
uev_t *w;
if (!ctx) {
errno = EINVAL;
return -1;
}
_UEV_FOREACH(w, ctx->watchers) {
/* Remove from internal list */
_UEV_REMOVE(w, ctx->watchers);
if (!_uev_watcher_active(w))
continue;
switch (w->type) {
case UEV_IO_TYPE:
uev_io_stop(w);
break;
case UEV_SIGNAL_TYPE:
uev_signal_stop(w);
break;
case UEV_TIMER_TYPE:
case UEV_CRON_TYPE:
uev_timer_stop(w);
break;
case UEV_EVENT_TYPE:
uev_event_stop(w);
break;
}
}
ctx->watchers = NULL;
ctx->running = 0;
if (ctx->fd > -1)
close(ctx->fd);
ctx->fd = -1;
return 0;
}
/**
* Start the event loop
* @param ctx A valid libuEv context
* @param flags A mask of ::UEV_ONCE and ::UEV_NONBLOCK, or zero
*
* With @p flags set to ::UEV_ONCE the event loop returns after the first
* event has been served, useful for instance to set a timeout on a file
* descriptor. If @p flags also has the ::UEV_NONBLOCK flag set the event
* loop will return immediately if no event is pending, useful when run
* inside another event loop.
*
* @return POSIX OK(0) upon successful termination of the event loop, or
* non-zero on error.
*/
int uev_run(uev_ctx_t *ctx, int flags)
{
int timeout = -1;
uev_t *w;
if (!ctx || ctx->fd < 0) {
errno = EINVAL;
return -1;
}
if (flags & UEV_NONBLOCK)
timeout = 0;
/* Start the event loop */
ctx->running = 1;
/* Start all dormant timers */
_UEV_FOREACH(w, ctx->watchers) {
if (UEV_CRON_TYPE == w->type)
uev_cron_set(w, w->u.c.when, w->u.c.interval);
if (UEV_TIMER_TYPE == w->type)
uev_timer_set(w, w->u.t.timeout, w->u.t.period);
}
while (ctx->running && ctx->watchers) {
struct epoll_event ee[UEV_MAX_EVENTS];
int maxevents = ctx->maxevents;
int i, nfds, rerun = 0;
if (maxevents > UEV_MAX_EVENTS)
maxevents = UEV_MAX_EVENTS;
/* Handle special case: `application < file.txt` */
if (ctx->workaround) {
_UEV_FOREACH(w, ctx->watchers) {
if (w->active != -1 || !w->cb)
continue;
if (!has_data(w->fd)) {
w->active = 0;
_UEV_REMOVE(w, ctx->watchers);
}
rerun++;
w->cb(w, w->arg, UEV_READ);
}
}
if (rerun)
continue;
ctx->workaround = 0;
while ((nfds = epoll_wait(ctx->fd, ee, maxevents, timeout)) < 0) {
if (!ctx->running)
break;
if (EINTR == errno)
continue; /* Signalled, try again */
/* Unrecoverable error, cleanup and exit with error. */
uev_exit(ctx);
return -2;
}
for (i = 0; ctx->running && i < nfds; i++) {
struct signalfd_siginfo fdsi;
ssize_t sz = sizeof(fdsi);
uint32_t events;
uint64_t exp;
w = (uev_t *)ee[i].data.ptr;
events = ee[i].events;
switch (w->type) {
case UEV_IO_TYPE:
if (events & (EPOLLHUP | EPOLLERR))
uev_io_stop(w);
break;
case UEV_SIGNAL_TYPE:
if (read(w->fd, &fdsi, sz) != sz) {
if (uev_signal_start(w)) {
uev_signal_stop(w);
events = UEV_ERROR;
}
memset(&w->siginfo, 0, sizeof(w->siginfo));
} else
w->siginfo = fdsi;
break;
case UEV_TIMER_TYPE:
if (read(w->fd, &exp, sizeof(exp)) != sizeof(exp)) {
uev_timer_stop(w);
events = UEV_ERROR;
}
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 (!w->u.c.when)
uev_timer_stop(w);
break;
case UEV_EVENT_TYPE:
if (read(w->fd, &exp, sizeof(exp)) != sizeof(exp))
events = UEV_HUP;
break;
}
/*
* 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)
break;
}
return 0;
}
/**
* Local Variables:
* indent-tabs-mode: t
* c-file-style: "linux"
* End:
*/
+138
View File
@@ -0,0 +1,138 @@
/* libuEv - Micro event loop library
*
* Copyright (c) 2012 Flemming Madsen <flemming!madsen()madsensoft!dk>
* Copyright (c) 2013-2024 Joachim Wiberg <troglobit()gmail!com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
/**
* Micro event loop library
* @file uev.h
* @author Flemming Madsen (2012)
* @author Joachim Wiberg (2013-2021)
* @copyright MIT License
*
* The latest version of this manual and the libuEv software are
* available at https://github.com/troglobit/libuEv/
*/
#ifndef LIBUEV_UEV_H_
#define LIBUEV_UEV_H_
#include "private.h"
#define UEV_MAX_EVENTS 10 /**< Max. number of simulateneous events */
/* I/O events, signal and timer revents are always UEV_READ */
#define UEV_NONE 0 /**< normal loop */
#define UEV_ERROR EPOLLERR /**< error flag */
#define UEV_READ EPOLLIN /**< poll for reading */
#define UEV_WRITE EPOLLOUT /**< poll for writing */
#define UEV_PRI EPOLLPRI /**< priority message */
#define UEV_HUP EPOLLHUP /**< hangup event */
#define UEV_RDHUP EPOLLRDHUP /**< peer shutdown */
#define UEV_EDGE EPOLLET /**< edge triggered */
#define UEV_ONESHOT EPOLLONESHOT /**< one-shot event */
/* Run flags */
#define UEV_ONCE 1 /**< run loop once */
#define UEV_NONBLOCK 2 /**< exit if no event */
/** Check if I/O watcher is active or stopped */
#define uev_io_active(w) _uev_watcher_active(w)
/** Check if signal watcher is active or stopped */
#define uev_signal_active(w) _uev_watcher_active(w)
/** Check if timer is active or stopped */
#define uev_timer_active(w) _uev_watcher_active(w)
/** Check if cron timer watcher is active or stopped */
#define uev_cron_active(w) _uev_watcher_active(w)
/** Check if event watcher is active or stopped */
#define uev_event_active(w) _uev_watcher_active(w)
/** Event loop context, need one per process and thread */
typedef struct uev_ctx uev_ctx_t;
/** Event watcher */
typedef struct uev {
/* Private data for libuEv internal engine */
uev_private_t type;
/* Public data for users to reference */
int signo; /**< configured signal */
int fd; /**< active descriptor */
uev_ctx_t *ctx; /**< watcher context */
/* Extra data for certain watcher types */
struct signalfd_siginfo siginfo; /**< received signal */
} uev_t;
/**
* Generic callback for watchers, @p 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 and peer shutdown 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);
/* Public interface */
/** Create an event loop context */
int uev_init (uev_ctx_t *ctx);
int uev_init1 (uev_ctx_t *ctx, int maxevents);
int uev_exit (uev_ctx_t *ctx);
int uev_run (uev_ctx_t *ctx, int flags);
int uev_io_init (uev_ctx_t *ctx, uev_t *w, uev_cb_t *cb, void *arg, int fd, int events);
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);
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);
int uev_timer_start (uev_t *w);
int uev_timer_stop (uev_t *w);
int uev_cron_init (uev_ctx_t *ctx, uev_t *w, uev_cb_t *cb, void *arg, time_t when, time_t interval);
int uev_cron_set (uev_t *w, time_t when, time_t interval);
int uev_cron_start (uev_t *w);
int uev_cron_stop (uev_t *w);
int uev_signal_init (uev_ctx_t *ctx, uev_t *w, uev_cb_t *cb, void *arg, int signo);
int uev_signal_set (uev_t *w, int signo);
int uev_signal_start (uev_t *w);
int uev_signal_stop (uev_t *w);
int uev_event_init (uev_ctx_t *ctx, uev_t *w, uev_cb_t *cb, void *arg);
int uev_event_post (uev_t *w);
int uev_event_stop (uev_t *w);
#endif /* LIBUEV_UEV_H_ */
/**
* Local Variables:
* indent-tabs-mode: t
* c-file-style: "linux"
* End:
*/
+9
View File
@@ -0,0 +1,9 @@
*.trs
*.log
active
api
complete
cronrun
signal
timer
event
+16
View File
@@ -0,0 +1,16 @@
EXTRA_DIST = check.h
CLEANFILES = *~ *.trs *.log
AM_CFLAGS = -W -Wall -Wextra -Wno-unused-result -Wno-unused-parameter
AM_CPPFLAGS = -D_GNU_SOURCE -D_TIME_BITS=64 -D_FILE_OFFSET_BITS=64
AM_LDFLAGS = -L../src ../src/libuev.la
TESTS =
TESTS += active
TESTS += api
TESTS += complete
TESTS += cronrun
TESTS += signal
TESTS += timer
TESTS += event
check_PROGRAMS = $(TESTS)
+64
View File
@@ -0,0 +1,64 @@
#include "check.h"
#include <time.h>
#include <sys/time.h>
#define TIMEOUT1 2 /* 2 sec */
#define TIMEOUT2 4 /* 4 sec */
#define DAYLY (24 * 60 * 60) /* Seconds in one day */
uev_t timer1;
uev_t timer2;
uev_t timer3;
uev_t cron1;
uev_t cron2;
static void cb(uev_t *w, void *arg, int events)
{
if (UEV_ERROR == events)
fprintf(stderr, "timer watcher failed, ignoring ...\n");
fail_unless(w == &timer1);
fail_unless(uev_timer_active(&timer2));
fail_unless(!uev_timer_active(&timer3));
fail_unless(uev_cron_active(&cron1));
fail_unless(uev_cron_active(&cron2));
uev_timer_stop(&timer2);
uev_timer_stop(&cron2);
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);
}
int main(void)
{
struct timeval tomorrow;
uev_ctx_t ctx;
gettimeofday(&tomorrow, NULL);
tomorrow.tv_sec += 24 * 60 * 60;
uev_init(&ctx);
uev_timer_init(&ctx, &timer1, cb, NULL, TIMEOUT1 * 1000, 0);
uev_timer_init(&ctx, &timer2, cb, NULL, TIMEOUT2 * 1000, 0);
uev_timer_init(&ctx, &timer3, cb, NULL, TIMEOUT2 * 1000, 0);
uev_timer_stop(&timer3);
uev_cron_init(&ctx, &cron1, cb, NULL, tomorrow.tv_sec, 24 * 60 * 60);
uev_cron_init(&ctx, &cron2, cb, NULL, tomorrow.tv_sec, 24 * 60 * 60);
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 *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;
}
+79
View File
@@ -0,0 +1,79 @@
#ifndef UEV_TEST_CHECK_H_
#define UEV_TEST_CHECK_H_
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include "../src/uev.h"
#define fail_unless(test) \
do { \
if (!(test)) { \
fprintf(stderr, \
"----------------------------------------------\n" \
"%s:%d: test FAILED:\nFailed test: %s\n" \
"----------------------------------------------\n", \
__FILE__, __LINE__, #test); \
exit(1); \
} \
} while (0)
static inline int test(int result, const char *fmt, ...)
{
char buf[80];
size_t len;
va_list ap;
const char success[] = " \033[1m[ OK ]\033[0m\n";
const char failure[] = " \033[7m[FAIL]\033[0m\n";
const char dots[] = " .....................................................................";
va_start(ap, fmt);
len = vsnprintf(buf, sizeof(buf), fmt, ap);
va_end(ap);
write(STDERR_FILENO, buf, len);
write(STDERR_FILENO, dots, 60 - len); /* pad with dots. */
if (!result)
write(STDERR_FILENO, success, strlen(success));
else
write(STDERR_FILENO, failure, strlen(failure));
return result;
}
static inline int timespec_newer(const struct timespec *a, const struct timespec *b)
{
if (a->tv_sec != b->tv_sec)
return a->tv_sec > b->tv_sec;
return a->tv_nsec > b->tv_nsec;
}
static inline char *timespec2str(struct timespec *ts, char *buf, size_t len)
{
size_t ret, pos;
struct tm t;
memset(buf, 0, len);
tzset();
if (localtime_r(&(ts->tv_sec), &t) == NULL)
return buf;
ret = strftime(buf, len, "%F %T", &t);
if (ret == 0)
return buf;
len -= ret - 1;
pos = strlen(buf);
len -= pos;
snprintf(&buf[pos], len, ".%09ld", ts->tv_nsec);
return buf;
}
#endif /* UEV_TEST_CHECK_H_ */
+54 -27
View File
@@ -1,7 +1,7 @@
/* Test libuEv event library /* Test libuEv event library
* *
* Copyright (c) 2012 Flemming Madsen <flemming!madsen()madsensoft!dk> * Copyright (c) 2012 Flemming Madsen <flemming!madsen()madsensoft!dk>
* Copyright (c) 2013-2015 Joachim Nilsson <troglobit()gmail!com> * Copyright (c) 2013-2024 Joachim Wiberg <troglobit()gmail!com>
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
@@ -22,14 +22,8 @@
* THE SOFTWARE. * THE SOFTWARE.
*/ */
#include "check.h"
#include <signal.h> #include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h> /* intptr_t */
#include "uev.h"
#define UNUSED(arg) arg __attribute__ ((unused))
typedef struct { typedef struct {
int counter; int counter;
@@ -39,15 +33,21 @@ static int in, out;
static int period = 0; static int period = 0;
static uev_t *watchdog; 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); fprintf(stderr, "\nLifetime exceeded, program completed successfully! (arg:%p)\n", arg);
uev_exit(w->ctx); uev_exit(w->ctx);
} }
/* The pipe watchdog, if it triggers we haven't received data in time. */ /* 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; watchdog = NULL;
fprintf(stderr, "\nTimeout exceeded %p\n", arg); fprintf(stderr, "\nTimeout exceeded %p\n", arg);
@@ -55,39 +55,66 @@ static void timeout_cb(uev_t *w, void *arg, int UNUSED(events))
uev_exit(w->ctx); uev_exit(w->ctx);
} }
static void periodic_task(uev_t UNUSED(*w), void UNUSED(*arg), int UNUSED(events)) static void periodic_task(uev_t *w, void *arg, int events)
{ {
fprintf(stderr, "|"); fprintf(stderr, "|");
} }
static void signal_cb(uev_t *w, void *UNUSED(arg), int UNUSED(events)) static void signal_cb(uev_t *w, void *arg, int events)
{ {
if (UEV_ERROR == events) {
fprintf(stderr, "Signal watcher failed, unrecoverable error.\n");
return;
}
fprintf(stderr, w->signo == SIGINT ? "^Cv" : "^\v"); 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 *arg, int events)
{ {
int cnt; int len;
char msg[50]; 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) if (watchdog)
uev_timer_set(watchdog, 1000, 0); uev_timer_set(watchdog, 1000, 0);
cnt = read(in, msg, sizeof(msg)); /* Here we can read() from in or w->fd, either works. */
// fprintf(stderr, "READ %.*s %d\n", cnt, msg, cnt); len = read(w->fd, msg, sizeof(msg));
fprintf(stderr, "%.*s.%d ", cnt, msg, cnt); 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)) static void pipe_write_cb(uev_t *w, void *arg, int events)
{ {
my_t *my = arg; my_t *my = arg;
char *msg = "TESTING"; 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) { if (write(out, msg, my->counter) < 0) {
perror("\nFailed writing to pipe"); perror("\nFailed writing to pipe");
return; return;
} }
// fprintf(stderr, "WRITE %.*s %d\n", my->counter, msg, my->counter); // fprintf(stderr, "WRITE %.*s %d\n", my->counter, msg, my->counter);
fprintf(stderr, "%d ", my->counter); fprintf(stderr, "%d ", my->counter);
@@ -126,8 +153,10 @@ int main(void)
uev_io_init(&ctx, &reader, pipe_read_cb, NULL, in, UEV_READ); uev_io_init(&ctx, &reader, pipe_read_cb, NULL, in, UEV_READ);
uev_timer_init(&ctx, &writer, pipe_write_cb, &my, 400, 0); uev_timer_init(&ctx, &writer, pipe_write_cb, &my, 400, 0);
/* Watchdog for the above timer callback, if it doesn't wake up /*
* and write to the pipe within a given deadline it will bark. */ * Watchdog for the above timer callback, if it doesn't wake up
* and write to the pipe within a given deadline it will bark.
*/
uev_timer_init(&ctx, &wdt, timeout_cb, (void *)(intptr_t)1, 950, 0); uev_timer_init(&ctx, &wdt, timeout_cb, (void *)(intptr_t)1, 950, 0);
watchdog = &wdt; watchdog = &wdt;
@@ -138,15 +167,13 @@ int main(void)
uev_run(&ctx, 0); uev_run(&ctx, 0);
fprintf(stderr, "Period is %d must be 10: %s\n", period, 10 == period ? "OK" : "ERROR!"); fprintf(stderr, "Period is %d must be 10: %s\n", period, 10 == period ? "OK" : "ERROR!");
if (10 != period) fail_unless(10 == period);
return 1;
return 0; return 0;
} }
/** /**
* Local Variables: * Local Variables:
* version-control: t
* indent-tabs-mode: t * indent-tabs-mode: t
* c-file-style: "linux" * c-file-style: "linux"
* End: * End:
+84
View File
@@ -0,0 +1,84 @@
/* Test cron API in libuEv event library
*
* Copyright (c) 2016-2024 Joachim Wiberg <troglobit()gmail!com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "check.h"
#include <time.h>
#include <sys/time.h>
#define TIMEOUT 2
#define INTERVAL 2
int result = -1;
struct timeval tv;
static void cron_job(uev_t *w, void *arg, int events)
{
struct timeval now;
static int laps = 3;
if (UEV_ERROR == events)
fprintf(stderr, "cron watcher failed, ignoring ...\n");
/* Update timer every lap */
tv.tv_sec += TIMEOUT;
gettimeofday(&now, NULL);
printf("Cron job HELO %s", ctime(&now.tv_sec));
fail_unless(now.tv_sec == tv.tv_sec);
if (!laps--) {
result = 0;
uev_exit(w->ctx);
}
}
int main(void)
{
uev_ctx_t ctx;
time_t when, interval;
uev_t cron;
int rc;
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));
interval = INTERVAL;
uev_cron_init(&ctx, &cron, cron_job, NULL, when, interval);
rc = uev_run(&ctx, 0);
fail_unless(result == 0);
return rc;
}
/**
* Local Variables:
* indent-tabs-mode: t
* c-file-style: "linux"
* End:
*/
+78
View File
@@ -0,0 +1,78 @@
/* Verifies eventfd support
*
* Copyright (c) 2018-2024 Joachim Wiberg <troglobit@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "check.h"
#include <err.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
#define LAPS 10
pid_t pid;
static void cb(uev_t *w, void *arg, int events)
{
static int num = LAPS;
num--;
// printf("Got event %d ...\n", LAPS - num);
if (num == 0) {
waitpid(pid, NULL, 0);
uev_exit(w->ctx);
}
}
int main(void)
{
uev_ctx_t ctx;
uev_t ev;
int i;
/* Initialize libuEv */
uev_init(&ctx);
/* Setup callbacks */
uev_event_init(&ctx, &ev, cb, NULL);
pid = fork();
if (-1 == pid)
err(1, "fork");
/* Start event loop */
if (pid > 0)
return uev_run(&ctx, 0);
for (i = 0; i < LAPS; i++) {
uev_event_post(&ev);
usleep(10000);
}
return 0;
}
/**
* Local Variables:
* indent-tabs-mode: t
* c-file-style: "linux"
* End:
*/
+55 -47
View File
@@ -1,6 +1,6 @@
/* Multiple signals, segfault and fork() to test sub-processes. /* Multiple signals, segfault and fork() to test sub-processes.
* *
* Copyright (c) 2015 Joachim Nilsson <troglobit@gmail.com> * Copyright (c) 2015-2024 Joachim Wiberg <troglobit@gmail.com>
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
@@ -21,7 +21,7 @@
* THE SOFTWARE. * THE SOFTWARE.
*/ */
#define _GNU_SOURCE #include "check.h"
#include <err.h> #include <err.h>
#include <sched.h> #include <sched.h>
#include <signal.h> #include <signal.h>
@@ -33,12 +33,10 @@
#include <sys/wait.h> #include <sys/wait.h>
#include <unistd.h> #include <unistd.h>
#include "uev.h"
#define UNUSED(arg) arg __attribute__ ((unused))
#define DO_SEGFAULT 1 #define DO_SEGFAULT 1
typedef struct { typedef struct {
pid_t pid;
int magic; int magic;
void *ptr; void *ptr;
} arg_t; } arg_t;
@@ -51,10 +49,10 @@ static arg_t arg = {
static int callback(arg_t *arg, int event, void *foo) static int callback(arg_t *arg, int event, void *foo)
{ {
arg_t *event_arg = (arg_t *)foo; arg_t *event_arg = (arg_t *)foo;
printf("child: got magic %d and ptr %p, with event %d and event arg %p\n", printf("child[%d] magic %d ptr %p, event %d event arg %p\n",
arg->magic, arg->ptr, event, event_arg); getpid(), arg->magic, arg->ptr, event, event_arg);
arg->magic = 7331; arg->magic = 7331;
arg->ptr = &event_arg; arg->ptr = &event_arg;
@@ -65,68 +63,79 @@ static int callback(arg_t *arg, int event, void *foo)
printf("child: segfaulting failed!\n"); printf("child: segfaulting failed!\n");
#endif #endif
return 42; return 42;
} }
static void sigsegv_cb(uev_t *UNUSED(w), void *UNUSED(arg), int UNUSED(events)) static void sig_cb(uev_t *w, void *cbarg, int events)
{ {
warnx("PID %d caused segfault.", getpid()); arg_t *arg = (arg_t *)cbarg;
exit(-1);
switch (w->signo) {
case SIGSEGV:
// printf("Got SIGSEGV (%d) from PID %d\n", w->siginfo.ssi_signo, w->siginfo.ssi_pid);
warnx("PID %d caused segfault.", getpid());
exit(-1);
break;
case SIGCHLD:
if (arg->pid != (pid_t)w->siginfo.ssi_pid)
err(1, "wrong child exited pid %d vs ssi_pid %d",
arg->pid, w->siginfo.ssi_pid);
warnx("Got SIGCHLD (%d), PID %d exited, bye.", w->siginfo.ssi_signo, arg->pid);
break;
default:
err(1, "unhandled signal %d", w->siginfo.ssi_signo);
}
} }
static void sigchld_cb(uev_t *UNUSED(w), void *UNUSED(arg), int UNUSED(events)) static void work_cb(uev_t *w, void *cbarg, int events)
{ {
pid_t pid = waitpid(-1, NULL, WNOHANG); arg_t *arg = (arg_t *)cbarg;
pid_t pid;
int rc = 0;
if (-1 != pid) pid = fork();
warnx("PID %d exited, bye.", pid); if (-1 == pid)
} err(1, "fork");
if (!pid)
exit(callback(arg, 6137, NULL));
static void work_cb(uev_t *UNUSED(w), void *arg, int UNUSED(events)) arg->pid = pid;
{ pid = waitpid(pid, &rc, 0);
int status = 0; if (pid == -1)
pid_t pid; err(1, "waitpid");
pid = fork(); if (WIFEXITED(rc))
if (-1 == pid) printf("Child %d exited normally => %d\n", pid, WEXITSTATUS(rc));
err(1, "fork"); else if (WCOREDUMP(rc))
if (!pid) { printf("Child %d crashed%s\n", pid, DO_SEGFAULT
status = callback(arg, 6137, NULL); ? ", as expected, everything is OK."
exit(status); : ". This should not happen!");
}
if (waitpid(pid, &status, 0) == -1)
err(1, "waitpid");
if (WIFEXITED(status))
printf("Child exited normally => %d\n", WEXITSTATUS(status));
else if (WCOREDUMP(status))
printf("Child crashed! %s\n", DO_SEGFAULT
? "As expected, everything is OK."
: "This should not happen!");
else else
printf("Child did not exit normally!\n"); printf("Child %d did not exit normally!\n", pid);
} }
static void exit_cb(uev_t *w, void *UNUSED(arg), int UNUSED(events)) static void exit_cb(uev_t *w, void *arg, int events)
{ {
printf("Process deadline reached, exiting!\n"); printf("Process deadline reached, exiting!\n");
uev_exit(w->ctx); uev_exit(w->ctx);
} }
int main(void) int main(void)
{ {
uev_t sigsegv_watcher, sigchld_watcher, timeout_watcher, deadline_watcher; uev_t deadline, sigsegv, sigchld, timeout;
uev_ctx_t ctx; uev_ctx_t ctx;
/* Initialize libuEv */ /* Initialize libuEv */
uev_init(&ctx); uev_init(&ctx);
/* Setup callbacks */ /* Setup callbacks */
uev_signal_init(&ctx, &sigsegv_watcher, sigsegv_cb, NULL, SIGSEGV); uev_signal_init(&ctx, &sigsegv, sig_cb, NULL, SIGSEGV);
uev_signal_init(&ctx, &sigchld_watcher, sigchld_cb, NULL, SIGCHLD); uev_signal_init(&ctx, &sigchld, sig_cb, &arg, SIGCHLD);
uev_timer_init(&ctx, &timeout_watcher, work_cb, &arg, 400, 0); uev_timer_init(&ctx, &timeout, work_cb, &arg, 400, 0);
uev_timer_init(&ctx, &deadline_watcher, exit_cb, NULL, 1000, 0); uev_timer_init(&ctx, &deadline, exit_cb, NULL, 1000, 0);
/* Start event loop */ /* Start event loop */
return uev_run(&ctx, 0); return uev_run(&ctx, 0);
@@ -134,7 +143,6 @@ int main(void)
/** /**
* Local Variables: * Local Variables:
* version-control: t
* indent-tabs-mode: t * indent-tabs-mode: t
* c-file-style: "linux" * c-file-style: "linux"
* End: * End:
+45
View File
@@ -0,0 +1,45 @@
#include "check.h"
#include <time.h>
#include <sys/time.h>
#define TIMEOUT 2 /* 2 sec */
int result = -1;
struct timeval start;
static void cb(uev_t *w, void *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)
{
uev_ctx_t ctx;
uev_t w;
int rc;
uev_init(&ctx);
uev_timer_init(&ctx, &w, cb, NULL, TIMEOUT * 1000, 0);
gettimeofday(&start, NULL);
rc = uev_run(&ctx, 0);
fail_unless(result == 0);
return rc;
}
/**
* Local Variables:
* indent-tabs-mode: t
* c-file-style: "linux"
* End:
*/
-321
View File
@@ -1,321 +0,0 @@
/* libuEv - Micro event loop library
*
* Copyright (c) 2012 Flemming Madsen <flemming!madsen()madsensoft!dk>
* Copyright (c) 2013-2015 Joachim Nilsson <troglobit()gmail!com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <errno.h>
#include <fcntl.h> /* O_CLOEXEC */
#include <string.h> /* memset() */
#include <sys/epoll.h>
#include <sys/signalfd.h> /* struct signalfd_siginfo */
#include <unistd.h> /* close(), read() */
#include "uev.h"
#define UNUSED(arg) arg __attribute__ ((unused))
static int _init(uev_ctx_t *ctx, int close_old)
{
int fd = epoll_create1(EPOLL_CLOEXEC);
if (fd < 0)
return -1;
if (close_old)
close(ctx->fd);
ctx->fd = fd;
return 0;
}
/* Simple check if a descriptor is still valid in the kernel */
static int is_valid_fd(int fd)
{
return fcntl(fd, F_GETFL) != -1 || errno != EBADF;
}
/* 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)
{
if (!ctx || !w) {
errno = EINVAL;
return -1;
}
w->ctx = ctx;
w->type = type;
w->active = 0;
w->fd = fd;
w->cb = (void *)cb;
w->arg = arg;
w->events = events;
return 0;
}
/* Private to libuEv, do not use directly! */
int uev_watcher_start(uev_t *w)
{
struct epoll_event ev;
if (!w || w->fd < 0) {
errno = EINVAL;
return -1;
}
if (w->active)
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;
w->active = 1;
/* Add to internal list for bookkeeping */
LIST_INSERT_HEAD(&w->ctx->watchers, w, link);
return 0;
}
/* Private to libuEv, do not use directly! */
int uev_watcher_stop(uev_t *w)
{
if (!w) {
errno = EINVAL;
return -1;
}
if (!w->active)
return 0;
w->active = 0;
/* Remove from internal list */
LIST_REMOVE(w, link);
/* Remove from kernel */
if (epoll_ctl(w->ctx->fd, EPOLL_CTL_DEL, w->fd, NULL) < 0)
return -1;
return 0;
}
/**
* Create an event loop context
* @param ctx Pointer to an uev_ctx_t context to be initialized
*
* @return POSIX OK(0) on success, or non-zero on error.
*/
int uev_init(uev_ctx_t *ctx)
{
if (!ctx) {
errno = EINVAL;
return -1;
}
memset(ctx, 0, sizeof(*ctx));
LIST_INIT(&ctx->watchers);
return _init(ctx, 0);
}
/**
* Terminate the event loop
* @param ctx A valid libuEv context
*
* @return POSIX OK(0) or non-zero with @param errno set on error.
*/
int uev_exit(uev_ctx_t *ctx)
{
if (!ctx) {
errno = EINVAL;
return -1;
}
while (!LIST_EMPTY(&ctx->watchers)) {
uev_t *w = LIST_FIRST(&ctx->watchers);
/* Remove from internal list */
LIST_REMOVE(w, link);
if (!w->active)
continue;
switch (w->type) {
case UEV_TIMER_TYPE:
uev_timer_stop(w);
break;
case UEV_SIGNAL_TYPE:
uev_signal_stop(w);
break;
case UEV_IO_TYPE:
uev_io_stop(w);
break;
}
}
ctx->running = 0;
close(ctx->fd);
ctx->fd = -1;
return 0;
}
/**
* Start the event loop
* @param ctx A valid libuEv context
* @param flags A mask of %UEV_ONCE and %UEV_NONBLOCK, or zero
*
* With @flags set to %UEV_ONCE the event loop returns after the first
* event has been served, useful for instance to set a timeout on a file
* descriptor. If @flags also has the %UEV_NONBLOCK flag set the event
* loop will return immediately if no event is pending, useful when run
* inside another event loop.
*
* @return POSIX OK(0) upon successful termination of the event loop, or
* non-zero on error.
*/
int uev_run(uev_ctx_t *ctx, int flags)
{
int result = 0, timeout = -1;
uev_t *w;
if (!ctx || ctx->fd < 0) {
errno = EINVAL;
return -1;
}
if (flags & UEV_NONBLOCK)
timeout = 0;
/* Start the event loop */
ctx->running = 1;
/* Start all dormant timers */
LIST_FOREACH(w, &ctx->watchers, link) {
if (UEV_TIMER_TYPE == w->type)
uev_timer_set(w, w->timeout, w->period);
}
while (ctx->running) {
int i, nfds;
struct epoll_event events[UEV_MAX_EVENTS];
while ((nfds = epoll_wait(ctx->fd, events, UEV_MAX_EVENTS, timeout)) < 0) {
if (!ctx->running)
break;
if (EINTR == errno)
continue; /* Signalled, try again */
/* Unrecoverable error, cleanup and exit with error. */
uev_exit(ctx);
return -1;
}
for (i = 0; ctx->running && i < nfds; i++) {
w = (uev_t *)events[i].data.ptr;
if (events[i].events & (EPOLLHUP | EPOLLERR)) {
ctx->errors++;
if (ctx->errors >= 42) {
uev_t *tmp, *retry = w;;
/* 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;
}
/* 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_TIMER_TYPE == w->type) {
uint64_t exp;
if (read(w->fd, &exp, sizeof(exp)) != sizeof(exp)) {
uev_exit(ctx);
return -3;
}
if (!w->period)
w->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_TIMER_TYPE == w->type) {
if (!w->timeout)
uev_timer_stop(w);
}
}
if ((flags & UEV_ONCE) || LIST_EMPTY(&ctx->watchers))
break;
}
return result;
}
/**
* Local Variables:
* version-control: t
* indent-tabs-mode: t
* c-file-style: "linux"
* End:
*/
-84
View File
@@ -1,84 +0,0 @@
/* libuEv - Micro event loop library
*
* Copyright (c) 2012 Flemming Madsen <flemming!madsen()madsensoft!dk>
* Copyright (c) 2013-2015 Joachim Nilsson <troglobit()gmail!com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef LIBUEV_UEV_H_
#define LIBUEV_UEV_H_
#include "private.h"
/* Max. number of simulateneous events */
#define UEV_MAX_EVENTS 10
/* I/O events, for signals and timers revents will always be UEV_READ */
#define UEV_NONE 0
#define UEV_READ EPOLLIN
#define UEV_WRITE EPOLLOUT
#define UEV_PRI EPOLLPRI
/* Run flags */
#define UEV_ONCE 1
#define UEV_NONBLOCK 2
/* Event watcher */
typedef struct uev {
/* Private data for libuEv internal engine */
uev_private_t type;
/* Public data for users to reference */
int fd;
uev_ctx_t *ctx;
} uev_t;
/* Generic callback for watchers */
typedef void (uev_cb_t)(uev_t *w, void *arg, int events);
/* Public interface */
int uev_init (uev_ctx_t *ctx);
int uev_exit (uev_ctx_t *ctx);
int uev_run (uev_ctx_t *ctx, int flags);
int uev_io_init (uev_ctx_t *ctx, uev_t *w, uev_cb_t *cb, void *arg, int fd, int events);
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);
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);
int uev_timer_start (uev_t *w);
int uev_timer_stop (uev_t *w);
int uev_signal_init (uev_ctx_t *ctx, uev_t *w, uev_cb_t *cb, void *arg, int signo);
int uev_signal_set (uev_t *w, int signo);
int uev_signal_start (uev_t *w);
int uev_signal_stop (uev_t *w);
#endif /* LIBUEV_UEV_H_ */
/**
* Local Variables:
* version-control: t
* indent-tabs-mode: t
* c-file-style: "linux"
* End:
*/