diff --git a/CppTimer.cpp b/CppTimer.cpp new file mode 100644 index 0000000..a8c75d0 --- /dev/null +++ b/CppTimer.cpp @@ -0,0 +1,97 @@ +#include "CppTimer.h" +#include + +/** + * GNU GENERAL PUBLIC LICENSE + * Version 3, 29 June 2007 + * + * (C) 2020, Bernd Porr + * + * This is inspired by the timer_create man page. + **/ + +CppTimer::CppTimer() { + // We create a static handler catches the signal SIG + sa.sa_flags = SA_SIGINFO; + sa.sa_sigaction = handler; + sigemptyset(&sa.sa_mask); + if (sigaction(SIG, &sa, NULL) == -1) + throw("Could not create signal handler"); + + if(pipe(pipeFd) < 0) + throw("Could not create pipe"); + + // Create the timer + sev.sigev_notify = SIGEV_SIGNAL; + sev.sigev_signo = SIG; + // Cruical is that the signal carries the pointer to this class instance here + // because the handler just handles anything that comes in! + sev.sigev_value.sival_ptr = this; + // create the timer + if (timer_create(CLOCKID, &sev, &timerid) == -1) + throw("Could not create timer"); +}; + +void CppTimer::start(long nanosecs,std::function callbackIn, int type) { + switch(type){ + case(PERIODIC): + //starts after specified period of nanoseconds + its.it_value.tv_sec = nanosecs / 1000000000; + its.it_value.tv_nsec = nanosecs % 1000000000; + its.it_interval.tv_sec = nanosecs / 1000000000; + its.it_interval.tv_nsec = nanosecs % 1000000000; + break; + case(ONESHOT): + //fires once after specified period of nanoseconds + its.it_value.tv_sec = nanosecs / 1000000000; + its.it_value.tv_nsec = nanosecs % 1000000000; + its.it_interval.tv_sec = 0; + its.it_interval.tv_nsec = 0; + break; + } + callback = callbackIn; + if (timer_settime(timerid, 0, &its, NULL) == -1) + throw("Could not start timer"); + discardPipe(); + running = true; +} + +void CppTimer::discardPipe() { + char buf; + fcntl(pipeFd[0], F_SETFL, O_NONBLOCK); + while(read(pipeFd[0], &buf, 1) > 0); + fcntl(pipeFd[0], F_SETFL, 0); +} + +void CppTimer::block() +{ + if(running) + { + char buf; + read(pipeFd[0], &buf, 1); + } +} + +void CppTimer::stop() { + // disarm + struct itimerspec itsnew; + itsnew.it_value.tv_sec = 0; + itsnew.it_value.tv_nsec = 0; + itsnew.it_interval.tv_sec = 0; + itsnew.it_interval.tv_nsec = 0; + timer_settime(timerid, 0, &itsnew, &its); + running = false; +} + +bool CppTimer::isRunning() +{ + return running; +} + +CppTimer::~CppTimer() { + stop(); + // delete the timer + timer_delete(timerid); + // default action for signal handling + signal(SIG, SIG_IGN); +} diff --git a/CppTimer.h b/CppTimer.h new file mode 100644 index 0000000..0465465 --- /dev/null +++ b/CppTimer.h @@ -0,0 +1,85 @@ +#ifndef __CPP_TIMER_H_ +#define __CPP_TIMER_H_ + +/** + * GNU GENERAL PUBLIC LICENSE + * Version 3, 29 June 2007 + * + * (C) 2020, Bernd Porr + * + * This is inspired by the timer_create man page. + **/ + +#include +#include +#include +#include +#include +#include +#include + +#define CLOCKID CLOCK_MONOTONIC +#define SIG SIGRTMIN + +/** + * Timer class which repeatedly fires. It's wrapper around the + * POSIX per-process timer. + **/ +class CppTimer { + +public: + static constexpr int PERIODIC = 0; + static constexpr int ONESHOT = 1; + static constexpr long MS_TO_NS = 1000000; + /** + * Creates an instance of the timer and connects the + * signal handler to the timer. + **/ + CppTimer(); + + /** + * Starts the timer. The timer fires first after + * the specified time in nanoseconds and then at + * that interval in PERIODIC mode. In ONESHOT mode + * the timer fires once after the specified time in + * nanoseconds. + **/ + virtual void start(long nanosecs, std::function callbackIn, int type = PERIODIC); + + /** + * Stops the timer by disarming it. It can be re-started + * with start(). + **/ + virtual void stop(); + + /** + * Destructor disarms the timer, deletes it and + * disconnect the signal handler. + **/ + virtual ~CppTimer(); + + bool isRunning(); + + void block(); + +private: + timer_t timerid = 0; + struct sigevent sev; + struct sigaction sa; + struct itimerspec its; + int pipeFd[2]; + std::atomic running = false; + std::function callback; + void discardPipe(); + + static void handler(int sig, siginfo_t *si, void *uc ) { + CppTimer *timer = reinterpret_cast (si->si_value.sival_ptr); + timer->callback(); + char buf = '\n'; + write(timer->pipeFd[1], &buf, 1); + timer->running = false; + } +}; + + +#endif diff --git a/debian/changelog b/debian/changelog index 07b432a..3a3e737 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,8 +1,8 @@ sigstoped (1.0.5) unstable; urgency=medium - Configureable timout for applications to close their windows. - Fix 5sec stall when switching from an application to be stopped to an application that was stopped before. - Make Xinstance thread safe - -- Uvos Wed, 01 Jul Jun 2020 09:47:00 +0100 + Configureable timout for applications to close their windows. + Fix 5sec stall when switching from an application to be stopped to an application that was stopped before. + Make Xinstance thread safe +-- Uvos Mon, 16 Jun 2020 09:47:00 +0100 sigstoped (1.0.4) unstable; urgency=medium Fix memory leak in XInstance::getTopLevelWindows()