123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244 |
- /*
- * timer.cpp
- *
- * Created on: Nov 9, 2015
- * Author: Philipp Hinz
- * Source: http://man7.org/linux/man-pages/man2/timer_create.2.html
- * http://www.informit.com/articles/article.aspx?p=23618&seqNum=14
- */
- #include <csignal>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <stdint.h>
- //#include <sys/time.h>
- #include <time.h>
- #include <pthread.h>
- #include <errno.h>
- //#include <unistd.h>
- #include "global.h"
- #include "timer.h"
- #include "logger.h"
- int counter = 0;
- int timercnt = 10;
- timer *firstTimer = NULL;
- timer *lastTimer = NULL;
- /**
- * Timer constructor
- * Depending on the call of the constructor the handler will be called as thread or not
- * @param *handler target pointer to the method
- */
- timer::timer(void (*handler)(void)) {
- this->active = false;
- this->divider = 0;
- this->handler = handler;
- this->thandler = NULL;
- this->next = firstTimer;
- this->asThread = false;
- this->id = timercnt++;
- this->thread = pthread_t();
- firstTimer = this;
- }
- timer::timer(void *(*handler)(void *)) {
- this->active = false;
- this->divider = 0;
- this->thandler = handler;
- this->handler = NULL;
- this->next = firstTimer;
- this->thread = pthread_t();
- this->id = timercnt++;
- // Now calling a dummy thread, to allow later the check of the thread state
- int rc = pthread_create(&this->thread, NULL, nullThread, (void *) this->id);
- if (rc) {
- logger_error("Error: unable to create thread in timer, %d\n", rc);
- exit(-1);
- }
- this->asThread = true;
- firstTimer = this;
- }
- /**
- * Calls the timer handler if enabled
- */
- // void *MainLoop(void *threadid)
- void timer::call() {
- int rc, ret = 0;
- if (this->asThread) {
- if (this->thread)
- ret = pthread_kill(this->thread, 0);
- if (ret == ESRCH) { // Thread clear
- pthread_detach(this->thread); // Important! Freeing the resources of the previous thread
- rc = pthread_create(&this->thread, NULL, this->thandler,
- (void *) this->id);
- if (rc) {
- logger_error(
- "Error: unable to create thread in timer, %s (%d)\n",
- strerror(rc), rc);
- exit(-1);
- }
- }
- } else
- this->handler();
- }
- /**
- * enables the timer
- */
- void timer::start() {
- this->active = true;
- }
- /**
- * disables the timer
- */
- void timer::stop() {
- this->active = false;
- }
- /**
- * sets the divider for this timer (based on system timer)
- * @param divider integer timer divider
- */
- void timer::setDivider(unsigned int divider) {
- this->divider = divider;
- }
- /**
- * reads the timer divider
- * @return timer divider
- */
- int timer::getDivider() {
- return this->divider;
- }
- /**
- * Returns the timers active state
- * @return true if active
- */
- bool timer::isActive() {
- return this->active;
- }
- /**
- * this method is called by the system timer and handles the other timers
- */
- void timer_handler(int sig, siginfo_t *si, void *uc) {
- timer *t = firstTimer;
- if (++counter >= TIMER_DELAY_US)
- counter = 0;
- while (t != NULL) {
- if (t->isActive() && t->getDivider() > 0
- && (counter % t->getDivider()) == 0)
- t->call();
- t = t->next;
- }
- }
- /**
- * inits the system timer based on signals
- */
- void initTimers(void) {
- /*struct sigaction sa;
- struct itimerval timer;
- * Install timer_handler as the signal handler for SIGVTALRM.
- memset(&sa, 0, sizeof(sa));
- sa.sa_handler = &timer_handler;
- sigaction(SIGVTALRM, &sa, NULL);*/
- timer_t timerid;
- struct sigevent sev;
- struct itimerspec its;
- //sigset_t mask;
- struct sigaction sa;
- /* Establish handler for timer signal */
- logger(V_BASIC, "timer.cpp: Establishing handler for signal %d\n", SIG);
- sa.sa_flags = SA_SIGINFO;
- sa.sa_sigaction = &timer_handler;
- sigemptyset(&sa.sa_mask);
- if (sigaction(SIG, &sa, NULL) == -1)
- errExit("sigaction");
- /* Block timer signal temporarily
- printf("Blocking signal %d\n", SIG);
- sigemptyset(&mask);
- sigaddset(&mask, SIG);
- if (sigprocmask(SIG_SETMASK, &mask, NULL) == -1)
- errExit("sigprocmask"); */
- /* Create the timer */
- sev.sigev_notify = SIGEV_SIGNAL;
- sev.sigev_signo = SIG;
- sev.sigev_value.sival_ptr = &timerid;
- if (timer_create(CLOCKID, &sev, &timerid) == -1)
- errExit("timer_create");
- logger(V_BASIC, "timer ID is 0x%lx\n", (long) timerid);
- /* Configure the timer to expire after x msec... */
- its.it_value.tv_sec = TIMER_DELAY_US / 1000000;
- its.it_value.tv_nsec = TIMER_DELAY_US * 1000;
- /* ... and every x msec after that. */
- its.it_interval.tv_sec = its.it_value.tv_sec;
- its.it_interval.tv_nsec = its.it_value.tv_nsec;
- /* Start a virtual timer. It counts down whenever this process is
- executing. */
- //setitimer(ITIMER_VIRTUAL, &timer, NULL);
- if (timer_settime(timerid, 0, &its, NULL) == -1)
- errExit("timer_settime");
- counter = 0;
- }
- /**
- * Calculates the divider corresponding to the given period.
- * If the given period does not match exactly to a divider, the
- * next higher is returned!
- */
- uint32_t ms2Divider(uint64_t millisec) {
- uint32_t divider = (millisec * 1000) / (uint64_t) TIMER_DELAY_US;
- if (((uint64_t) divider * TIMER_DELAY_US) < (millisec * 1000)) return ++divider;
- else return divider;
- }
- /**
- * Stops all existing timers
- */
- void stopTimers(void) {
- timer *t = firstTimer;
- while (t != NULL) {
- t->stop();
- t = t->next;
- }
- logger(V_BASIC, "Stopped all timers.\n");
- }
- /**
- * This is a dummy thread
- * @param *threadid Thread ID
- */
- void *nullThread(void *threadid) {
- pthread_exit(NULL);
- }
|