From 2487ad21511a08b1b29c28aeb893155cb779a8f8 Mon Sep 17 00:00:00 2001 From: pk910 Date: Wed, 19 Mar 2014 02:15:48 +0100 Subject: [PATCH] [IOMultiplexerV2] added CIOTimer class to c++ interface && added some features to IOTimer.c --- configure.ac | 1 + src/IOHandler++/IOTimer.cpp | 140 +++++++++++++++++++++++++ src/IOHandler++/IOTimer.h | 57 ++++++++++ src/IOHandler++/Makefile.am | 3 +- src/IOHandler/IOTimer.c | 135 ++++++++++++++++++------ src/IOHandler/IOTimer.h | 6 ++ src/IOHandler_test/Makefile.am | 2 +- src/IOHandler_test/timer++/.gitignore | 7 ++ src/IOHandler_test/timer++/Makefile.am | 7 ++ src/IOHandler_test/timer++/iotest.cpp | 66 ++++++++++++ 10 files changed, 389 insertions(+), 35 deletions(-) create mode 100644 src/IOHandler++/IOTimer.cpp create mode 100644 src/IOHandler++/IOTimer.h create mode 100644 src/IOHandler_test/timer++/.gitignore create mode 100644 src/IOHandler_test/timer++/Makefile.am create mode 100644 src/IOHandler_test/timer++/iotest.cpp diff --git a/configure.ac b/configure.ac index 318b98b..4275959 100644 --- a/configure.ac +++ b/configure.ac @@ -74,6 +74,7 @@ AC_CONFIG_FILES([ src/IOHandler_test/client_ssl/Makefile src/IOHandler_test/server_ssl/Makefile src/IOHandler_test/timer/Makefile + src/IOHandler_test/timer++/Makefile src/IOHandler_test/resolv/Makefile ]) AC_OUTPUT diff --git a/src/IOHandler++/IOTimer.cpp b/src/IOHandler++/IOTimer.cpp new file mode 100644 index 0000000..e6a2cd7 --- /dev/null +++ b/src/IOHandler++/IOTimer.cpp @@ -0,0 +1,140 @@ +/* IOTimer.cpp - IOMultiplexer v2 + * Copyright (C) 2014 Philipp Kreil (pk910) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU 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 a copy of the GNU General Public License + * along with this program. If not, see . + */ +extern "C" { + #include "../IOHandler/IOTimer.h" +} +#include "IOTimer.h" +#include +#include +#include + +static IOTIMER_CALLBACK(c_timer_callback) { + CIOTimer *ciotimer = (CIOTimer *) iotimer->data; + ciotimer->timer_callback(); +} + +CIOTimer::CIOTimer() { + this->iotimer = iotimer_create(NULL); + this->iotimer->data = this; + iotimer_set_callback(this->iotimer, c_timer_callback); + iotimer_set_persistent(this->iotimer, 1); +} + +CIOTimer::~CIOTimer() { + iotimer_destroy(this->iotimer); +} + +void CIOTimer::setTimeout(timeval timeout) { + iotimer_set_timeout(this->iotimer, &timeout); +} + +void CIOTimer::setRelativeTimeout(timeval timeout) { + timeval now; + gettimeofday(&now, NULL); + + timeout.tv_sec += now.tv_sec; + timeout.tv_usec += now.tv_usec; + while(timeout.tv_usec > 1000000) { + timeout.tv_usec -= 1000000; + timeout.tv_sec++; + } + + this->setTimeout(timeout); +} + +void CIOTimer::setRelativeTimeout(timeval timeout, int auto_reload) { + this->setRelativeTimeout(timeout); + if(auto_reload) + this->setAutoReload(timeout); +} + +void CIOTimer::setRelativeTimeoutSeconds(double seconds) { + this->setRelativeTimeoutSeconds(seconds, 0); +} + +void CIOTimer::setRelativeTimeoutSeconds(double seconds, int auto_reload) { + timeval tout; + tout.tv_sec = (int) seconds; + tout.tv_usec = ((int) (seconds * 1000000)) % 1000000; + this->setRelativeTimeout(tout); + if(auto_reload) + this->setAutoReload(tout); +} + +timeval CIOTimer::getTimeout() { + return iotimer_get_timeout(this->iotimer); +} + +timeval CIOTimer::getRelativeTimeout() { + timeval tout, now; + gettimeofday(&now, NULL); + + tout = iotimer_get_timeout(this->iotimer); + + if(tout.tv_sec || tout.tv_usec) { + tout.tv_sec = tout.tv_sec - now.tv_sec; + tout.tv_usec = tout.tv_usec - now.tv_usec; + if(tout.tv_usec < 0) { + tout.tv_usec += 1000000; + tout.tv_sec--; + } + } + + return tout; +} + +double CIOTimer::getRelativeTimeoutSeconds() { + timeval tout = this->getRelativeTimeout(); + return tout.tv_sec + (tout.tv_usec / 1000000); +} + + +void CIOTimer::setAutoReload(timeval timeout) { + iotimer_set_autoreload(this->iotimer, &timeout); +} + +void CIOTimer::clearAutoReload() { + iotimer_set_autoreload(this->iotimer, NULL); +} + +timeval CIOTimer::getAutoReloadTime() { + return iotimer_get_autoreload(this->iotimer); +} + +int CIOTimer::getAutoReloadState() { + timeval timeout = this->getAutoReloadTime(); + if(timeout.tv_sec == 0 && timeout.tv_usec == 0) + return 0; + else + return 1; +} + +void CIOTimer::setActive(int active) { + if(active) + iotimer_start(this->iotimer); + else + iotimer_stop(this->iotimer); +} + +int CIOTimer::getActive() { + return iotimer_state(this->iotimer); +} + +void CIOTimer::timer_callback() { + this->timeout(); +} + diff --git a/src/IOHandler++/IOTimer.h b/src/IOHandler++/IOTimer.h new file mode 100644 index 0000000..df586a5 --- /dev/null +++ b/src/IOHandler++/IOTimer.h @@ -0,0 +1,57 @@ +/* IOTimer.h - IOMultiplexer v2 + * Copyright (C) 2014 Philipp Kreil (pk910) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU 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 a copy of the GNU General Public License + * along with this program. If not, see . + */ +#ifndef _IOTimer_cpp_h +#define _IOTimer_cpp_h + +#include +#include +#include + +struct IOTimerDescriptor; + +class CIOTimer { +public: + CIOTimer(); + ~CIOTimer(); + + void setTimeout(timeval timeout); + timeval getTimeout(); + void setRelativeTimeout(timeval timeout); + void setRelativeTimeout(timeval timeout, int auto_reload); + timeval getRelativeTimeout(); + void setRelativeTimeoutSeconds(double seconds); + void setRelativeTimeoutSeconds(double seconds, int auto_reload); + double getRelativeTimeoutSeconds(); + + void setAutoReload(timeval timeout); + void clearAutoReload(); + int getAutoReloadState(); + timeval getAutoReloadTime(); + + void setActive(int active); + int getActive(); + + + void timer_callback(); +protected: + virtual void timeout() {}; + +private: + IOTimerDescriptor *iotimer; +}; + +#endif diff --git a/src/IOHandler++/Makefile.am b/src/IOHandler++/Makefile.am index df2e17c..681f9fb 100644 --- a/src/IOHandler++/Makefile.am +++ b/src/IOHandler++/Makefile.am @@ -5,7 +5,8 @@ noinst_LTLIBRARIES = libiohandler.cpp.la libiohandler_cpp_la_LIBADD = ../IOHandler/libiohandler.la libiohandler_cpp_la_SOURCES = IOHandler.cpp \ -IOSocket.cpp +IOSocket.cpp \ +IOTimer.cpp all-local: libiohandler.cpp.la \ No newline at end of file diff --git a/src/IOHandler/IOTimer.c b/src/IOHandler/IOTimer.c index 7764831..784ab76 100644 --- a/src/IOHandler/IOTimer.c +++ b/src/IOHandler/IOTimer.c @@ -51,12 +51,37 @@ struct IOTimerDescriptor *iotimer_create(struct timeval *timeout) { void iotimer_start(struct IOTimerDescriptor *descriptor) { struct _IOTimerDescriptor *timer = descriptor->iotimer; if(timer == NULL) { - iolog_trigger(IOLOG_WARNING, "called iotimer_set_autoreload for destroyed IOTimerDescriptor in %s:%d", __FILE__, __LINE__); + iolog_trigger(IOLOG_WARNING, "called iotimer_start for destroyed IOTimerDescriptor in %s:%d", __FILE__, __LINE__); return; } timer->flags |= IOTIMERFLAG_ACTIVE; - if(!(timer->flags & IOTIMERFLAG_IN_LIST)) - _trigger_timer(timer); + _rearrange_timer(timer); +} + +void iotimer_stop(struct IOTimerDescriptor *descriptor) { + struct _IOTimerDescriptor *timer = descriptor->iotimer; + if(timer == NULL) { + iolog_trigger(IOLOG_WARNING, "called iotimer_stop for destroyed IOTimerDescriptor in %s:%d", __FILE__, __LINE__); + return; + } + timer->flags &= ~IOTIMERFLAG_ACTIVE; + if((timer->flags & IOTIMERFLAG_PERSISTENT)) { + timer->flags &= ~IOTIMERFLAG_ACTIVE; + _rearrange_timer(timer); + } else + iotimer_destroy(descriptor); +} + +int iotimer_state(struct IOTimerDescriptor *descriptor) { + struct _IOTimerDescriptor *timer = descriptor->iotimer; + if(timer == NULL) { + iolog_trigger(IOLOG_WARNING, "called iotimer_state for destroyed IOTimerDescriptor in %s:%d", __FILE__, __LINE__); + return 0; + } + if((timer->flags & IOTIMERFLAG_ACTIVE)) + return 1; + else + return 0; } void iotimer_set_autoreload(struct IOTimerDescriptor *descriptor, struct timeval *autoreload) { @@ -69,7 +94,7 @@ void iotimer_set_autoreload(struct IOTimerDescriptor *descriptor, struct timeval timer->flags |= IOTIMERFLAG_PERIODIC; timer->autoreload = *autoreload; - if(!(timer->flags & IOTIMERFLAG_IN_LIST)) { + if(timer->timeout.tv_sec == 0 && timer->timeout.tv_usec == 0) { struct timeval now; gettimeofday(&now, NULL); timer->timeout = now; @@ -80,6 +105,25 @@ void iotimer_set_autoreload(struct IOTimerDescriptor *descriptor, struct timeval } } +struct timeval iotimer_get_autoreload(struct IOTimerDescriptor *descriptor) { + struct _IOTimerDescriptor *timer = descriptor->iotimer; + if(timer == NULL) { + iolog_trigger(IOLOG_WARNING, "called iotimer_get_autoreload for destroyed IOTimerDescriptor in %s:%d", __FILE__, __LINE__); + struct timeval tout; + tout.tv_sec = 0; + tout.tv_usec = 0; + return tout; + } + if((timer->flags & IOTIMERFLAG_PERIODIC)) + return timer->autoreload; + else { + struct timeval tout; + tout.tv_sec = 0; + tout.tv_usec = 0; + return tout; + } +} + void iotimer_set_timeout(struct IOTimerDescriptor *descriptor, struct timeval *timeout) { struct _IOTimerDescriptor *timer = descriptor->iotimer; if(timer == NULL) { @@ -94,10 +138,34 @@ void iotimer_set_timeout(struct IOTimerDescriptor *descriptor, struct timeval *t _rearrange_timer(timer); } +struct timeval iotimer_get_timeout(struct IOTimerDescriptor *descriptor) { + struct _IOTimerDescriptor *timer = descriptor->iotimer; + if(timer == NULL) { + iolog_trigger(IOLOG_WARNING, "called iotimer_get_timeout for destroyed IOTimerDescriptor in %s:%d", __FILE__, __LINE__); + struct timeval tout; + tout.tv_sec = 0; + tout.tv_usec = 0; + return tout; + } + return timer->timeout; +} + void iotimer_set_callback(struct IOTimerDescriptor *descriptor, iotimer_callback *callback) { descriptor->callback = callback; } +void iotimer_set_persistent(struct IOTimerDescriptor *descriptor, int persistent) { + struct _IOTimerDescriptor *timer = descriptor->iotimer; + if(timer == NULL) { + iolog_trigger(IOLOG_WARNING, "called iotimer_set_persistent for destroyed IOTimerDescriptor in %s:%d", __FILE__, __LINE__); + return; + } + if(persistent) + timer->flags |= IOTIMERFLAG_PERSISTENT; + else + timer->flags &= ~IOTIMERFLAG_PERSISTENT; +} + void iotimer_destroy(struct IOTimerDescriptor *descriptor) { struct _IOTimerDescriptor *timer = descriptor->iotimer; if(timer == NULL) { @@ -121,10 +189,8 @@ struct _IOTimerDescriptor *_create_timer(struct timeval *timeout) { iolog_trigger(IOLOG_ERROR, "could not allocate memory for _IOTimerDescriptor in %s:%d", __FILE__, __LINE__); return NULL; } - if(timeout) { + if(timeout) timer->timeout = *timeout; - _rearrange_timer(timer); - } return timer; } @@ -136,7 +202,10 @@ static void _rearrange_timer(struct _IOTimerDescriptor *timer) { timer->prev->next = timer->next; if(timer->next != NULL) timer->next->prev = timer->prev; + timer->flags &= ~IOTIMERFLAG_IN_LIST; } + if(!(timer->flags & IOTIMERFLAG_ACTIVE)) + return; struct _IOTimerDescriptor *ctimer; for(ctimer = iotimer_sorted_descriptors; ctimer; ctimer = ctimer->next) { if(timeval_is_bigger(ctimer->timeout, timer->timeout)) { @@ -184,32 +253,32 @@ static void _autoreload_timer(struct _IOTimerDescriptor *timer) { void _trigger_timer() { struct timeval now; - _trigger_timer_start: - gettimeofday(&now, NULL); - - struct _IOTimerDescriptor *timer = iotimer_sorted_descriptors; - if(!timer || timeval_is_bigger(timer->timeout, now)) { - return; - } - iotimer_sorted_descriptors = timer->next; - if(timer->next != NULL) - timer->next->prev = timer->prev; - timer->flags &= ~IOTIMERFLAG_IN_LIST; - - if((timer->flags & IOTIMERFLAG_PERIODIC)) - _autoreload_timer(timer); - - if(timer->flags & IOTIMERFLAG_PARENT_PUBLIC) { - struct IOTimerDescriptor *descriptor = timer->parent; - if(descriptor->callback) - descriptor->callback(descriptor); - if(!(timer->flags & IOTIMERFLAG_PERIODIC)) - iotimer_destroy(descriptor); - } else { - if(!(timer->flags & IOTIMERFLAG_PERIODIC)) - _destroy_timer(timer); + struct _IOTimerDescriptor *timer; + while(iotimer_sorted_descriptors) { + gettimeofday(&now, NULL); + + timer = iotimer_sorted_descriptors; + if(timeval_is_bigger(timer->timeout, now)) + break; + + iotimer_sorted_descriptors = timer->next; + if(timer->next != NULL) + timer->next->prev = timer->prev; + timer->flags &= ~IOTIMERFLAG_IN_LIST; + + if((timer->flags & IOTIMERFLAG_PERIODIC)) + _autoreload_timer(timer); + + if(timer->flags & IOTIMERFLAG_PARENT_PUBLIC) { + struct IOTimerDescriptor *descriptor = timer->parent; + if(descriptor->callback) + descriptor->callback(descriptor); + if(!(timer->flags & IOTIMERFLAG_PERIODIC)) + iotimer_destroy(descriptor); + } else { + if(!(timer->flags & IOTIMERFLAG_PERIODIC)) + _destroy_timer(timer); + } } - - goto _trigger_timer_start; } diff --git a/src/IOHandler/IOTimer.h b/src/IOHandler/IOTimer.h index 1a42264..e67ee6f 100644 --- a/src/IOHandler/IOTimer.h +++ b/src/IOHandler/IOTimer.h @@ -27,6 +27,7 @@ #define IOTIMERFLAG_IN_LIST 0x04 #define IOTIMERFLAG_PARENT_PUBLIC 0x08 #define IOTIMERFLAG_PARENT_SOCKET 0x10 +#define IOTIMERFLAG_PERSISTENT 0x20 struct _IOTimerDescriptor; @@ -63,9 +64,14 @@ struct IOTimerDescriptor { struct IOTimerDescriptor *iotimer_create(struct timeval *timeout); void iotimer_start(struct IOTimerDescriptor *iotimer); +void iotimer_stop(struct IOTimerDescriptor *iotimer); +int iotimer_state(struct IOTimerDescriptor *iotimer); void iotimer_set_autoreload(struct IOTimerDescriptor *iotimer, struct timeval *autoreload); +struct timeval iotimer_get_autoreload(struct IOTimerDescriptor *iotimer); void iotimer_set_timeout(struct IOTimerDescriptor *iotimer, struct timeval *timeout); +struct timeval iotimer_get_timeout(struct IOTimerDescriptor *iotimer); void iotimer_set_callback(struct IOTimerDescriptor *iotimer, iotimer_callback *callback); +void iotimer_set_persistent(struct IOTimerDescriptor *iotimer, int persistent); void iotimer_destroy(struct IOTimerDescriptor *iotimer); #endif diff --git a/src/IOHandler_test/Makefile.am b/src/IOHandler_test/Makefile.am index e8c6698..d8ca43d 100644 --- a/src/IOHandler_test/Makefile.am +++ b/src/IOHandler_test/Makefile.am @@ -1,3 +1,3 @@ ##Process this file with automake to create Makefile.in ACLOCAL_AMFLAGS = -I m4 -SUBDIRS = client client++ client_ssl server_ssl timer resolv +SUBDIRS = client client++ client_ssl server_ssl timer timer++ resolv diff --git a/src/IOHandler_test/timer++/.gitignore b/src/IOHandler_test/timer++/.gitignore new file mode 100644 index 0000000..7af2f69 --- /dev/null +++ b/src/IOHandler_test/timer++/.gitignore @@ -0,0 +1,7 @@ +.deps +.libs +*.o +*.exe +iotest +Makefile +Makefile.in diff --git a/src/IOHandler_test/timer++/Makefile.am b/src/IOHandler_test/timer++/Makefile.am new file mode 100644 index 0000000..0591fea --- /dev/null +++ b/src/IOHandler_test/timer++/Makefile.am @@ -0,0 +1,7 @@ +##Process this file with automake to create Makefile.in +ACLOCAL_AMFLAGS = -I m4 + +noinst_PROGRAMS = iotest + +iotest_LDADD = ../../IOHandler++/libiohandler.cpp.la +iotest_SOURCES = iotest.cpp diff --git a/src/IOHandler_test/timer++/iotest.cpp b/src/IOHandler_test/timer++/iotest.cpp new file mode 100644 index 0000000..6c6fd9b --- /dev/null +++ b/src/IOHandler_test/timer++/iotest.cpp @@ -0,0 +1,66 @@ +/* main.c - IOMultiplexer + * Copyright (C) 2012 Philipp Kreil (pk910) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU 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 a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include "../../IOHandler++/IOHandler.h" +#include "../../IOHandler++/IOTimer.h" + +class IOTestTimer : public CIOTimer { +public: + IOTestTimer(int test_duration) : CIOTimer() { + this->tick_count = 0; + this->test_duration = test_duration; + gettimeofday(&this->test_clock1, NULL); + gettimeofday(&this->test_clock2, NULL); + + this->setRelativeTimeoutSeconds(this->test_duration / 1000.0, 1); + this->setActive(1); + + printf("[timer 0] %ld.%ld\n", test_clock1.tv_sec, test_clock1.tv_usec); + }; + +protected: + virtual void timeout() { + this->tick_count++; + this->tick(); + }; + +private: + timeval test_clock1, test_clock2; + int tick_count, test_duration; + + void tick() { + timeval curr_time; + int diff1; + double diff2; + + gettimeofday(&curr_time, NULL); + diff1 = (curr_time.tv_sec - this->test_clock1.tv_sec) * 1000 + ((curr_time.tv_usec - this->test_clock1.tv_usec) / 1000); + diff2 = (curr_time.tv_sec - this->test_clock2.tv_sec) * 1000 + ((curr_time.tv_usec - this->test_clock2.tv_usec) / 1000.0); + diff2 -= (this->tick_count * this->test_duration); + gettimeofday(&this->test_clock1, NULL); + printf("[timer %03d] %ld.%06ld [%d ms] accuracy: %f ms\n", this->tick_count, curr_time.tv_sec, curr_time.tv_usec, diff1, diff2); + }; +}; + + +int main(int argc, char *argv[]) { + CIOHandler *iohandler = new CIOHandler(); + IOTestTimer *timer = new IOTestTimer(100); + + iohandler->start(); +} -- 2.20.1