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:
2025-09-18 13:28:27 -07:00
parent c7729ca9b6
commit d0dd5f7a4a
8 changed files with 143 additions and 90 deletions

View File

@@ -1,7 +1,7 @@
/** Pollcat test stub - timers
*
* 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>
*
* The Pollcat Library is free software: you can redistribute it and/or modify it under
@@ -34,12 +34,17 @@
#include <pollcat.h>
int opt_wrapper = 0;
int opt_stdin = 0;
/** control for main loop for orderly shutdown */
static int main_loop = 1;
static void signal_fatal (int signum)
{
fprintf(stderr, "Fatal signal %d, exit loop\n", signum);
main_loop = 0;
pollcat_loop_exit();
}
static void stop (const char *fmt, ...);
@@ -55,8 +60,9 @@ static void callback (void *arg)
extern char *__progname;
static void usage (void)
{
printf("Usage: %s -v [-t timeout]\n"
"-v Verbose (set all modules to debug, enable trace)\n"
printf("Usage: %s [-ws] [-t timeout]\n"
"-w Use pollcat_poll() wrapper\n"
"-s Add stdin file descriptor to pollcat\n"
"-t timeout Timeout for poll() calls (ms)\n"
"",
__progname);
@@ -65,16 +71,17 @@ static void usage (void)
int main (int argc, char **argv)
{
int ret = 0;
short revents;
struct termios tio_old;
int flags;
int ret = 0;
// basic arguments parsing
int opt;
while ( (opt = getopt(argc, argv, "vt:")) != -1 )
while ( (opt = getopt(argc, argv, "wst:")) != -1 )
switch ( opt )
{
case 'v':
break;
case 'w': opt_wrapper = 1; break;
case 's': opt_stdin = 1; break;
case 't':
pollcat_time_base = atoi(optarg);
@@ -84,73 +91,92 @@ int main (int argc, char **argv)
usage();
}
pollcat_fd_add(fileno(stdin), POLLIN);
if ( opt_stdin )
pollcat_fd_add(fileno(stdin), POLLIN);
signal(SIGTERM, signal_fatal);
signal(SIGINT, signal_fatal);
// reopen stdout/stderr before making stdin non-blocking
char tty[256];
memset(tty, 0, sizeof(tty));
if ( readlink("/proc/self/fd/1", tty, sizeof(tty)) > 0 )
if ( opt_stdin )
{
if ( !freopen(tty, "w", stdout) || !freopen(tty, "w", stderr) )
perror(tty);
setbuf(stderr, NULL);
}
// 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 )
// reopen stdout/stderr before making stdin non-blocking
char tty[256];
memset(tty, 0, sizeof(tty));
if ( readlink("/proc/self/fd/1", tty, sizeof(tty)) > 0 )
{
perror("poll()");
break;
if ( !freopen(tty, "w", stdout) || !freopen(tty, "w", stderr) )
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 )
continue;
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 ( tcsetattr(0, TCSANOW, &tio_old) )
stop("tcsetattr(0, TCSANOW, &tio_old)");
}
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;
}