- 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
196 lines
4.4 KiB
C
196 lines
4.4 KiB
C
/** Pollcat test stub - timers
|
|
*
|
|
* This file is part of the Pollcat Library.
|
|
* 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
|
|
* the terms of the the GNU Lesser General Public License as published by the Free
|
|
* Software Foundation; either version 3 of the License, or (at your option) any later
|
|
* version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
|
* PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
|
*
|
|
* You should have received copies of the GNU General Public License and the GNU Lesser
|
|
* General Public License along with the Pollcat Library. If not, see
|
|
* https://www.gnu.org/licenses/
|
|
*
|
|
* vim:ts=4:noexpandtab
|
|
*/
|
|
#include <assert.h>
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <stdarg.h>
|
|
#include <string.h>
|
|
#include <fcntl.h>
|
|
#include <ctype.h>
|
|
#include <errno.h>
|
|
#include <unistd.h>
|
|
#include <signal.h>
|
|
#include <termios.h>
|
|
|
|
#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, ...);
|
|
|
|
struct pollcat_timer timer = { 0 };
|
|
static void callback (void *arg)
|
|
{
|
|
printf("timer callback\n");
|
|
pollcat_timer_attach(&timer, 333, callback, NULL);
|
|
}
|
|
|
|
|
|
extern char *__progname;
|
|
static void usage (void)
|
|
{
|
|
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);
|
|
exit(1);
|
|
}
|
|
|
|
int main (int argc, char **argv)
|
|
{
|
|
struct termios tio_old;
|
|
int flags;
|
|
int ret = 0;
|
|
|
|
// basic arguments parsing
|
|
int opt;
|
|
while ( (opt = getopt(argc, argv, "wst:")) != -1 )
|
|
switch ( opt )
|
|
{
|
|
case 'w': opt_wrapper = 1; break;
|
|
case 's': opt_stdin = 1; break;
|
|
|
|
case 't':
|
|
pollcat_time_base = atoi(optarg);
|
|
break;
|
|
|
|
default:
|
|
usage();
|
|
}
|
|
|
|
if ( opt_stdin )
|
|
pollcat_fd_add(fileno(stdin), POLLIN);
|
|
|
|
signal(SIGTERM, signal_fatal);
|
|
signal(SIGINT, signal_fatal);
|
|
|
|
if ( opt_stdin )
|
|
{
|
|
// 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 ( !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);
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( opt_stdin )
|
|
{
|
|
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;
|
|
}
|
|
|
|
static void stop (const char *fmt, ...)
|
|
{
|
|
int err = errno;
|
|
va_list ap;
|
|
|
|
va_start(ap, fmt);
|
|
vfprintf(stderr, fmt, ap);
|
|
va_end(ap);
|
|
|
|
fprintf(stderr, ": %s\n", strerror(err));
|
|
exit(1);
|
|
}
|
|
|