diff --git a/Makefile b/Makefile index 35fb163..94f579a 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ CC = gcc -CFLAGS = -Wall -Wpedantic +CFLAGS = -std=c99 -Wall -D_POSIX_C_SOURCE=199506L LD = gcc LDFLAGS = -lpthread -lrt @@ -7,16 +7,17 @@ BIN_NAME = cfloor 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 $@ $^ valgrind: CFLAGS += -static -g valgrind: clean 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/linked.o: src/linked.h obj/loggin.o: src/logging.h +obj/signals.o: src/signals.h obj/%.o: src/%.c obj $(CC) $(CFLAGS) -c -o $@ $< diff --git a/src/signals.c b/src/signals.c new file mode 100644 index 0000000..af87f1b --- /dev/null +++ b/src/signals.c @@ -0,0 +1,102 @@ +#include +#include +#include +#include + +#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); +} diff --git a/src/signals.h b/src/signals.h new file mode 100644 index 0000000..d810052 --- /dev/null +++ b/src/signals.h @@ -0,0 +1,20 @@ +#ifndef SIGNALS_H +#define SIGNALS_H + +#include + +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 diff --git a/src/test.c b/src/test.c index c9fe21b..e0eb5be 100644 --- a/src/test.c +++ b/src/test.c @@ -2,12 +2,20 @@ #include #include #include +#include +#include +#include +#include +#include +#include #include "networking.h" #include "linked.h" #include "logging.h" +#include "signals.h" bool global = true; +bool overall = true; void checkBool(bool ok, const char* check) { const char* result; @@ -33,6 +41,10 @@ void checkNull(void* value, const char* check) { checkBool(value != NULL, check); } +void showError() { + fprintf(stderr, "Error: %s\n", strerror(errno)); +} + void testLinkedList() { linkedList_t list = linked_create(); @@ -85,20 +97,80 @@ void testLinkedList() { 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() { printf("This is the critical handler.\n"); printBacktrace(); } 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); info("This info should not be displayed."); + checkBool(!hasData(pipefd[0]), "no data read (info)"); + warn("This warning should be displayed."); + checkBool(hasData(pipefd[0]), "data read (warn)"); + fflush(pipeRead); + error("This error should be displayed."); + checkBool(hasData(pipefd[0]), "data read (error)"); + fflush(pipeRead); setCriticalHandler(&criticalHandler); 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) { @@ -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) { - bool overall = true; - - printf("linked lists\n"); - 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; + test("linked lists", &testLinkedList); + test("logging", &testLogging); + test("signals", &testTimers); printf("\nOverall: %s\n", overall ? "OK" : "FAILED");