From 77024bd50fdc4e4bc967dc1884a0d9a34bd35b8c Mon Sep 17 00:00:00 2001 From: hama Date: Thu, 9 Jun 2016 00:20:16 +0200 Subject: [PATCH] Timer works without memory leaks --- .gitignore | 12 +++++++++ Server/Makefile | 2 +- Server/cpidjinn.hpp | 1 + Server/gpiotimer.cpp | 58 +++++++++++++++++++++++++++++++++++++++++ Server/gpiotimer.hpp | 50 +++++++++++++++++++++++++++++++++++ util/thread.cpp | 31 +++++++--------------- util/thread.hpp | 2 ++ util/timer.cpp | 62 ++++++++++++++++++++++++-------------------- util/timer.hpp | 5 ++-- 9 files changed, 171 insertions(+), 52 deletions(-) create mode 100644 Server/gpiotimer.cpp create mode 100644 Server/gpiotimer.hpp diff --git a/.gitignore b/.gitignore index 874c63c..8fab621 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,14 @@ *.o +Server/cpidjinn +Server/client +*.kdev4 +util/test +src/ +*.gdb +cl +cl.gdb +sv +sv.gdb +sv.sh +util/test.wav diff --git a/Server/Makefile b/Server/Makefile index c07910b..7593f79 100644 --- a/Server/Makefile +++ b/Server/Makefile @@ -4,7 +4,7 @@ CFLAGS = -Wall LDFLAGS = -lbcm2835 -lpthread OBJ_UTIL = timer.o thread.o dynbuffer.o logger.o -OBJ = cpidjinn.o $(OBJ_UTIL) tcpserver.o gpioprocessor.o +OBJ = gpiotimer.o cpidjinn.o $(OBJ_UTIL) tcpserver.o gpioprocessor.o PROG = cpidjinn OBJ_CLIENT = $(OBJ_UTIL) tcpclient.o client.o diff --git a/Server/cpidjinn.hpp b/Server/cpidjinn.hpp index 49cb5c1..c4cd173 100644 --- a/Server/cpidjinn.hpp +++ b/Server/cpidjinn.hpp @@ -2,4 +2,5 @@ #include "util.hpp" #include "tcpserver.hpp" #include "gpioprocessor.hpp" +#include "gpiotimer.hpp" #endif diff --git a/Server/gpiotimer.cpp b/Server/gpiotimer.cpp new file mode 100644 index 0000000..50c9847 --- /dev/null +++ b/Server/gpiotimer.cpp @@ -0,0 +1,58 @@ +#include "cpidjinn.hpp" + +/** + * Constructor. + * + * @param pin the pin where the data will be transferred + * @param pause pause in microseconds befor starting the first hight state + * @param logger the logger + */ +GPIOTimer::GPIOTimer(int pin, uint64_t pause, Announcer* logger) : + Timer(1, 0, pause, uMicroSeconds, true, logger), + m_pin(pin) +{ +} + +/** + * Destructor. + */ +GPIOTimer::~GPIOTimer() { + +} + +/** + * Switches the state of a pin. + * + * @param high true: the state will be set to high + */ +void GPIOTimer::switchState(bool high){ + m_logger->sayf(LOG_DEBUG, "%d: %c", m_pin, high ? 'H' : 'L'); +} +/** + * Constructor. + * + * @param pin the target pin + * @param pause the pause (in microseconds) to wait before starting the wave + * @param count the number of high states to create + * @param high the duration of the high state in microseconds + * @param low the duration of the low state in microseconds + */ +SquareWaveTimer::SquareWaveTimer(int pin, uint64_t pause, int count, + uint64_t high, uint64_t low, Announcer* logger) : + GPIOTimer(pin, pause, logger), + m_pause(pause), + m_high(high), + m_low(low), + m_nextHigh(false){ + // high + low = factor 2: + m_count = count * 2; +} + +/** + * The action done from the timer. + */ +void SquareWaveTimer::timerTask(){ + m_nextHigh = ! m_nextHigh; + switchState(m_nextHigh); + m_delay = m_nextHigh ? m_high : m_low; +} diff --git a/Server/gpiotimer.hpp b/Server/gpiotimer.hpp new file mode 100644 index 0000000..4205419 --- /dev/null +++ b/Server/gpiotimer.hpp @@ -0,0 +1,50 @@ +#ifndef GPIOTIMER_H +#define GPIOTIMER_H + +/** + * Abstract base class for controlling "General input output" pins. + */ +class GPIOTimer : public Timer { +public: + GPIOTimer(int pin, uint64_t pause, Announcer* logger); + virtual ~GPIOTimer(); +private: + // not implemented, private to avoid usage + GPIOTimer ( const GPIOTimer& other ); + GPIOTimer& operator= ( const GPIOTimer& other ); +protected: + void switchState(bool high); +protected: + int m_pin; +}; + +/** + * A timer producing a square wave with constant frequency. + */ +class SquareWaveTimer : public GPIOTimer{ +public: + SquareWaveTimer(int pin, uint64_t pause, int count, + uint64_t high, uint64_t low, Announcer* logger); +public: + virtual void timerTask(); +private: + int m_count; + uint64_t m_pause; + uint64_t m_high; + uint64_t m_low; + bool m_nextHigh; +}; + +/** + * A timer producing a melody. + * + * A melody is a squence of square waves with different frequencies. + */ +class MelodyTimer : public GPIOTimer{ +public: + MelodyTimer(int pin, DynBuffer& melody); +public: + virtual void timerTask(); +}; + +#endif // GPIOTIMER_H diff --git a/util/thread.cpp b/util/thread.cpp index 41ac1e6..dc0beb9 100644 --- a/util/thread.cpp +++ b/util/thread.cpp @@ -5,15 +5,13 @@ int ThreadPool::m_currentMaxThreads = 128; ThreadPool* ThreadPool::m_instance = NULL; const pthread_mutex_t ThreadPool::m_mutexInitializer = PTHREAD_MUTEX_INITIALIZER; - -int gv_rounds = 0; -int gv_calls; +pthread_mutex_t Thread::m_mutexStarter = PTHREAD_MUTEX_INITIALIZER; /** * Connects the posix thread to the class instance. */ void* threadStarter(void *param){ - trace("threadstarter"); + trace1("threadstarter(%llx)", (uint64_t) param); Thread* thread = reinterpret_cast(param); thread->execute(); return param; @@ -53,10 +51,12 @@ void Thread::execute(){ m_running = true; run(); m_pool.remove(*this); + pthread_t pthread = m_pthread; if (m_autoDelete){ trace1("Thread::execute(%d) autodelete\n", m_threadId); delete this; } + pthread_detach(pthread); } /** @@ -75,8 +75,10 @@ void Thread::microSleep(uint64_t microseconds){ * Lets the thread run. */ void Thread::start(){ - pthread_create(&m_pthread, NULL, &threadStarter, this); + pthread_attr_t attr; + pthread_attr_init(&attr); trace2("Thread::start(%d): %lx\n", m_threadId, m_pthread); + pthread_create(&m_pthread, &attr, &threadStarter, this); } /** * Introduces the termination of the thread. @@ -166,27 +168,14 @@ void* ThreadPool::join(int threadId){ trace1("ThreadPool::join(%d):\n", threadId); void* rc = NULL; Thread* thread = NULL; - pthread_t pthread = -1; - bool running = false; do { lock(); thread = findById(threadId); - if(thread == NULL){ - unlock(); - break; - } else { - pthread = thread->m_pthread; - running = thread->m_running; - } unlock(); - if (! running) + if (thread != NULL) Thread::microSleep(10*1000); - } while(! running); - trace2("join: thread: %c %lx\n", thread != NULL ? 't' : 'f', pthread); - // Does the thread already exist? - if (pthread != (pthread_t) -1) - pthread_join(pthread, &rc); - trace1("join: rc: %c\n", rc == NULL ? 't' : 'f'); + } while(thread != NULL); + trace2("join: thread: %c %llx\n", thread != NULL ? 't' : 'f', (uint64_t) thread); return rc; } diff --git a/util/thread.hpp b/util/thread.hpp index 484b9d3..6840c40 100644 --- a/util/thread.hpp +++ b/util/thread.hpp @@ -28,6 +28,8 @@ public: private: friend void* threadStarter(void *); void execute(); +private: + static pthread_mutex_t m_mutexStarter; protected: int m_threadId; bool m_shouldStop; diff --git a/util/timer.cpp b/util/timer.cpp index 92fff64..13a0a93 100644 --- a/util/timer.cpp +++ b/util/timer.cpp @@ -16,7 +16,7 @@ Timer::Timer(int count, int delay, int m_startDelay, Unit unit, bool autoDelete, Announcer* logger, ThreadPool* pool) : Thread(logger, autoDelete, pool), - m_count(count), + m_taskCount(count), m_delay(delay), m_startDelay(delay), m_unit(unit) @@ -33,35 +33,41 @@ Timer::~Timer() { */ void Timer::run(){ trace1("Timer::run(%d)\n", threadId()); - if (m_startDelay > 0){ - switch (m_unit){ - case uSeconds: - sleep(m_startDelay); - break; - case uMilliSeconds: - microSleep(m_startDelay * 1000); - break; - case uMicroSeconds: - default: - microSleep(m_startDelay); - break; - } + if (! m_shouldStop && m_startDelay > 0){ + sleep(m_startDelay); } - while(m_count-- > 0){ + while(! m_shouldStop && m_taskCount-- > 0){ trace2("Timer::run(%d): %d\n", threadId(), m_count); timerTask(); - switch (m_unit){ - case Timer::uSeconds: - sleep(m_delay); - break; - case Timer::uMilliSeconds: - microSleep(m_delay * 1000); - break; - case Timer::uMicroSeconds: - usleep(m_delay); - break; - default: - break; - } + sleep(m_delay); } } + +/** + * Sleeps a given amount of microseconds. + * + * The sleep is broken if a stop request is done. + * + * @param units time to wait in units given by m_unit + */ +void Timer::sleep(int units){ + uint64_t microseconds; + switch (m_unit){ + case uSeconds: + microseconds = units * (uint64_t) 1000000; + break; + case uMilliSeconds: + microseconds = units * (uint64_t) 1000; + break; + case uMicroSeconds: + default: + microseconds = units; + break; + } + while(! m_shouldStop && microseconds >= (uint64_t) 2000000){ + sleep(1); + microseconds -= 1000000; + } + if (! m_shouldStop) + Thread::microSleep(microseconds); +} diff --git a/util/timer.hpp b/util/timer.hpp index 95e1da2..3d34d41 100644 --- a/util/timer.hpp +++ b/util/timer.hpp @@ -25,8 +25,9 @@ public: virtual void timerTask() = 0; private: virtual void run(); -private: - int m_count; + void sleep(int units); +protected: + int m_taskCount; int m_delay; int m_startDelay; Unit m_unit; -- 2.39.5