signals + tests

This commit is contained in:
overflowerror 2019-03-03 19:21:52 +01:00
parent 4b6cbba04f
commit fa9cc3b8cc
4 changed files with 212 additions and 20 deletions

View file

@ -1,5 +1,5 @@
CC = gcc CC = gcc
CFLAGS = -Wall -Wpedantic CFLAGS = -std=c99 -Wall -D_POSIX_C_SOURCE=199506L
LD = gcc LD = gcc
LDFLAGS = -lpthread -lrt LDFLAGS = -lpthread -lrt
@ -7,16 +7,17 @@ BIN_NAME = cfloor
all: $(BIN_NAME) all: $(BIN_NAME)
test: obj/test.o obj/networking.o obj/linked.o obj/logging.o test: obj/test.o obj/networking.o obj/linked.o obj/logging.o obj/signals.o
$(LD) $(LDFLAGS) -o $@ $^ $(LD) $(LDFLAGS) -o $@ $^
valgrind: CFLAGS += -static -g valgrind: CFLAGS += -static -g
valgrind: clean test valgrind: clean test
valgrind --leak-check=yes ./test valgrind --leak-check=yes ./test
obj/test.o: src/networking.h src/linked.h src/logging.h obj/test.o: src/networking.h src/linked.h src/logging.h src/signals.h
obj/networking.o: src/networking.h src/headers.h src/linked.h obj/networking.o: src/networking.h src/headers.h src/linked.h
obj/linked.o: src/linked.h obj/linked.o: src/linked.h
obj/loggin.o: src/logging.h obj/loggin.o: src/logging.h
obj/signals.o: src/signals.h
obj/%.o: src/%.c obj obj/%.o: src/%.c obj
$(CC) $(CFLAGS) -c -o $@ $< $(CC) $(CFLAGS) -c -o $@ $<

102
src/signals.c Normal file
View file

@ -0,0 +1,102 @@
#include <signal.h>
#include <pthread.h>
#include <time.h>
#include <stdio.h>
#include "signals.h"
int signal_setup(int signo, void (*handler)(int signo)) {
struct sigaction action;
action.sa_flags = 0;
action.sa_handler = handler;
return sigaction(signo, &action, NULL);
}
int signal_block_all() {
sigset_t mask;
sigfillset(&mask);
return pthread_sigmask(SIG_BLOCK, &mask, NULL);
}
int signal_allow_all() {
sigset_t mask;
sigfillset(&mask);
return pthread_sigmask(SIG_UNBLOCK, &mask, NULL);
}
int signal_block(int signo) {
sigset_t mask;
sigaddset(&mask, signo);
return pthread_sigmask(SIG_BLOCK, &mask, NULL);
}
int signal_allow(int signo) {
sigset_t mask;
sigaddset(&mask, signo);
return pthread_sigmask(SIG_UNBLOCK, &mask, NULL);
}
static void timerHandler(union sigval target) {
((void (*)(void))(target.sival_ptr))();
}
timer_t timer_createThreadTimer(void (*handler)()) {
struct sigevent sevp;
sevp.sigev_notify = SIGEV_THREAD;
sevp.sigev_notify_function = timerHandler;
sevp.sigev_notify_attributes = NULL;
sevp.sigev_value.sival_ptr = (void*) handler;
timer_t timer;
if (timer_create(CLOCK_BOOTTIME, &sevp, &timer) < 0) {
timer = NULL;
}
return timer;
}
timer_t timer_createSignalTimer(int signo) {
struct sigevent sevp;
sevp.sigev_notify = SIGEV_SIGNAL;
sevp.sigev_signo = signo;
timer_t timer;
if (timer_create(CLOCK_BOOTTIME, &sevp, &timer) < 0) {
timer = NULL;
}
return timer;
}
int timer_destroy(timer_t timer) {
return timer_delete(timer);
}
int timer_startTimer(timer_t timer, unsigned long ms) {
struct itimerspec time, old;
time.it_value.tv_sec = ms / 1000;
time.it_value.tv_nsec = ((ms % 1000) * 1000000);
time.it_interval.tv_sec = 0;
time.it_interval.tv_nsec = 0;
return timer_settime(timer, 0, &time, &old);
}
int timer_startInterval(timer_t timer, unsigned long ms) {
struct itimerspec time, old;
time.it_value.tv_sec = ms / 1000;
time.it_value.tv_nsec = ((ms % 1000) * 1000000);
time.it_interval.tv_sec = ms / 1000;
time.it_interval.tv_nsec = ((ms % 1000) * 1000000);
return timer_settime(timer, 0, &time, &old);
}
int timer_stop(timer_t timer) {
struct itimerspec time, old;
time.it_value.tv_sec = 0;
time.it_value.tv_nsec = 0;
time.it_interval.tv_sec = 0;
time.it_interval.tv_nsec = 0;
return timer_settime(timer, 0, &time, &old);
}

20
src/signals.h Normal file
View file

