From 09e7586237524b585382555ea1219c4854f29692 Mon Sep 17 00:00:00 2001 From: Chris Tallon Date: Sun, 25 Mar 2007 15:48:56 +0000 Subject: [PATCH] Allow a timercall to try to cancel its own timer - silent ignore --- defines.h | 3 +++ thread.h | 3 +++ threadp.cc | 12 ++++++++++++ threadp.h | 5 ++++- timers.cc | 21 ++++++++++++++++++--- 5 files changed, 40 insertions(+), 4 deletions(-) diff --git a/defines.h b/defines.h index a1a7d7d..b3bde10 100644 --- a/defines.h +++ b/defines.h @@ -38,6 +38,7 @@ void MILLISLEEP(ULONG a); #define Surface_TYPE SurfaceWin #define Thread_TYPE ThreadWin + #define ThreadID_TYPE FIXME Marten #define SNPRINTF _snprintf #define VSNPRINTF _vsnprintf @@ -51,6 +52,8 @@ void MILLISLEEP(ULONG a); #define Surface_TYPE SurfaceMVP #define Thread_TYPE ThreadP + #include + #define ThreadID_TYPE pthread_t #define SNPRINTF snprintf #define VSNPRINTF vsnprintf diff --git a/thread.h b/thread.h index 16178e0..f6dcfcf 100644 --- a/thread.h +++ b/thread.h @@ -21,6 +21,8 @@ #ifndef THREAD_H #define THREAD_H +#include "defines.h" + class Thread { protected: @@ -35,6 +37,7 @@ class Thread virtual void threadSignal()=0; // releases a thread that has called threadWaitForSignal virtual void threadSignalNoLock()=0; // same as above but without locking guarantees. probably not a good idea. char threadIsActive(); // returns 1 if thread has been started but not stop() or cancel() 'd + virtual ThreadID_TYPE getThreadID()=0; // returns the ID of this thread // Methods to use from inside the thread virtual void threadSetKillable()=0; // allows threadCancel() to work diff --git a/threadp.cc b/threadp.cc index f97fb8f..d95156f 100644 --- a/threadp.cc +++ b/threadp.cc @@ -102,6 +102,13 @@ void ThreadP::threadSetKillable() pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL); } +pthread_t ThreadP::getThreadID() // returns the ID of this thread +{ + return pthread; +} + +// Static functions + void ThreadP::threadSuicide() { if(!pthread_detach(pthread_self())) @@ -116,3 +123,8 @@ void ThreadP::threadSuicide() pthread_exit(NULL); } + +pthread_t ThreadP::thisThreadID() // returns the ID of the calling thread +{ + return pthread_self(); +} diff --git a/threadp.h b/threadp.h index 419a93e..46deb25 100644 --- a/threadp.h +++ b/threadp.h @@ -51,12 +51,15 @@ class ThreadP : public Thread // Internal bits and pieces - private: pthread_t pthread; pthread_cond_t threadCond; pthread_mutex_t threadCondMutex; public: + pthread_t getThreadID(); // returns the ID of the thread represented by this object + + + static pthread_t thisThreadID(); // Self identification - returns ID of calling thread static void threadSuicide(); // Self termination }; diff --git a/timers.cc b/timers.cc index 9c491cc..0c1b460 100755 --- a/timers.cc +++ b/timers.cc @@ -187,8 +187,13 @@ bool Timers::cancelTimer(TimerReceiver* client, int clientReference) Delete the timer normally, set resetFlag 2. The TimerEvent is found, running = true. This means the timer is currently firing, timercall on the client is being called. - In this case, this thread calling cancelTimer needs to unlock and wait for the - timercall thread to get back. (sleeps or signalling) + a. Thread calling cancelTimer is an external thread: In this case, this thread + calling cancelTimer needs to unlock and wait for the timercall thread to get + back. (sleeps or signalling) + b. the timercall thread is calling cancelTimer. remove any restartAfterFinished + request, but otherwise ignore the request to cancelTimer because it has already + fired. The timercall thread will return to the calling code and eventually + terminate in threadEventFinished. 3. The TimerEvent is not found. Client error or the thread returned to the Timers module in between client calling cancelTimer and cancelTimer actually running. Do nothing, return normally. @@ -240,7 +245,17 @@ bool Timers::cancelTimer(TimerReceiver* client, int clientReference) } else { - // Case 2. For now, use polling with a 50ms delay. + if (Thread_TYPE::thisThreadID() == currentTimerEvent->getThreadID()) + { + // Case 2 b. + // The thread requesting cancelTimer is the timer thread itself, the timer has already fired. + logger->log("Timers", Log::DEBUG, "%p ref %i cancelTimer itself calling - ignore", client, clientReference); + currentTimerEvent->restartAfterFinish = false; // in case a restart had already been set. + threadUnlock(); + return true; + } + + // Case 2 a. For now, use polling with a 50ms delay. // Don't delete a running timer. // FIXME upgrade me to signalling -- 2.39.5