/** Pollcat test stub - timers * * This file is part of the Pollcat Library. * Copyright (C) 2022,2025 Expatria Technologies Inc. * Contact: Morgan Hughes * * 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 #include #include #include #include #include #include #include #include #include #include #include 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); }