@ -0,0 +1,20 @@
#ifndef SIGNALS_H
#define SIGNALS_H
#include <time.h>
int signal_setup(int signum, void (*handler)(int signo));
int signal_block_all();
int signal_allow_all();
int signal_block(int signo);
int signal_allow(int signo);
timer_t timer_createThreadTimer(void (*handler)());
timer_t timer_createSignalTimer(int signo);
int timer_destroy(timer_t timer);
int timer_startTimer(timer_t timer, unsigned long ms);
int timer_startInterval(timer_t timer, unsigned long ms);
int timer_stop(timer_t timer);
#endif

View file

@ -2,12 +2,20 @@
#include <stdlib.h> #include <stdlib.h>
#include <stdbool.h> #include <stdbool.h>
#include <string.h> #include <string.h>
#include <errno.h>
#include <sys/select.h>
#include <unistd.h>
#include <poll.h>
#include <fcntl.h>
#include <time.h>
#include "networking.h" #include "networking.h"
#include "linked.h" #include "linked.h"
#include "logging.h" #include "logging.h"
#include "signals.h"
bool global = true; bool global = true;
bool overall = true;
void checkBool(bool ok, const char* check) { void checkBool(bool ok, const char* check) {
const char* result; const char* result;
@ -33,6 +41,10 @@ void checkNull(void* value, const char* check) {
checkBool(value != NULL, check); checkBool(value != NULL, check);
} }
void showError() {
fprintf(stderr, "Error: %s\n", strerror(errno));
}
void testLinkedList() { void testLinkedList() {
linkedList_t list = linked_create(); linkedList_t list = linked_create();
@ -85,20 +97,80 @@ void testLinkedList() {
linked_destroy(&list); linked_destroy(&list);
} }
bool hasData(int fd) {
int tmp = poll(&(struct pollfd){ .fd = fd, .events = POLLIN }, 1, 10);
return tmp == 1;
}
bool handlerHasTriggered = false;
void criticalHandler() { void criticalHandler() {
printf("This is the critical handler.\n"); printf("This is the critical handler.\n");
printBacktrace(); printBacktrace();
} }
void testLogging() { void testLogging() {
int pipefd[2];
if (pipe(pipefd) < 0) {
showError();
return;
}
FILE* pipeWrite = fdopen(pipefd[1], "w");
if (pipeWrite == NULL) {
showError();
return;
}
setbuf(pipeWrite, NULL);
FILE* pipeRead = fdopen(pipefd[0], "r");
if (pipeRead == NULL) {
showError();
return;
}
setbuf(pipeRead, NULL);
setLogging(pipeWrite, DEFAULT_LOGLEVEL, false);
setLogging(stderr, DEFAULT_LOGLEVEL, true); setLogging(stderr, DEFAULT_LOGLEVEL, true);
info("This info should not be displayed."); info("This info should not be displayed.");
checkBool(!hasData(pipefd[0]), "no data read (info)");
warn("This warning should be displayed."); warn("This warning should be displayed.");
checkBool(hasData(pipefd[0]), "data read (warn)");
fflush(pipeRead);
error("This error should be displayed."); error("This error should be displayed.");
checkBool(hasData(pipefd[0]), "data read (error)");
fflush(pipeRead);
setCriticalHandler(&criticalHandler); setCriticalHandler(&criticalHandler);
critical("This critical should be displayed."); critical("This critical should be displayed.");
checkBool(hasData(pipefd[0]), "data read (crititcal)");
fflush(pipeRead);
fclose(pipeWrite);
fclose(pipeRead);
}
volatile int counter = 0;
void timerThread() {
counter++;
}
void testTimers() {
timer_t timer = timer_createThreadTimer(&timerThread);
if (timer == NULL) {
showError();
return;
}
if (timer_startInterval(timer, 10) < 0) {
showError();
return;
}
sleep(1);
timer_stop(timer);
timer_destroy(timer);
checkInt(counter, 100, "interval count");
} }
handler_t handlerGetter(struct metaData metaData, const char* host) { handler_t handlerGetter(struct metaData metaData, const char* host) {
@ -115,24 +187,21 @@ void testNetworking() {
}); });
} }
void test(const char* name, void (*testFunction)()) {
printf("%s\n", name);
printf("%.*s\n", (int) strlen(name),
"===================================");
testFunction();
if (!global)
overall = false;
printf("%s: %s\n\n", name, global ? "OK" : "FAILED");
global = true;
}
int main(int argc, char** argv) { int main(int argc, char** argv) {
bool overall = true; test("linked lists", &testLinkedList);
test("logging", &testLogging);
printf("linked lists\n"); test("signals", &testTimers);
printf("============\n\n");
testLinkedList();
if (!global)
overall = false;
printf("linked lists: %s\n\n", global ? "OK" : "FAILED");
global = true;
printf("logging\n");
printf("============\n\n");
testLogging();
if (!global)
overall = false;
printf("logging: %s\n\n", global ? "OK" : "FAILED");
global = true;
printf("\nOverall: %s\n", overall ? "OK" : "FAILED"); printf("\nOverall: %s\n", overall ? "OK" : "FAILED");