Initial commit of Pollcat library

This commit is contained in:
2022-06-28 15:25:57 -07:00
commit bbd4625d43
26 changed files with 3534 additions and 0 deletions

3
tests/.gitignore vendored Normal file
View File

@@ -0,0 +1,3 @@
/poll
/struct
/timer

73
tests/Makefile Normal file
View File

@@ -0,0 +1,73 @@
# Test stubs Makefile
#
# This file is part of the Pollcat Library.
# Copyright (C) 2022 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
# output targets
BINS := \
poll \
struct \
timer
# "poll" app
POLL_OBJS := poll.o
POLL_LIBS := -lpollcat
# "struct" app
STRUCT_OBJS := struct.o
STRUCT_LIBS := -lpollcat
# "timer app
TIMER_OBJS := timer.o
TIMER_LIBS := -lpollcat
CFLAGS += -I../include -Wall -Werror -g
CFLAGS += -D_LARGEFILE64_SOURCE
LFLAGS += -L.. -Wl,-rpath=$(shell cd .. && pwd)
.PHONY: all install clean
all: $(BINS)
@echo
poll: $(POLL_OBJS)
$(CC) $(CFLAGS) $(LFLAGS) $^ $(POLL_LIBS) -o $@
struct: $(STRUCT_OBJS)
$(CC) $(CFLAGS) $(LFLAGS) $^ $(STRUCT_LIBS) -o $@
timer: $(TIMER_OBJS)
$(CC) $(CFLAGS) $(LFLAGS) $^ $(TIMER_LIBS) -o $@
install:
false
clean:
rm -f $(POLL_OBJS)
rm -f $(STRUCT_OBJS)
rm -f $(TIMER_OBJS)
rm -f $(BINS)
%.i: %.c
$(CC) $(CFLAGS) -E $< -o $@
%.o: %.c
$(CC) $(CFLAGS) -c $< -o $@

154
tests/poll.c Normal file
View File

@@ -0,0 +1,154 @@
/** Pollcat test stub
*
* This file is part of the Pollcat Library.
* Copyright (C) 2022 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>
/** 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;
}
static void stop (const char *fmt, ...);
extern char *__progname;
static void usage (void)
{
printf("Usage: %s -v [-t timeout]\n"
"-v Verbose (set all modules to debug, enable trace)\n"
"-t timeout Timeout for poll() calls (ms)\n"
"",
__progname);
exit(1);
}
int main (int argc, char **argv)
{
int ret = 0;
short revents;
// basic arguments parsing
int opt;
while ( (opt = getopt(argc, argv, "vt:")) != -1 )
switch ( opt )
{
case 'v':
break;
case 't':
pollcat_time_base = atoi(optarg);
break;
default:
usage();
}
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 ( !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 )
{
if ( (ret = pollcat_poll()) < 0 )
{
perror("poll()");
break;
}
else 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);
}
}
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);
}

196
tests/struct.c Normal file
View File

@@ -0,0 +1,196 @@
/** Pollcat test stub
*
* This file is part of the Pollcat Library.
* Copyright (C) 2022 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>
static void stdin_service (struct pollcat *cat)
{
char buff[16];
int ret;
int idx;
if ( !(pollcat_revents(fileno(stdin)) & POLLIN) )
return;
memset(buff, 0, sizeof(buff));
if ( (ret = read(fileno(stdin), buff, sizeof(buff) - 1)) < 0 )
{
fprintf(stderr, "recv(%d): %s", ret, strerror(errno));
pollcat_loop_exit();
return;
}
fprintf(stderr, "recv(%d): '", ret);
for ( idx = 0; idx < ret; idx++ )
if ( isprint(buff[idx]) )
fputc(buff[idx], stderr);
else
fprintf(stderr, "\\x%02x", buff[idx]);
fputs("'\n", stderr);
if ( ret )
switch ( tolower(buff[0]) )
{
case 'q':
case '\033':
case '\03':
fprintf(stderr, "shutting down\n");
pollcat_loop_exit();
return;
}
}
const struct pollcat_ops stdin_ops =
{
.service = stdin_service,
};
struct pollcat stdin_cat =
{
.ops = &stdin_ops,
};
struct pollcat_timer timer = { 0 };
static void callback (void *arg)
{
printf("timer callback\n");
pollcat_timer_attach(&timer, 5000, callback, NULL);
}
/** control for main loop for orderly shutdown */
static void signal_fatal (int signum)
{
fprintf(stderr, "Fatal signal %d, exit loop\n", signum);
pollcat_loop_exit();
}
static void stop (const char *fmt, ...);
extern char *__progname;
static void usage (void)
{
printf("Usage: %s -v [-t timeout]\n"
"-v Verbose (set all modules to debug, enable trace)\n"
"-t timeout Timeout for poll() calls (ms)\n"
"",
__progname);
exit(1);
}
int main (int argc, char **argv)
{
int ret;
// basic arguments parsing
int opt;
while ( (opt = getopt(argc, argv, "vt:")) != -1 )
switch ( opt )
{
case 'v':
break;
case 't':
pollcat_time_base = atoi(optarg);
break;
default:
usage();
}
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 ( !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)");
pollcat_fd_add(fileno(stdin), POLLIN);
pollcat_iter_add(&stdin_cat);
pollcat_timer_attach(&timer, 5000, callback, NULL);
while ( pollcat_loop(&ret) )
{
}
pollcat_iter_remove(&stdin_cat);
pollcat_fd_remove(fileno(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);
}

169
tests/timer.c Normal file
View File

@@ -0,0 +1,169 @@
/** Pollcat test stub - timers
*
* This file is part of the Pollcat Library.
* Copyright (C) 2022 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>
/** 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;
}
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 -v [-t timeout]\n"
"-v Verbose (set all modules to debug, enable trace)\n"
"-t timeout Timeout for poll() calls (ms)\n"
"",
__progname);
exit(1);
}
int main (int argc, char **argv)
{
int ret = 0;
short revents;
// basic arguments parsing
int opt;
while ( (opt = getopt(argc, argv, "vt:")) != -1 )
switch ( opt )
{
case 'v':
break;
case 't':
pollcat_time_base = atoi(optarg);
break;
default:
usage();
}
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 ( !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 )
{
perror("poll()");
break;
}
pollcat_timer_dispatch();
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 ( 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);
}