34 Commits
Author SHA1 Message Date
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
22 changed files with 580 additions and 85 deletions

No files matched your search

+2 -1
View File
@@ -6,6 +6,7 @@
*.a
*.la
*.lo
*.html
.deps
.libs
compile
@@ -23,7 +24,7 @@ aclocal.m4
ar-lib
autom4te.cache
bench
test
libuev*.tar.*
libuev.pc
!libuev.pc.in
test-driver
+4 -5
View File
@@ -2,7 +2,7 @@
# Defaults to GNU GCC and autotools: ./configure && make && make test
language: c
# We don't need to install packages, use dockerized build, quicker
# Use docker for quicker builds, it now allows https://docs.travis-ci.com/user/apt/
sudo: false
env:
@@ -17,14 +17,13 @@ addons:
name: "troglobit/libuev"
description: "libuEv | Simple event loop for Linux"
notification_email: troglobit@gmail.com
build_command_prepend: "./autogen && ./configure --enable-examples"
build_command_prepend: "./autogen && ./configure"
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
- ./configure --disable-silent-rules
- make clean
- make -j5
- make test
- make check
+26
View File
@@ -3,6 +3,32 @@ Change Log
All notable changes to the project are documented in this file.
[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
### Fixes
- Fix `uev_timer_set()` so that it returns error in case the underlying
Linux timerfd API fails.
[v1.4.2][] - 2016-06-25
-----------------------
+10 -26
View File
@@ -1,39 +1,23 @@
ACLOCAL_AMFLAGS = -I m4
lib_LTLIBRARIES = libuev.la
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_SOURCES = uev.c io.c timer.c signal.c cron.c
libuev_la_CPPFLAGS = -D_GNU_SOURCE
libuev_la_CFLAGS = -W -Wall -Wextra
libuev_la_LDFLAGS = $(AM_LDFLAGS) -version-info 1:1:0
libuev_la_LDFLAGS = $(AM_LDFLAGS) -version-info 1:2: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 queue.h
doc_DATA = README.md LICENSE
EXTRA_DIST = README.md LICENSE AUTHORS ChangeLog.md
DIST_SUBDIRS = examples
SUBDIRS = .
if ENABLE_EXAMPLES
SUBDIRS += examples
endif
test joystick: all-recursive
./examples/$@
check-local:
@echo " BENCH $(PACKAGE)"
@./bench
if ENABLE_EXAMPLES
@echo " TEST $(PACKAGE)"
@./examples/test
endif
DIST_SUBDIRS = examples tests
SUBDIRS = tests
## Generate MD5 checksum file
MD5 = md5sum
+25 -10
View File
@@ -35,17 +35,25 @@ For details, see [this article][4] at [lwn.net](http://lwn.net).
API
---
The C interface to [libuEv][] is listed in `uev.h`. It handles three
different types of events: I/O (files, sockets, message queues, etc.),
timers, and signals. With a slight caveat on signals detailed below
in the [Summary](#summary).
The C API to [libuEv][], listed in `uev/uev.h`, handles three different
types of events: I/O (files, sockets, message queues, etc.), timers, and
signals. The [Summary](#summary) details a slight caveat on signals.
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 systems in particular, `time_t` is a
32-bit integer that wraps around in the year 2038. [libuEv][] cannot
protect you against this problem, unfortunately.
```C
/*
* Callback example, arg is passed from watcher's *_init()
* w->fd holds the file descriptor, events is set by libuEv
* to indicate if any of UEV_READ and/or UEV_WRITE is ready.
* 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_HUP, UEV_READ and/or UEV_WRITE
*/
void callback (uev_t *w, void *arg, int events);
@@ -60,12 +68,18 @@ in the [Summary](#summary).
int uev_io_start (uev_t *w);
int uev_io_stop (uev_t *w);
/* Timer watcher: timeout and period in milliseconds */
/* Timer watcher: schedule a relative timer, 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 */
/* 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 */
@@ -281,9 +295,10 @@ libuEv use the GNU configure and build system. To try out the bundled
examples, use the `--enable-examples` switch to the `configure` script.
./configure
make all
make -j5
make test
make install
sudo make install-strip
sudo ldconfig
The resulting .so file is ~14 kiB (<kbd>make install-strip</kbd>).
+2 -1
View File
@@ -140,7 +140,8 @@ static struct timeval *run_once(uev_ctx_t *ctx)
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);
+2 -7
View File
@@ -1,19 +1,14 @@
AC_INIT(libuev, 1.4.2, https://github.com/troglobit/libuev/issues)
AC_INIT(libuev, 1.5.2, https://github.com/troglobit/libuev/issues)
AM_INIT_AUTOMAKE([1.11 foreign no-dist-gzip dist-xz])
AM_SILENT_RULES([yes])
AC_CONFIG_SRCDIR(uev.c)
AM_CONFIG_HEADER(config.h)
AC_CONFIG_FILES([Makefile libuev.pc examples/Makefile])
AC_CONFIG_FILES([Makefile libuev.pc examples/Makefile tests/Makefile])
AC_CONFIG_MACRO_DIR([m4])
AC_PROG_CC
AM_PROG_AR
LT_INIT
AC_ARG_ENABLE([examples],
[AS_HELP_STRING([--enable-examples], [build examples])],
[enable_examples=yes], [])
AM_CONDITIONAL([ENABLE_EXAMPLES], [test "$enable_examples" = yes])
AC_OUTPUT
+165
View File
@@ -0,0 +1,165 @@
/* libuEv - Micro event loop library
*
* Copyright (c) 2012 Flemming Madsen <flemming!madsen()madsensoft!dk>
* Copyright (c) 2013-2016 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 <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
/**
* 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 @param cb
* @param interval For an at job this is zero, for cron the offset interval
*
* For at jobs set @param interval to zero and only use @param when. For
* cron jobs, set @param interval to the offset. E.g., if the job should
* run every five minutes set the @param tm_min of struct tm to five.
*
* Use mktime() to create the time_t arguments. The special value zero
* may be used for @param 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 @param interval to 3600 to create a cron job that
* runs every hour.
*
* @return POSIX OK(0) or non-zero with @param 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 @param cb
* @param interval For an at job this is zero, for cron the offset interval
*
* @return POSIX OK(0) or non-zero with @param 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;
/* Remove from internal list */
LIST_REMOVE(w, link);
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 @param 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 @param 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:
*/
+4
View File
@@ -0,0 +1,4 @@
joystick
signal
cronrun
test
+1 -1
View File
@@ -1,4 +1,4 @@
noinst_PROGRAMS = signal test joystick
noinst_PROGRAMS = joystick
AM_CPPFLAGS = -I$(top_srcdir)
AM_LDFLAGS = -L$(top_srcdir)
LIBS = $(LTLIBINTL)
+23 -13
View File
@@ -31,13 +31,14 @@
/* I/O, timer, or signal watcher */
typedef enum {
UEV_IO_TYPE = 1,
UEV_TIMER_TYPE,
UEV_CRON_TYPE = 1,
UEV_IO_TYPE,
UEV_SIGNAL_TYPE,
UEV_TIMER_TYPE,
} uev_type_t;
/* Event mask, used internally only. */
#define UEV_EVENT_MASK (UEV_READ | UEV_WRITE | UEV_PRI)
#define UEV_EVENT_MASK (UEV_READ | UEV_WRITE | UEV_PRI | UEV_HUP)
/* Main libuEv context type */
typedef struct {
@@ -61,22 +62,31 @@ struct uev;
void (*cb)(struct uev *, void *, int); \
void *arg; \
\
/* Timer watchers, time in milliseconds */ \
int timeout; \
int period; \
/* Arguments for different watchers */ \
union { \
/* Cron watchers */ \
struct { \
time_t when; \
time_t interval; \
} c; \
\
/* Signal watchers */ \
int signo; \
/* Timer watchers, time in milliseconds */ \
struct { \
int timeout; \
int period; \
} t; \
} u; \
\
/* Watcher type */ \
uev_type_t
/* Internal API for dealing with generic watchers */
int uev_watcher_init (uev_ctx_t *ctx, struct uev *w, uev_type_t type,
void (*cb)(struct uev *, void *, int), void *arg,
int fd, int events);
int uev_watcher_start(struct uev *w);
int uev_watcher_stop (struct uev *w);
int uev_watcher_init (uev_ctx_t *ctx, struct uev *w, uev_type_t type,
void (*cb)(struct uev *, void *, int), void *arg,
int fd, int events);
int uev_watcher_start (struct uev *w);
int uev_watcher_stop (struct uev *w);
int uev_watcher_active(struct uev *w);
#endif /* LIBUEV_PRIVATE_H_ */
+7
View File
@@ -0,0 +1,7 @@
*.trs
*.log
active
complete
cronrun
signal
timer
+16
View File
@@ -0,0 +1,16 @@
EXTRA_DIST = check.h
CLEANFILES = *~ *.trs *.log
TESTS =
TESTS += active
TESTS += complete
TESTS += cronrun
TESTS += signal
TESTS += timer
check_PROGRAMS = $(TESTS)
# Ignore warnings about unused result, in e.g. write()
CFLAGS = -W -Wall -Wextra -Wno-unused-result
CPPFLAGS = -D_GNU_SOURCE
LDADD = -L../ ../libuev.la
+51
View File
@@ -0,0 +1,51 @@
#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 *UNUSED(arg), int UNUSED(events))
{
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));
uev_exit(w->ctx);
}
int main(void)
{
uev_ctx_t ctx;
struct timeval tomorrow;
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);
}
+81
View File
@@ -0,0 +1,81 @@
#ifndef UEV_TESTS_CHECK_H_
#define UEV_TESTS_CHECK_H_
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include "../uev.h"
#define UNUSED(arg) arg __attribute__ ((unused))
#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_TESTS_CHECK_H_ */
+2 -9
View File
@@ -22,14 +22,8 @@
* THE SOFTWARE.
*/
#include "check.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 {
int counter;
@@ -138,8 +132,7 @@ int main(void)
uev_run(&ctx, 0);
fprintf(stderr, "Period is %d must be 10: %s\n", period, 10 == period ? "OK" : "ERROR!");
if (10 != period)
return 1;
fail_unless(10 == period);
return 0;
}
+73
View File
@@ -0,0 +1,73 @@
/* Test cron API in libuEv event library
*
* Copyright (c) 2016 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 "check.h"
#include <time.h>
#include <sys/time.h>
#define TIMEOUT 2
#define INTERVAL 2
struct timeval tv;
static void cron_job(uev_t *w, void *UNUSED(arg), int UNUSED(events))
{
static int laps = 3;
struct timeval now;
/* 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--)
uev_exit(w->ctx);
}
int main(void)
{
uev_t cron_watcher;
uev_ctx_t ctx;
time_t when, interval;
uev_init(&ctx);
gettimeofday(&tv, NULL);
printf("Start of test %s", ctime(&tv.tv_sec));
printf("Expected cron %s", ctime(&when));
when = tv.tv_sec + TIMEOUT;
interval = INTERVAL;
uev_cron_init(&ctx, &cron_watcher, cron_job, NULL, when, interval);
return uev_run(&ctx, 0);
}
/**
* Local Variables:
* indent-tabs-mode: t
* c-file-style: "linux"
* End:
*/
+1 -3
View File
@@ -21,7 +21,7 @@
* THE SOFTWARE.
*/
#define _GNU_SOURCE
#include "check.h"
#include <err.h>
#include <sched.h>
#include <signal.h>
@@ -33,8 +33,6 @@
#include <sys/wait.h>
#include <unistd.h>
#include "uev.h"
#define UNUSED(arg) arg __attribute__ ((unused))
#define DO_SEGFAULT 1
+28
View File
@@ -0,0 +1,28 @@
#include "check.h"
#include <time.h>
#include <sys/time.h>
#define TIMEOUT 2 /* 2 sec */
struct timeval start;
static void cb(uev_t *w, void *UNUSED(arg), int UNUSED(events))
{
struct timeval now;
gettimeofday(&now, NULL);
fail_unless(now.tv_sec == start.tv_sec + TIMEOUT);
uev_exit(w->ctx);
}
int main(void)
{
uev_t w;
uev_ctx_t ctx;
uev_init(&ctx);
uev_timer_init(&ctx, &w, cb, NULL, TIMEOUT * 1000, 0);
gettimeofday(&start, NULL);
return uev_run(&ctx, 0);
}
+5 -4
View File
@@ -123,15 +123,16 @@ int uev_timer_set(uev_t *w, int timeout, int period)
return -1;
}
w->timeout = timeout;
w->period = period;
w->u.t.timeout = timeout;
w->u.t.period = period;
if (w->ctx->running) {
struct itimerspec time;
msec2tspec(timeout, &time.it_value);
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);
@@ -153,7 +154,7 @@ int uev_timer_start(uev_t *w)
if (-1 != w->fd)
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);
}
/**
+39 -5
View File
@@ -68,7 +68,7 @@ int uev_watcher_init(uev_ctx_t *ctx, uev_t *w, uev_type_t type, uev_cb_t *cb, vo
w->type = type;
w->active = 0;
w->fd = fd;
w->cb = (void *)cb;
w->cb = cb;
w->arg = arg;
w->events = events;
@@ -124,6 +124,15 @@ int uev_watcher_stop(uev_t *w)
return 0;
}
/* Private to libuEv, do not use directly! */
int uev_watcher_active(uev_t *w)
{
if (!w)
return 0;
return w->active;
}
/**
* Create an event loop context
* @param ctx Pointer to an uev_ctx_t context to be initialized
@@ -166,6 +175,7 @@ int uev_exit(uev_ctx_t *ctx)
continue;
switch (w->type) {
case UEV_CRON_TYPE:
case UEV_TIMER_TYPE:
uev_timer_stop(w);
break;
@@ -219,8 +229,10 @@ int uev_run(uev_ctx_t *ctx, int flags)
/* Start all dormant timers */
LIST_FOREACH(w, &ctx->watchers, link) {
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->timeout, w->period);
uev_timer_set(w, w->u.t.timeout, w->u.t.period);
}
while (ctx->running) {
@@ -274,6 +286,24 @@ int uev_run(uev_ctx_t *ctx, int flags)
}
}
if (UEV_CRON_TYPE == w->type) {
uint64_t exp;
if (read(w->fd, &exp, sizeof(exp)) != sizeof(exp)) {
if (errno != ECANCELED) {
uev_exit(ctx);
return -3;
}
events[i].events = UEV_HUP;
}
if (!w->u.c.interval)
w->u.c.when = 0;
else
w->u.c.when += w->u.c.interval;
}
if (UEV_TIMER_TYPE == w->type) {
uint64_t exp;
@@ -282,8 +312,8 @@ int uev_run(uev_ctx_t *ctx, int flags)
return -3;
}
if (!w->period)
w->timeout = 0;
if (!w->u.t.period)
w->u.t.timeout = 0;
}
if (UEV_SIGNAL_TYPE == w->type) {
@@ -299,8 +329,12 @@ int uev_run(uev_ctx_t *ctx, int flags)
if (w->cb)
w->cb(w, w->arg, events[i].events & UEV_EVENT_MASK);
if (UEV_CRON_TYPE == w->type) {
if (!w->u.c.when)
uev_timer_stop(w);
}
if (UEV_TIMER_TYPE == w->type) {
if (!w->timeout)
if (!w->u.t.timeout)
uev_timer_stop(w);
}
}
+13
View File
@@ -35,17 +35,25 @@
#define UEV_READ EPOLLIN
#define UEV_WRITE EPOLLOUT
#define UEV_PRI EPOLLPRI
#define UEV_HUP EPOLLHUP
/* Run flags */
#define UEV_ONCE 1
#define UEV_NONBLOCK 2
/* Macros */
#define uev_io_active(w) uev_watcher_active(w)
#define uev_timer_active(w) uev_watcher_active(w)
#define uev_cron_active(w) uev_watcher_active(w)
#define uev_signal_active(w) uev_watcher_active(w)
/* Event watcher */
typedef struct uev {
/* Private data for libuEv internal engine */
uev_private_t type;
/* Public data for users to reference */
int signo;
int fd;
uev_ctx_t *ctx;
} uev_t;
@@ -68,6 +76,11 @@ 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);