More minor bugfixes
- make pollcat_loop() work as expected with no structs linked, by - calling usleep() instead of poll() - refactoring delay calculation and reset into pollcat_time_value() - simplify pollcat_timer_dispatch() in case of slow callbacks - deprecate pollcat_timer_dispatch_thresh - revise tests/timer.c to support two new options: - -s to monitor stdin with pollcat_fd_add() - -w to use pollcat_loop() instead of handling main-loop separately - make pollcat_dump() always present in header, since it's always compiled in - add Makefile rules for installing tests, for easier running on cross-compiled targets
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
/** Wrapper structure for poll()
|
/** Wrapper structure for poll()
|
||||||
*
|
*
|
||||||
* This file is part of the Pollcat Library.
|
* This file is part of the Pollcat Library.
|
||||||
* Copyright (C) 2022 Expatria Technologies Inc.
|
* Copyright (C) 2022,2025 Expatria Technologies Inc.
|
||||||
* Contact: Morgan Hughes <morgan@expatria.ca>
|
* Contact: Morgan Hughes <morgan@expatria.ca>
|
||||||
*
|
*
|
||||||
* The Pollcat Library is free software: you can redistribute it and/or modify it under
|
* The Pollcat Library is free software: you can redistribute it and/or modify it under
|
||||||
@@ -40,9 +40,7 @@
|
|||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <poll.h>
|
#include <poll.h>
|
||||||
#if POLLCAT_DEBUG
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
/** Optional function to call on fatal error; if unset an assert()-style message will be
|
/** Optional function to call on fatal error; if unset an assert()-style message will be
|
||||||
@@ -123,11 +121,9 @@ void pollcat_time_reduce (int time);
|
|||||||
int pollcat_poll (void);
|
int pollcat_poll (void);
|
||||||
|
|
||||||
|
|
||||||
#if POLLCAT_DEBUG
|
/** Prints the pollfd array to a given file handle, if POLLCAT_DEBUG is nonzero
|
||||||
/** Prints the pollfd array to a given file handle
|
|
||||||
*/
|
*/
|
||||||
void pollcat_dump (FILE *fp);
|
void pollcat_dump (FILE *fp);
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
#endif /* _INCLUDE_POLLCAT_POLLCAT_H_ */
|
#endif /* _INCLUDE_POLLCAT_POLLCAT_H_ */
|
||||||
|
|||||||
@@ -28,8 +28,9 @@
|
|||||||
typedef uint64_t pollcat_time_t;
|
typedef uint64_t pollcat_time_t;
|
||||||
|
|
||||||
|
|
||||||
/** Grace period in milliseconds for late timers, set to 0 for exact match */
|
/** This was removed and replaced with a simpler implementation which allowed slow/late
|
||||||
extern pollcat_time_t pollcat_timer_dispatch_thresh;
|
* timers to run reliably. Setting it now has no effect. */
|
||||||
|
extern pollcat_time_t pollcat_timer_dispatch_thresh __attribute__((deprecated));
|
||||||
|
|
||||||
|
|
||||||
/** Maximum number of times to run the dispatch loop, set to -1 for no limit */
|
/** Maximum number of times to run the dispatch loop, set to -1 for no limit */
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/** Wrapper structure for poll()
|
/** Wrapper structure for poll()
|
||||||
*
|
*
|
||||||
* This file is part of the Pollcat Library.
|
* This file is part of the Pollcat Library.
|
||||||
* Copyright (C) 2022 Expatria Technologies Inc.
|
* Copyright (C) 2022,2025 Expatria Technologies Inc.
|
||||||
* Contact: Morgan Hughes <morgan@expatria.ca>
|
* Contact: Morgan Hughes <morgan@expatria.ca>
|
||||||
*
|
*
|
||||||
* The Pollcat Library is free software: you can redistribute it and/or modify it under
|
* The Pollcat Library is free software: you can redistribute it and/or modify it under
|
||||||
@@ -284,6 +284,23 @@ void pollcat_time_reduce (int time)
|
|||||||
pollcat_time_current = time;
|
pollcat_time_current = time;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Return the current timeout and reset the current timeout to the base value
|
||||||
|
*
|
||||||
|
* \return Timeout in milliseconds
|
||||||
|
*/
|
||||||
|
int pollcat_time_value (void)
|
||||||
|
{
|
||||||
|
/* latch current value, which may have been reduced by pollcat_time_reduce() */
|
||||||
|
int value = pollcat_time_current;
|
||||||
|
|
||||||
|
/* enforce minimum */
|
||||||
|
if ( value < pollcat_time_minimum )
|
||||||
|
value = pollcat_time_minimum;
|
||||||
|
|
||||||
|
/* reset to base before return, for next call */
|
||||||
|
pollcat_time_current = pollcat_time_base;
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
/** Wraps the system poll() command using the internal pollfd array and timeout
|
/** Wraps the system poll() command using the internal pollfd array and timeout
|
||||||
*
|
*
|
||||||
@@ -296,11 +313,7 @@ int pollcat_poll (void)
|
|||||||
/* Auto init, no-return if failed */
|
/* Auto init, no-return if failed */
|
||||||
pollcat_init();
|
pollcat_init();
|
||||||
|
|
||||||
if ( pollcat_time_current < pollcat_time_minimum )
|
ret = poll(pollcat_list, pollcat_used, pollcat_time_value());
|
||||||
pollcat_time_current = pollcat_time_minimum;
|
|
||||||
|
|
||||||
ret = poll(pollcat_list, pollcat_used, pollcat_time_current);
|
|
||||||
pollcat_time_current = pollcat_time_base;
|
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/** Private includes
|
/** Private includes
|
||||||
*
|
*
|
||||||
* This file is part of the Pollcat Library.
|
* This file is part of the Pollcat Library.
|
||||||
* Copyright (C) 2022 Expatria Technologies Inc.
|
* Copyright (C) 2022,2025 Expatria Technologies Inc.
|
||||||
* Contact: Morgan Hughes <morgan@expatria.ca>
|
* Contact: Morgan Hughes <morgan@expatria.ca>
|
||||||
*
|
*
|
||||||
* The Pollcat Library is free software: you can redistribute it and/or modify it under
|
* The Pollcat Library is free software: you can redistribute it and/or modify it under
|
||||||
@@ -40,4 +40,8 @@
|
|||||||
extern pollcat_assert_f pollcat_assert_func;
|
extern pollcat_assert_f pollcat_assert_func;
|
||||||
|
|
||||||
|
|
||||||
|
/** Return the current timeout and reset the current timeout to the base value */
|
||||||
|
int pollcat_time_value (void);
|
||||||
|
|
||||||
|
|
||||||
#endif /* _SRC_PRIVATE_H_ */
|
#endif /* _SRC_PRIVATE_H_ */
|
||||||
|
|||||||
17
src/struct.c
17
src/struct.c
@@ -1,7 +1,7 @@
|
|||||||
/** Registration struct, iterators, and main-loop convenience functions
|
/** Registration struct, iterators, and main-loop convenience functions
|
||||||
*
|
*
|
||||||
* This file is part of the Pollcat Library.
|
* This file is part of the Pollcat Library.
|
||||||
* Copyright (C) 2022 Expatria Technologies Inc.
|
* Copyright (C) 2022,2025 Expatria Technologies Inc.
|
||||||
* Contact: Morgan Hughes <morgan@expatria.ca>
|
* Contact: Morgan Hughes <morgan@expatria.ca>
|
||||||
*
|
*
|
||||||
* The Pollcat Library is free software: you can redistribute it and/or modify it under
|
* The Pollcat Library is free software: you can redistribute it and/or modify it under
|
||||||
@@ -21,6 +21,7 @@
|
|||||||
*/
|
*/
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
#include <pollcat.h>
|
#include <pollcat.h>
|
||||||
#include "private.h"
|
#include "private.h"
|
||||||
@@ -145,8 +146,18 @@ int pollcat_loop (int *poll_ret)
|
|||||||
if ( walk->ops && walk->ops->prepare )
|
if ( walk->ops && walk->ops->prepare )
|
||||||
walk->ops->prepare(walk);
|
walk->ops->prepare(walk);
|
||||||
|
|
||||||
/* call pollcat_poll() and optionally save the return value in poll-ret */
|
/* call pollcat_poll() if the iterator list is non-empty, otherwise sleep */
|
||||||
ret = pollcat_poll();
|
if ( pollcat_iter_head )
|
||||||
|
ret = pollcat_poll();
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* pollcat_time_value() returns milliseconds, usleep takes microseconds */
|
||||||
|
ret = pollcat_time_value() * 1000;
|
||||||
|
ret = usleep(ret);
|
||||||
|
ret = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* optionally save the return value in poll-ret */
|
||||||
if ( poll_ret )
|
if ( poll_ret )
|
||||||
*poll_ret = ret;
|
*poll_ret = ret;
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/** Millisecond-resolution event timers
|
/** Millisecond-resolution event timers
|
||||||
*
|
*
|
||||||
* This file is part of the Pollcat Library.
|
* This file is part of the Pollcat Library.
|
||||||
* Copyright (C) 2022 Expatria Technologies Inc.
|
* Copyright (C) 2022,2025 Expatria Technologies Inc.
|
||||||
* Contact: Morgan Hughes <morgan@expatria.ca>
|
* Contact: Morgan Hughes <morgan@expatria.ca>
|
||||||
*
|
*
|
||||||
* The Pollcat Library is free software: you can redistribute it and/or modify it under
|
* The Pollcat Library is free software: you can redistribute it and/or modify it under
|
||||||
@@ -219,11 +219,8 @@ void pollcat_timer_dispatch (void)
|
|||||||
|
|
||||||
while ( timer_head && max-- )
|
while ( timer_head && max-- )
|
||||||
{
|
{
|
||||||
pollcat_time_t due = pollcat_now();
|
if ( pollcat_now() < timer_head->due )
|
||||||
|
return;
|
||||||
due -= timer_head->due;
|
|
||||||
if ( due > pollcat_timer_dispatch_thresh )
|
|
||||||
return;
|
|
||||||
|
|
||||||
// detach the head
|
// detach the head
|
||||||
struct pollcat_timer *t = timer_head;
|
struct pollcat_timer *t = timer_head;
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
# Test stubs Makefile
|
# Test stubs Makefile
|
||||||
#
|
#
|
||||||
# This file is part of the Pollcat Library.
|
# This file is part of the Pollcat Library.
|
||||||
# Copyright (C) 2022 Expatria Technologies Inc.
|
# Copyright (C) 2022,2025 Expatria Technologies Inc.
|
||||||
# Contact: Morgan Hughes <morgan@expatria.ca>
|
# Contact: Morgan Hughes <morgan@expatria.ca>
|
||||||
#
|
#
|
||||||
# The Pollcat Library is free software: you can redistribute it and/or modify it under the
|
# The Pollcat Library is free software: you can redistribute it and/or modify it under the
|
||||||
@@ -18,6 +18,10 @@
|
|||||||
#
|
#
|
||||||
# vim:ts=4:noexpandtab
|
# vim:ts=4:noexpandtab
|
||||||
|
|
||||||
|
# Integrators should override these
|
||||||
|
PREFIX ?= /usr/local
|
||||||
|
export PREFIX DESTDIR
|
||||||
|
|
||||||
# output targets
|
# output targets
|
||||||
BINS := \
|
BINS := \
|
||||||
poll \
|
poll \
|
||||||
@@ -57,7 +61,8 @@ timer: $(TIMER_OBJS)
|
|||||||
|
|
||||||
|
|
||||||
install:
|
install:
|
||||||
false
|
mkdir -p $(DESTDIR)$(PREFIX)/bin
|
||||||
|
install -m755 $(BINS) $(DESTDIR)$(PREFIX)/bin
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -f $(POLL_OBJS)
|
rm -f $(POLL_OBJS)
|
||||||
|
|||||||
154
tests/timer.c
154
tests/timer.c
@@ -1,7 +1,7 @@
|
|||||||
/** Pollcat test stub - timers
|
/** Pollcat test stub - timers
|
||||||
*
|
*
|
||||||
* This file is part of the Pollcat Library.
|
* This file is part of the Pollcat Library.
|
||||||
* Copyright (C) 2022 Expatria Technologies Inc.
|
* Copyright (C) 2022,2025 Expatria Technologies Inc.
|
||||||
* Contact: Morgan Hughes <morgan@expatria.ca>
|
* Contact: Morgan Hughes <morgan@expatria.ca>
|
||||||
*
|
*
|
||||||
* The Pollcat Library is free software: you can redistribute it and/or modify it under
|
* The Pollcat Library is free software: you can redistribute it and/or modify it under
|
||||||
@@ -34,12 +34,17 @@
|
|||||||
#include <pollcat.h>
|
#include <pollcat.h>
|
||||||
|
|
||||||
|
|
||||||
|
int opt_wrapper = 0;
|
||||||
|
int opt_stdin = 0;
|
||||||
|
|
||||||
|
|
||||||
/** control for main loop for orderly shutdown */
|
/** control for main loop for orderly shutdown */
|
||||||
static int main_loop = 1;
|
static int main_loop = 1;
|
||||||
static void signal_fatal (int signum)
|
static void signal_fatal (int signum)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "Fatal signal %d, exit loop\n", signum);
|
fprintf(stderr, "Fatal signal %d, exit loop\n", signum);
|
||||||
main_loop = 0;
|
main_loop = 0;
|
||||||
|
pollcat_loop_exit();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void stop (const char *fmt, ...);
|
static void stop (const char *fmt, ...);
|
||||||
@@ -55,8 +60,9 @@ static void callback (void *arg)
|
|||||||
extern char *__progname;
|
extern char *__progname;
|
||||||
static void usage (void)
|
static void usage (void)
|
||||||
{
|
{
|
||||||
printf("Usage: %s -v [-t timeout]\n"
|
printf("Usage: %s [-ws] [-t timeout]\n"
|
||||||
"-v Verbose (set all modules to debug, enable trace)\n"
|
"-w Use pollcat_poll() wrapper\n"
|
||||||
|
"-s Add stdin file descriptor to pollcat\n"
|
||||||
"-t timeout Timeout for poll() calls (ms)\n"
|
"-t timeout Timeout for poll() calls (ms)\n"
|
||||||
"",
|
"",
|
||||||
__progname);
|
__progname);
|
||||||
@@ -65,16 +71,17 @@ static void usage (void)
|
|||||||
|
|
||||||
int main (int argc, char **argv)
|
int main (int argc, char **argv)
|
||||||
{
|
{
|
||||||
int ret = 0;
|
struct termios tio_old;
|
||||||
short revents;
|
int flags;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
// basic arguments parsing
|
// basic arguments parsing
|
||||||
int opt;
|
int opt;
|
||||||
while ( (opt = getopt(argc, argv, "vt:")) != -1 )
|
while ( (opt = getopt(argc, argv, "wst:")) != -1 )
|
||||||
switch ( opt )
|
switch ( opt )
|
||||||
{
|
{
|
||||||
case 'v':
|
case 'w': opt_wrapper = 1; break;
|
||||||
break;
|
case 's': opt_stdin = 1; break;
|
||||||
|
|
||||||
case 't':
|
case 't':
|
||||||
pollcat_time_base = atoi(optarg);
|
pollcat_time_base = atoi(optarg);
|
||||||
@@ -84,73 +91,92 @@ int main (int argc, char **argv)
|
|||||||
usage();
|
usage();
|
||||||
}
|
}
|
||||||
|
|
||||||
pollcat_fd_add(fileno(stdin), POLLIN);
|
if ( opt_stdin )
|
||||||
|
pollcat_fd_add(fileno(stdin), POLLIN);
|
||||||
|
|
||||||
signal(SIGTERM, signal_fatal);
|
signal(SIGTERM, signal_fatal);
|
||||||
signal(SIGINT, signal_fatal);
|
signal(SIGINT, signal_fatal);
|
||||||
|
|
||||||
// reopen stdout/stderr before making stdin non-blocking
|
if ( opt_stdin )
|
||||||
char tty[256];
|
|
||||||
memset(tty, 0, sizeof(tty));
|
|
||||||
if ( readlink("/proc/self/fd/1", tty, sizeof(tty)) > 0 )
|
|
||||||
{
|
{
|
||||||
if ( !freopen(tty, "w", stdout) || !freopen(tty, "w", stderr) )
|
// reopen stdout/stderr before making stdin non-blocking
|
||||||
perror(tty);
|
char tty[256];
|
||||||
setbuf(stderr, NULL);
|
memset(tty, 0, sizeof(tty));
|
||||||
}
|
if ( readlink("/proc/self/fd/1", tty, sizeof(tty)) > 0 )
|
||||||
|
|
||||||
// set stdin nonblocking
|
|
||||||
int flags = fcntl(fileno(stdin), F_GETFL);
|
|
||||||
if ( flags < 0 )
|
|
||||||
stop("fcntl(0, F_GETFL)");
|
|
||||||
if ( fcntl(fileno(stdin), F_SETFL, flags | O_NONBLOCK) < 0 )
|
|
||||||
stop("fcntl(0, F_SETFL)");
|
|
||||||
|
|
||||||
// save old terminal modes and make raw
|
|
||||||
struct termios tio_old;
|
|
||||||
if ( tcgetattr(fileno(stdin), &tio_old) )
|
|
||||||
stop("tcgetattr(0, &tio_old)");
|
|
||||||
|
|
||||||
struct termios tio_new = tio_old;
|
|
||||||
tio_new.c_lflag &= ~(ECHO|ICANON);
|
|
||||||
if ( tcsetattr(fileno(stdin), TCSANOW, &tio_new) )
|
|
||||||
stop("tcsetattr(0, TCSANOW, &tio_new)");
|
|
||||||
|
|
||||||
while ( main_loop )
|
|
||||||
{
|
|
||||||
pollcat_timer_reduce_timeout();
|
|
||||||
|
|
||||||
if ( (ret = pollcat_poll()) < 0 )
|
|
||||||
{
|
{
|
||||||
perror("poll()");
|
if ( !freopen(tty, "w", stdout) || !freopen(tty, "w", stderr) )
|
||||||
break;
|
perror(tty);
|
||||||
|
setbuf(stderr, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
// set stdin nonblocking
|
||||||
|
if ( (flags = fcntl(fileno(stdin), F_GETFL)) < 0 )
|
||||||
|
stop("fcntl(0, F_GETFL)");
|
||||||
|
if ( fcntl(fileno(stdin), F_SETFL, flags | O_NONBLOCK) < 0 )
|
||||||
|
stop("fcntl(0, F_SETFL)");
|
||||||
|
|
||||||
|
// save old terminal modes and make raw
|
||||||
|
if ( tcgetattr(fileno(stdin), &tio_old) )
|
||||||
|
stop("tcgetattr(0, &tio_old)");
|
||||||
|
|
||||||
|
struct termios tio_new = tio_old;
|
||||||
|
tio_new.c_lflag &= ~(ECHO|ICANON);
|
||||||
|
if ( tcsetattr(fileno(stdin), TCSANOW, &tio_new) )
|
||||||
|
stop("tcsetattr(0, TCSANOW, &tio_new)");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
pollcat_timer_attach(&timer, 1000, callback, NULL);
|
||||||
|
|
||||||
|
if ( opt_wrapper )
|
||||||
|
{
|
||||||
|
pollcat_dump(stderr);
|
||||||
|
while ( pollcat_loop(&ret) )
|
||||||
|
pollcat_dump(stderr);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
while ( main_loop )
|
||||||
|
{
|
||||||
|
pollcat_timer_reduce_timeout();
|
||||||
|
|
||||||
|
pollcat_dump(stderr);
|
||||||
|
if ( (ret = pollcat_poll()) < 0 )
|
||||||
|
{
|
||||||
|
perror("poll()");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
pollcat_dump(stderr);
|
||||||
|
|
||||||
|
pollcat_timer_dispatch();
|
||||||
|
|
||||||
|
if ( !ret )
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if ( opt_stdin )
|
||||||
|
{
|
||||||
|
short revents = pollcat_revents(fileno(stdin));
|
||||||
|
assert(revents > -1);
|
||||||
|
if ( revents & POLLIN )
|
||||||
|
{
|
||||||
|
char buff[16];
|
||||||
|
|
||||||
|
memset(buff, 0, sizeof(buff));
|
||||||
|
ret = read(fileno(stdin), buff, sizeof(buff) - 1);
|
||||||
|
fprintf(stderr, "recv(%d): '%s'\n", ret, buff);
|
||||||
|
|
||||||
|
pollcat_timer_attach(&timer, 333, callback, NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pollcat_timer_dispatch();
|
if ( opt_stdin )
|
||||||
|
{
|
||||||
|
if ( fcntl(0, F_SETFL, flags) < 0 )
|
||||||
|
stop("fcntl(0, F_SETFL)");
|
||||||
|
|
||||||
if ( !ret )
|
if ( tcsetattr(0, TCSANOW, &tio_old) )
|
||||||
continue;
|
stop("tcsetattr(0, TCSANOW, &tio_old)");
|
||||||
|
|
||||||
revents = pollcat_revents(fileno(stdin));
|
|
||||||
assert(revents > -1);
|
|
||||||
if ( revents & POLLIN )
|
|
||||||
{
|
|
||||||
char buff[16];
|
|
||||||
|
|
||||||
memset(buff, 0, sizeof(buff));
|
|
||||||
ret = read(fileno(stdin), buff, sizeof(buff) - 1);
|
|
||||||
fprintf(stderr, "recv(%d): '%s'\n", ret, buff);
|
|
||||||
|
|
||||||
pollcat_timer_attach(&timer, 333, callback, NULL);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( fcntl(0, F_SETFL, flags) < 0 )
|
|
||||||
stop("fcntl(0, F_SETFL)");
|
|
||||||
|
|
||||||
if ( tcsetattr(0, TCSANOW, &tio_old) )
|
|
||||||
stop("tcsetattr(0, TCSANOW, &tio_old)");
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user