From 353c5d8e565e3ec20dc403eb000d824e84bf52a1 Mon Sep 17 00:00:00 2001 From: Chris Tallon Date: Thu, 1 Dec 2005 19:46:43 +0000 Subject: [PATCH] New timers system. New program structure for handling buttons/timers --- Makefile | 2 +- command.cc | 53 ++++++++- command.h | 5 +- message.h | 2 +- thread.cc | 17 +++ thread.h | 3 + timerreceiver.h | 30 +++++ timers.cc | 284 ++++++++++++++++++++++++++++++++++++++++++++++ timers.h | 74 ++++++++++++ vconnect.cc | 3 +- viewman.cc | 234 +------------------------------------- viewman.h | 25 +--- vlivebanner.cc | 18 ++- vlivebanner.h | 5 +- vmute.cc | 13 +++ vmute.h | 6 +- vrecordingmenu.cc | 22 ++-- vvideolive.cc | 2 - vvideolive.h | 2 + vvolume.cc | 13 +++ vvolume.h | 6 +- 21 files changed, 540 insertions(+), 279 deletions(-) create mode 100755 timerreceiver.h create mode 100755 timers.cc create mode 100755 timers.h diff --git a/Makefile b/Makefile index 0b7c21c..5757f5a 100644 --- a/Makefile +++ b/Makefile @@ -17,7 +17,7 @@ OBJECTS = main.o command.o log.o remote.o led.o mtd.o video.o audio.o tcp.o dire view.o vinfo.o vwallpaper.o vvolume.o vrecordinglist.o vlivebanner.o vmute.o \ vrecordingmenu.o vquestion.o vchannellist.o vwelcome.o vvideolive.o vvideorec.o vradiolive.o \ vchannelselect.o vserverselect.o colour.o vconnect.o voptions.o vepg.o region.o \ - widget.o wselectlist.o wjpeg.o wsymbol.o wbutton.o woptionbox.o wtextbox.o i18n.o \ + widget.o wselectlist.o wjpeg.o wsymbol.o wbutton.o woptionbox.o wtextbox.o i18n.o timers.o \ fonts/helvB24.o fonts/helvB18.o .PHONY: clean fresh all install strip diff --git a/command.cc b/command.cc index c43e912..ef48348 100644 --- a/command.cc +++ b/command.cc @@ -56,6 +56,8 @@ int Command::init() return 0; } + pthread_mutex_init(&masterLock, NULL); + return 1; } @@ -114,6 +116,11 @@ void Command::run() wallpaper->show(); viewman->add(wallpaper); + // End of startup. Lock the mutex and put the first view up + + pthread_mutex_lock(&masterLock); + + VConnect* vconnect = new VConnect(); viewman->add(vconnect); vconnect->run(); @@ -122,18 +129,34 @@ void Command::run() UCHAR button = 0; while(irun) { + // unlock and wait + pthread_mutex_unlock(&masterLock); + button = remote->getButtonPress(2); // FIXME why is this set to 2 and not 0? so it can quit + // something happened, lock and process + + pthread_mutex_lock(&masterLock); + if ((button == Remote::NA_NONE) || (button == Remote::NA_UNKNOWN)) continue; if (button != Remote::NA_SIGNAL) handleCommand(button); processMessageQueue(); } + + pthread_mutex_unlock(&masterLock); } void Command::postMessage(Message* m) { + // This is locked here in case the main loop is not waiting for an event, but is processing one + // it could be killed but then not react to it because the signal wouldn't cause + // remote->getButtonPress to break + // locking the mutex ensures that the master thread is waiting on getButtonPress + + pthread_mutex_lock(&masterLock); MessageQueue::postMessage(m); kill(mainPid, SIGURG); + pthread_mutex_unlock(&masterLock); } void Command::processMessage(Message* m) @@ -155,10 +178,10 @@ void Command::processMessage(Message* m) case Message::STREAM_END: { // post a message to ViewMan and then run the viewman message queue - Message* m = new Message(); - m->message = Message::STREAM_END; - m->to = VVideoLive::getInstance(); - viewman->postMessage(m); + Message* m2 = new Message(); + m2->message = Message::STREAM_END; + m2->to = VVideoLive::getInstance(); + viewman->postMessage(m2); handleCommand(Remote::NA_NONE); break; } @@ -167,6 +190,26 @@ void Command::processMessage(Message* m) doJustConnected((VConnect*)m->from); break; } + case Message::TIMER: + { + // FIXME lock main mutex + // FIXME Reply - if messages are being processed then main loop is on processMessageQueue() + // -- this means the mutex is locked + + // FIXME investigate whether timer can have fired, but waits on this mutex, + // a view is deleted, then the timer runs on a non-object + + // FIXME - go to one message queue only - then instead of having + // objects deriving from messagequeues, make them derive from + // messagereceiver - then one messagequeue can deliver any message to anywhere + + + // deliver timer + ((TimerReceiver*)m->to)->timercall(m->parameter); + handleCommand(Remote::NA_NONE); // in case any timer has posted messages to viewman, + // run viewman message queue here. FIXME improve this! + // FIXME unlock main mutex + } } } @@ -188,7 +231,6 @@ void Command::handleCommand(int button) VVolume* v = new VVolume(); v->handleCommand(button); // this will draw+show viewman->add(v); - viewman->timedDelete(v, 2, 1); return; } case Remote::MUTE: @@ -197,7 +239,6 @@ void Command::handleCommand(int button) v->draw(); v->show(); viewman->add(v); - viewman->timedDelete(v, 2, 1); return; } case Remote::POWER: diff --git a/command.h b/command.h index 2ce4014..91526f0 100644 --- a/command.h +++ b/command.h @@ -26,7 +26,7 @@ #include #include - +#include #include #include "defines.h" @@ -50,6 +50,8 @@ #include "colour.h" #include "osd.h" #include "i18n.h" +#include "timerreceiver.h" +#include "timers.h" class VConnect; @@ -74,6 +76,7 @@ class Command : public MessageQueue static Command* instance; pid_t mainPid; + pthread_mutex_t masterLock; UCHAR initted; UCHAR irun; UCHAR isStandby; diff --git a/message.h b/message.h index 844b1f1..873b4bc 100644 --- a/message.h +++ b/message.h @@ -41,7 +41,6 @@ class Message const static ULONG CLOSE_ME = 2; const static ULONG PLAY_SELECTED_RECORDING = 3; const static ULONG DELETE_SELECTED_RECORDING = 4; - const static ULONG SWAP_ME_FOR = 5; const static ULONG CHANNEL_CHANGE = 6; const static ULONG RESUME_SELECTED_RECORDING = 7; const static ULONG STANDBY = 8; @@ -55,6 +54,7 @@ class Message const static ULONG STREAM_END = 16; const static ULONG CHILD_CLOSE = 17; const static ULONG REDRAW_LANG = 18; + const static ULONG TIMER = 19; }; #endif diff --git a/thread.cc b/thread.cc index 9384858..d8bb647 100644 --- a/thread.cc +++ b/thread.cc @@ -74,6 +74,16 @@ char Thread::threadIsActive() return threadActive; } +void Thread::threadLock() +{ + pthread_mutex_lock(&threadCondMutex); +} + +void Thread::threadUnlock() +{ + pthread_mutex_unlock(&threadCondMutex); +} + void Thread::threadSignal() { pthread_mutex_lock(&threadCondMutex); @@ -93,6 +103,13 @@ void Thread::threadWaitForSignal() pthread_mutex_unlock(&threadCondMutex); } +void Thread::threadWaitForSignalTimed(struct timespec* ts) +{ + pthread_mutex_lock(&threadCondMutex); + pthread_cond_timedwait(&threadCond, &threadCondMutex, ts); + pthread_mutex_unlock(&threadCondMutex); +} + void Thread::threadSetKillable() { pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); diff --git a/thread.h b/thread.h index eddaf71..965228e 100644 --- a/thread.h +++ b/thread.h @@ -45,6 +45,9 @@ class Thread void threadSetKillable(); // allows threadCancel() to work void threadCheckExit(); // terminates thread if threadStop() has been called void threadWaitForSignal(); // pauses thread until threadSignal() is called + void threadWaitForSignalTimed(struct timespec*); // pauses thread until threadSignal() is called or timer expires + void threadLock(); // locks the mutex used for internal cond/signal stuff + void threadUnlock(); // unlocks. // Internal bits and pieces diff --git a/timerreceiver.h b/timerreceiver.h new file mode 100755 index 0000000..db11b61 --- /dev/null +++ b/timerreceiver.h @@ -0,0 +1,30 @@ +/* + Copyright 2005 Chris Tallon + + This file is part of VOMP. + + VOMP 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 2 of the License, or + (at your option) any later version. + + VOMP 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 VOMP; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef TIMERRECEIVER_H +#define TIMERRECEIVER_H + +class TimerReceiver +{ + public: + virtual void timercall(int clientReference)=0; +}; + +#endif diff --git a/timers.cc b/timers.cc new file mode 100755 index 0000000..eea0f89 --- /dev/null +++ b/timers.cc @@ -0,0 +1,284 @@ +/* + Copyright 2004-2005 Chris Tallon + + This file is part of VOMP. + + VOMP 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 2 of the License, or + (at your option) any later version. + + VOMP 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 VOMP; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "timers.h" + +Timers* Timers::instance = NULL; + +Timers::Timers() +{ + if (instance) return; + instance = this; + initted = false; +} + +Timers::~Timers() +{ + instance = NULL; +} + +Timers* Timers::getInstance() +{ + return instance; +} + +int Timers::init() +{ + if (initted) return 0; + initted = true; + logger = Log::getInstance(); + + logger->log("Timers", Log::DEBUG, "Timers init start"); + + threadLock(); + if (!threadStart()) + { + shutdown(); + return 0; + } + threadUnlock(); + + logger->log("Timers", Log::DEBUG, "Timers init end"); + + return 1; +} + +int Timers::shutdown() +{ + if (!initted) return 0; + initted = false; + + logger->log("Timers", Log::DEBUG, "Timers shutdown start"); + + threadStop(); + + TimerList::iterator i; + UINT numTimers = timerList.size(); + while(numTimers) + { + i = timerList.begin(); + delete *i; + timerList.pop_front(); + --numTimers; + } + + logger->log("Timers", Log::DEBUG, "Timers shutdown end"); + + return 1; +} + +int Timers::setTimer(TimerReceiver* client, int clientReference, time_t requestedTime) +{ + if (!initted) return 0; + + Timer* t = new Timer(); + t->client = client; + t->clientReference = clientReference; + t->requestedTime.tv_sec = requestedTime; + t->requestedTime.tv_nsec = 0; + + threadLock(); + timerList.push_back(t); + threadUnlock(); + threadSignal(); + + logger->log("Timers", Log::DEBUG, "Have set timer for %p ref %i", client, clientReference); + + return 1; +} + +int Timers::setTimer(TimerReceiver* client, int clientReference, struct timespec duration) +{ + if (!initted) return 0; + + Timer* t = new Timer(); + t->client = client; + t->clientReference = clientReference; + + struct timespec currentTime; + clock_gettime(CLOCK_REALTIME, ¤tTime); + + t->requestedTime.tv_sec = currentTime.tv_sec + duration.tv_sec; + t->requestedTime.tv_nsec = currentTime.tv_nsec + duration.tv_nsec; + if (t->requestedTime.tv_nsec > 999999999) + { + ++t->requestedTime.tv_sec; + t->requestedTime.tv_nsec -= 1000000000; + logger->log("Timers", Log::DEBUG, "Second rollover - CHECK FIXME"); + } + + threadLock(); + timerList.push_back(t); + threadUnlock(); + threadSignal(); + + logger->log("Timers", Log::DEBUG, "Have set timer for %p ref %i", client, clientReference); + + return 1; +} + +int Timers::cancelTimer(TimerReceiver* client, int clientReference) +{ + if (!initted) return 0; + + threadLock(); + TimerList::iterator i; + Timer* currentTimer = NULL; + for(i = timerList.begin(); i != timerList.end(); i++) + { + currentTimer = *i; + if ((currentTimer->client == client) && (currentTimer->clientReference == clientReference)) + { + timerList.erase(i); + break; + // At this point currentTimer is not in the list but might still be nextTimer in the thread + } + } + if (i == timerList.end()) + { + // no timer found + logger->log("Timers", Log::DEBUG, "No timer found in cancelTimer %p ref %i", client, clientReference); + threadUnlock(); + return 0; + } + + // FIXME how to delete a cancelled timer? + // Just delete it, thread now checks to see if timer is still valid when it wakes up + + threadUnlock(); + threadSignal(); + + logger->log("Timers", Log::DEBUG, "Removed timer for %p ref %i", client, clientReference); + + return 1; +} + +void Timers::threadMethod() +{ + struct timespec nextTime; + Timer* nextTimer = NULL; + resetThreadFlag = true; + + // locked here + + while(1) + { + if (resetThreadFlag) + { + resetThreadFlag = false; + + // Work out the next Timer + + nextTime.tv_sec = 0; + nextTime.tv_nsec = 0; + nextTimer = NULL; + + TimerList::iterator i; + Timer* currentTimer = NULL; + for(i = timerList.begin(); i != timerList.end(); i++) + { + currentTimer = *i; + if (!nextTimer) + { + nextTime.tv_sec = currentTimer->requestedTime.tv_sec; + nextTime.tv_nsec = currentTimer->requestedTime.tv_nsec; + nextTimer = currentTimer; + } + else + { + if (currentTimer->requestedTime.tv_sec < nextTime.tv_sec) + { + nextTime.tv_sec = currentTimer->requestedTime.tv_sec; + nextTime.tv_nsec = currentTimer->requestedTime.tv_nsec; + nextTimer = currentTimer; + } + else if (currentTimer->requestedTime.tv_sec == nextTime.tv_sec) + { + if (currentTimer->requestedTime.tv_nsec < nextTime.tv_nsec) + { + nextTime.tv_sec = currentTimer->requestedTime.tv_sec; + nextTime.tv_nsec = currentTimer->requestedTime.tv_nsec; + nextTimer = currentTimer; + } + } + } + } + + if (nextTimer) + { + threadWaitForSignalTimed(&nextTime); // FIXME does this work if the time is in the past? + logger->log("Timers", Log::DEBUG, "FIXME CHECK does waitforsignaltimed work for time < now?"); + + // unlocks in the wait + } + else + { + threadWaitForSignal(); + // unlocks in the wait + } + + // ok. we have been signalled or the time has run out + // This only gets signalled if it is to reset or die + + // First check for die.. + threadCheckExit(); // exiting thread with mutex locked + + // Check for reset.. + if (resetThreadFlag) continue; + + // timer ran out + // we have the lock, but we didn't in the wait. in case a timer was deleted during the wait, + // check to see if object nextTimer is still in the list + // FIXME - actually imlement the above + + // Ok. Get the main lock. + // If we get the main lock, the view can't be deleted before the timer gets there. + // (But will need to call Command->postMessageNoLock) to keep the lock + // How to run message queue then? + // Ah, no need to worry, if it is locked then main thread is waiting on getButtonPress and will + // run the queue afterwards anyway + // If we don't get the lock, lets say the view is deleted while we wait. + // As part of its delete process, it will cancel its timer AND CAUSE DEADLOCK. DAMN. + + + Log::getInstance()->log("Timers", Log::DEBUG, "Timer firing for client %p ref %i", nextTimer->client, nextTimer->clientReference); + + // send this timer to the timer receiver somehow + // possibly give to command message queue + + Message* m = new Message(); + m->from = this; + m->to = nextTimer->client; + m->message = Message::TIMER; + m->parameter = nextTimer->clientReference; + Command::getInstance()->postMessage(m); + + timerList.remove(nextTimer); + delete nextTimer; + nextTimer = NULL; + + resetThreadFlag = true; + } + } +} + +void Timers::threadPostStopCleanup() +{ +} diff --git a/timers.h b/timers.h new file mode 100755 index 0000000..4881e3a --- /dev/null +++ b/timers.h @@ -0,0 +1,74 @@ +/* + Copyright 2004-2005 Chris Tallon + + This file is part of VOMP. + + VOMP 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 2 of the License, or + (at your option) any later version. + + VOMP 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 VOMP; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef TIMERS_H +#define TIMERS_H + +#include +#include +#include + +#include "defines.h" +#include "log.h" +#include "thread.h" +#include "command.h" +#include "timerreceiver.h" + +class Timer +{ + public: + TimerReceiver* client; + int clientReference; + struct timespec requestedTime; +}; + +using namespace std; +//using namespace __gnu_cxx; +typedef list TimerList; + +class Timers : public Thread +{ + public: + Timers(); + virtual ~Timers(); + static Timers* getInstance(); + + int init(); + int shutdown(); + + // FIXME - ensure all objects that call settimer call cancel timer if they are being deleted + + int setTimer(TimerReceiver* client, int clientReference, time_t requestedTime); + int setTimer(TimerReceiver* client, int clientReference, timespec duration); + int cancelTimer(TimerReceiver* client, int clientReference); + + // Thread stuff + virtual void threadMethod(); + virtual void threadPostStopCleanup(); + + private: + static Timers* instance; + Log* logger; + bool initted; + TimerList timerList; + bool resetThreadFlag; +}; + +#endif diff --git a/vconnect.cc b/vconnect.cc index d4480bd..b487110 100644 --- a/vconnect.cc +++ b/vconnect.cc @@ -95,7 +95,8 @@ void VConnect::threadMethod() vs->setParent(this); vs->draw(); vs->show(); - viewman->add(vs); + viewman->add(vs); // FIXME - do this better - perhaps post message to Command + // Otherwise it will be using ViewMan without the Command mutex locked threadWaitForSignal(); } diff --git a/viewman.cc b/viewman.cc index c10a8fd..c3ccbc8 100644 --- a/viewman.cc +++ b/viewman.cc @@ -28,9 +28,6 @@ ViewMan::ViewMan() instance = this; initted = 0; numViews = 0; - resetThreadFlag = 0; - autoDeleteThreadRun = 0; - callFromThread = 0; } ViewMan::~ViewMan() @@ -46,9 +43,6 @@ ViewMan* ViewMan::getInstance() int ViewMan::init() { if (initted) return 0; - pthread_mutex_init(&viewManLock, NULL); - pthread_cond_init(&autoDeleteThreadSignal, NULL); - if (!startAutoDeleteThread()) return 0; initted = 1; return 1; } @@ -60,12 +54,6 @@ int ViewMan::shutdown() // FIXME don't think this can work properly, removeAll leaves the wallpaper there! removeAll(); - // get the lock here to ensure that the thread is waiting on the cond - pthread_mutex_lock(&viewManLock); - autoDeleteThreadRun = 0; - pthread_cond_signal(&autoDeleteThreadSignal); - pthread_mutex_unlock(&viewManLock); - pthread_join(autoDeleteThread, NULL); initted = 0; return 1; } @@ -73,40 +61,20 @@ int ViewMan::shutdown() int ViewMan::add(View* v) { if (!initted) return 0; - if (numViews == 20) return 0; - - pthread_mutex_lock(&viewManLock); + if (numViews == 16) return 0; views[numViews++] = v; - resetThread(); - pthread_mutex_unlock(&viewManLock); - - return 1; -} - -int ViewMan::addNoLock(View* v) -{ - if (!initted) return 0; - if (numViews == 20) return 0; - - views[numViews++] = v; - - resetThread(); - return 1; } - // ---------------------------------------------------- REMOVE CODE -int ViewMan::removeView(View* toDelete, int noLock) +int ViewMan::removeView(View* toDelete) { if (!initted) return 0; if (numViews == 0) return 0; - if (!noLock) pthread_mutex_lock(&viewManLock); - Log::getInstance()->log("ViewMan", Log::DEBUG, "entering remove, numViews=%i", numViews); int i; @@ -128,7 +96,6 @@ int ViewMan::removeView(View* toDelete, int noLock) if (i == -1) { // not a View we have! - if (!noLock) pthread_mutex_unlock(&viewManLock); return 0; } } @@ -144,9 +111,6 @@ int ViewMan::removeView(View* toDelete, int noLock) // Delete the view delete toDelete; - resetThread(); - if (!noLock) pthread_mutex_unlock(&viewManLock); - return 1; } @@ -359,22 +323,15 @@ void ViewMan::drawBlack(Region& r) void ViewMan::removeAll() { - pthread_mutex_lock(&viewManLock); - // 1.. Don't delete wallpaper. No point. for (; numViews > 1; --numViews) { delete views[numViews-1]; } - - resetThread(); - pthread_mutex_unlock(&viewManLock); } int ViewMan::handleCommand(UCHAR command) { - pthread_mutex_lock(&viewManLock); - int retVal; int retVal2 = 0; int i; @@ -394,33 +351,19 @@ int ViewMan::handleCommand(UCHAR command) if (retVal == 1) { // not handled but don't give to any more views - pthread_mutex_unlock(&viewManLock); return 0; } if (retVal == 2) { // command handled - if (views[i]->seconds) - { - struct timespec currentTime; - clock_gettime(CLOCK_REALTIME, ¤tTime); - views[i]->delSec = currentTime.tv_sec + views[i]->seconds; - views[i]->delNSec = currentTime.tv_nsec; - resetThread(); - } - pthread_mutex_unlock(&viewManLock); retVal2 = 1; break; } else if (retVal == 4) { - // removeNoLock(views[i]); - // Box::showAll(); - // resetThread(); Log::getInstance()->log("ViewMan", Log::DEBUG, "Return 4: i=%i, views[i]=%p", i, views[i]); removeView(views[i], 1); - pthread_mutex_unlock(&viewManLock); retVal2 = 1; break; } @@ -436,7 +379,6 @@ int ViewMan::handleCommand(UCHAR command) processMessageQueue(); - pthread_mutex_unlock(&viewManLock); return retVal2; } @@ -465,182 +407,12 @@ void ViewMan::processMessage(Message* m) removeView((View*)m->from, 1); break; } - case Message::SWAP_ME_FOR: - { - View* toReplace = (View*) m->parameter; - - removeView((View*)m->from, 1); - - views[numViews] = toReplace; - ++numViews; - if (toReplace->seconds) - { - struct timespec currentTime; - clock_gettime(CLOCK_REALTIME, ¤tTime); - toReplace->delSec = currentTime.tv_sec + toReplace->seconds; - toReplace->delNSec = currentTime.tv_nsec; - } - toReplace->draw(); - toReplace->show(); - resetThread(); - break; - } case Message::ADD_VIEW: { View* toAdd = (View*)m->parameter; - addNoLock(toAdd); + add(toAdd); toAdd->draw(); toAdd->show(); } } } - -int ViewMan::timedDelete(View* v, int seconds, int lockMutex) -{ - int success; - - if (lockMutex) pthread_mutex_lock(&viewManLock); - - struct timespec currentTime; - clock_gettime(CLOCK_REALTIME, ¤tTime); - - if (v) - { - if (seconds) - { - v->seconds = seconds; - v->delSec = currentTime.tv_sec + seconds; - v->delNSec = currentTime.tv_nsec; - } - else - { - // for cancelling the delete - v->seconds = 0; - v->delSec = 0; - v->delNSec = 0; - } - success = 1; - } - else - { - success = 0; - } - - resetThread(); - if (lockMutex) pthread_mutex_unlock(&viewManLock); - - return success; -} - - -// THE THREAD CODE STARTS HERE ///////////////////////////////////////////////////////////// - -void ViewMan::resetThread() -{ - // must be called with mutex already locked - resetThreadFlag = 1; - pthread_cond_signal(&autoDeleteThreadSignal); -} - -// undeclared function -void startAutoDeleteThread2(void *arg) -{ - ViewMan *v = (ViewMan *)arg; - v->startAutoDeleteThread3(); -} -int ViewMan::startAutoDeleteThread() -{ - pthread_mutex_lock(&viewManLock); - resetThreadFlag = 1; - autoDeleteThreadRun = 1; - if (pthread_create(&autoDeleteThread, NULL, (void*(*)(void*))startAutoDeleteThread2, (void *)this) == -1) return 0; - return 1; -} - -void ViewMan::startAutoDeleteThread3() -{ - struct timespec nextTime; - View* nextToDelete = NULL; - - // I don't want signals - sigset_t sigs; - sigfillset(&sigs); - pthread_sigmask(SIG_BLOCK, &sigs, NULL); - - // locked here - - while(1) - { - if (resetThreadFlag) - { - resetThreadFlag = 0; - - // Work out the next View to be deleted - - nextTime.tv_sec = 0; - nextTime.tv_nsec = 0; - nextToDelete = NULL; - - for(int i = 0; i < numViews; i++) - { - if ((views[i]->delSec > 0) && (views[i]->delNSec > 0)) - { - if ((nextTime.tv_sec == 0) && (nextTime.tv_nsec == 0)) - { - nextTime.tv_sec = views[i]->delSec; - nextTime.tv_nsec = views[i]->delNSec; - nextToDelete = views[i]; - } - else - { - if (views[i]->delSec < nextTime.tv_sec) - { - nextTime.tv_sec = views[i]->delSec; - nextTime.tv_nsec = views[i]->delNSec; - nextToDelete = views[i]; - } - else if (views[i]->delSec == nextTime.tv_sec) - { - if (views[i]->delNSec < nextTime.tv_nsec) - { - nextTime.tv_sec = views[i]->delNSec; - nextTime.tv_nsec = views[i]->delNSec; - nextToDelete = views[i]; - } - } - } - } - // no case - } - // end - } - - if (nextTime.tv_sec == 0) - { - pthread_cond_wait(&autoDeleteThreadSignal, &viewManLock); - } - else - { - pthread_cond_timedwait(&autoDeleteThreadSignal, &viewManLock, &nextTime); - } - - // ok. we have been signalled or the time has run out - - // see if we have been signalled. we only get signalled if we - // are to reset the timer or if we are to die completely - if (!autoDeleteThreadRun) - { - pthread_exit(NULL); - // exiting thread with mutex locked - } - - if (resetThreadFlag) continue; - - // timer ran out - Log::getInstance()->log("ViewMan", Log::DEBUG, "AutoDel: About to remove %p", nextToDelete); - removeView(nextToDelete, 1); // enter this method with mutex locked - - resetThreadFlag = 1; - } -} - diff --git a/viewman.h b/viewman.h index 8399445..859dbce 100644 --- a/viewman.h +++ b/viewman.h @@ -24,8 +24,7 @@ #include #include #include -#include -#include +#include #include "defines.h" #include "view.h" @@ -35,6 +34,9 @@ #include "surface.h" #include "region.h" +//using namespace std; +using namespace __gnu_cxx; + typedef slist RegionList; class ViewMan : public MessageQueue @@ -47,17 +49,11 @@ class ViewMan : public MessageQueue int init(); int shutdown(); - // All these reset the thread int add(View* v); - int addNoLock(View* v); - int removeView(View* toRemove = NULL, int noLock = 0); + int removeView(View* toRemove = NULL); void removeAll(); int handleCommand(UCHAR command); - int timedDelete(View* v, int seconds, int lock); - - // not for external use - void startAutoDeleteThread3(); private: static ViewMan* instance; @@ -66,17 +62,6 @@ class ViewMan : public MessageQueue View* views[20]; int numViews; - // Threading stuff - - int startAutoDeleteThread(); - pthread_mutex_t viewManLock; - pthread_t autoDeleteThread; - pthread_cond_t autoDeleteThreadSignal; - int resetThreadFlag; - int autoDeleteThreadRun; - int callFromThread; - void resetThread(); - void processMessage(Message* m); // New windowing stuff diff --git a/vlivebanner.cc b/vlivebanner.cc index 3d3639e..2b85d46 100644 --- a/vlivebanner.cc +++ b/vlivebanner.cc @@ -47,6 +47,9 @@ VLiveBanner::VLiveBanner(View* tparent, Channel* channel, bool bannerTakesComman sl.setNoLoop(); setChannel(channel); + + // set a timer for deleting view + Timers::getInstance()->setTimer(this, 1, (struct timespec){4, 0}); } VLiveBanner::~VLiveBanner() @@ -108,7 +111,8 @@ void VLiveBanner::setChannel(Channel* tChannel) } // Reset the timer as it probably took 1-2 seconds to change the channel - ViewMan::getInstance()->timedDelete(this, 4, 0); + Timers::getInstance()->cancelTimer(this, 1); // if it exists + Timers::getInstance()->setTimer(this, 1, (struct timespec){4, 0}); } } @@ -190,7 +194,7 @@ int VLiveBanner::handleCommand(int command) { Log::getInstance()->log("VLiveBanner", Log::DEBUG, "Found the option you pointed at. %s", event->title); // First, cancel my delete timer - ViewMan::getInstance()->timedDelete(this, 0, 0); + Timers::getInstance()->cancelTimer(this, 1); // if it exists VInfo* vi = new VInfo(); vi->setTitleText(event->title); @@ -222,3 +226,13 @@ int VLiveBanner::handleCommand(int command) return 1; } + +void VLiveBanner::timercall(int clientReference) +{ + // delete me! + Message* m = new Message(); + m->message = Message::CLOSE_ME; + m->to = ViewMan::getInstance(); + m->from = this; + ViewMan::getInstance()->postMessage(m); +} diff --git a/vlivebanner.h b/vlivebanner.h index d719f26..fe36207 100644 --- a/vlivebanner.h +++ b/vlivebanner.h @@ -36,8 +36,10 @@ #include "vinfo.h" #include "viewman.h" #include "i18n.h" +#include "timerreceiver.h" +#include "timers.h" -class VLiveBanner : public View +class VLiveBanner : public View, public TimerReceiver { public: VLiveBanner(View* parent, Channel* channel, bool bannerTakesCommands); @@ -48,6 +50,7 @@ class VLiveBanner : public View int handleCommand(int command); void draw(); + void timercall(int clientReference); private: View* parent; diff --git a/vmute.cc b/vmute.cc index f7eb1a3..c7fee0c 100644 --- a/vmute.cc +++ b/vmute.cc @@ -47,6 +47,19 @@ void VMute::draw() else w.nextSymbol = WSymbol::UNMUTE; w.setSurfaceOffset(5, 5); w.draw(); + + Timers::getInstance()->cancelTimer(this, 1); // if it exists + Timers::getInstance()->setTimer(this, 1, (struct timespec){2, 0}); +} + +void VMute::timercall(int clientReference) +{ + // delete me! + Message* m = new Message(); + m->message = Message::CLOSE_ME; + m->to = ViewMan::getInstance(); + m->from = this; + ViewMan::getInstance()->postMessage(m); } int VMute::handleCommand(int command) diff --git a/vmute.h b/vmute.h index fb393b4..263729d 100644 --- a/vmute.h +++ b/vmute.h @@ -29,13 +29,17 @@ #include "wsymbol.h" #include "colour.h" #include "video.h" +#include "timerreceiver.h" +#include "timers.h" +#include "viewman.h" -class VMute : public View +class VMute : public View, public TimerReceiver { public: VMute(); void draw(); int handleCommand(int command); + void timercall(int clientReference); private: int isMuted; diff --git a/vrecordingmenu.cc b/vrecordingmenu.cc index 6f64602..d7f95d0 100644 --- a/vrecordingmenu.cc +++ b/vrecordingmenu.cc @@ -182,17 +182,17 @@ void VRecordingMenu::processMessage(Message* m) { if (sl.getCurrentOption() == 3) { - Message* m = new Message(); - m->from = this; - m->to = ViewMan::getInstance(); - m->message = Message::CLOSE_ME; - ViewMan::getInstance()->postMessage(m); - - m = new Message(); - m->from = this; - m->to = vRecList; - m->message = Message::DELETE_SELECTED_RECORDING; - ViewMan::getInstance()->postMessage(m); + Message* m2 = new Message(); + m2->from = this; + m2->to = ViewMan::getInstance(); + m2->message = Message::CLOSE_ME; + ViewMan::getInstance()->postMessage(m2); + + m2 = new Message(); + m2->from = this; + m2->to = vRecList; + m2->message = Message::DELETE_SELECTED_RECORDING; + ViewMan::getInstance()->postMessage(m2); } } } diff --git a/vvideolive.cc b/vvideolive.cc index 95694dc..3beb850 100644 --- a/vvideolive.cc +++ b/vvideolive.cc @@ -117,7 +117,6 @@ int VVideoLive::handleCommand(int command) { VChannelSelect* v = new VChannelSelect(this, command); viewman->addNoLock(v); -// ViewMan::getInstance()->timedDelete(v, 4, 0); v->draw(); v->show(); } @@ -204,7 +203,6 @@ void VVideoLive::doBanner(bool bannerTakesCommands) if(epgmode) return; vlb = new VLiveBanner(this, (*chanList)[currentChannel], bannerTakesCommands); - viewman->timedDelete(vlb, 4, 0); Message* m = new Message(); m->from = this; diff --git a/vvideolive.h b/vvideolive.h index 60e7e73..ae6e51e 100644 --- a/vvideolive.h +++ b/vvideolive.h @@ -42,6 +42,8 @@ class VEpg; +class VLiveBanner; + class VVideoLive : public View { public: diff --git a/vvolume.cc b/vvolume.cc index 4f8af9f..b9de8cb 100644 --- a/vvolume.cc +++ b/vvolume.cc @@ -62,6 +62,19 @@ void VVolume::draw() w.setSurfaceOffset(40 + (i * 9), 13); w.draw(); } + + Timers::getInstance()->cancelTimer(this, 1); // if it exists + Timers::getInstance()->setTimer(this, 1, (struct timespec){2, 0}); +} + +void VVolume::timercall(int clientReference) +{ + // delete me! + Message* m = new Message(); + m->message = Message::CLOSE_ME; + m->to = ViewMan::getInstance(); + m->from = this; + ViewMan::getInstance()->postMessage(m); } int VVolume::handleCommand(int command) diff --git a/vvolume.h b/vvolume.h index 893b0d0..a7915b9 100644 --- a/vvolume.h +++ b/vvolume.h @@ -29,13 +29,17 @@ #include "wsymbol.h" #include "colour.h" #include "video.h" +#include "timerreceiver.h" +#include "timers.h" +#include "viewman.h" -class VVolume : public View +class VVolume : public View, public TimerReceiver { public: VVolume(); void draw(); int handleCommand(int command); + void timercall(int clientReference); private: int displayCommand; -- 2.39.2