diff --git a/testApp/misc/testTimer.cpp b/testApp/misc/testTimer.cpp index 41cfb8e..0b12818 100644 --- a/testApp/misc/testTimer.cpp +++ b/testApp/misc/testTimer.cpp @@ -15,9 +15,11 @@ #include #include #include +#include #include #include +#include #include #include @@ -27,175 +29,214 @@ using namespace epics::pvData; using std::string; -static TimeStamp currentTimeStamp; -static double oneDelay = 4.0; -static double twoDelay = 2.0; -static double threeDelay = 1.0; -static int ntimes = 3; +static const double delays[3] = {1.0, 2.0, 4.0}; +static const unsigned ntimes = 3; -class MyCallback; -typedef std::tr1::shared_ptr MyCallbackPtr; +namespace { -class MyCallback : public TimerCallback { -public: - POINTER_DEFINITIONS(MyCallback); - MyCallback(string name,EventPtr const & wait) - : name(name), - wait(wait) - { - } - ~MyCallback() - { - } +struct Marker : public TimerCallback +{ + POINTER_DEFINITIONS(Marker); + + Event wait, hold; + virtual ~Marker() {} virtual void callback() { - timeStamp.getCurrent(); - wait->signal(); + wait.signal(); + hold.wait(); + } + virtual void timerStopped() {} +}; + +struct MyCallback : public TimerCallback { + POINTER_DEFINITIONS(MyCallback); + + MyCallback(const string& name) + :name(name) + ,counter(0) + ,first_gbl(0) + {} + virtual ~MyCallback() {} + virtual void callback() + { + testDiag("expire %s",name.c_str()); + { + epicsGuard G(gbl_mutex); + counter++; + if(first_gbl==0) { + first_gbl = ++gbl_counter; + } + } + wait.signal(); } virtual void timerStopped() { - printf("timerStopped %s\n",name.c_str()); + testDiag("timerStopped %s",name.c_str()); } - TimeStamp &getTimeStamp() { return timeStamp;} -private: - string name; - EventPtr wait; - TimeStamp timeStamp; + void clear() { + epicsGuard G(gbl_mutex); + counter = gbl_counter = 0; + } + + const string name; + unsigned counter, first_gbl; + Event wait; + + static unsigned gbl_counter; + static Mutex gbl_mutex; }; -static void testBasic() +unsigned MyCallback::gbl_counter; +Mutex MyCallback::gbl_mutex; + +typedef std::tr1::shared_ptr MyCallbackPtr; + +}// namespace + +static void testBasic(unsigned oneOrd, unsigned twoOrd, unsigned threeOrd) { - testDiag("\n\ntestBasic oneDelay %lf twoDelay %lf threeDaley %lf\n", - oneDelay,twoDelay,threeDelay); + testDiag("testBasic oneOrd %u twoOrd %u threeOrd %u", + oneOrd,twoOrd,threeOrd); - string one("one"); - string two("two"); - string three("three"); - EventPtr eventOne(new Event()); - EventPtr eventTwo(new Event()); - EventPtr eventThree(new Event()); - TimerPtr timer(new Timer(string("timer"),middlePriority)); - MyCallbackPtr callbackOne(new MyCallback(one,eventOne)); - MyCallbackPtr callbackTwo(new MyCallback(two,eventTwo)); - MyCallbackPtr callbackThree(new MyCallback(three,eventThree)); - for(int n=0; nisScheduled(callbackOne)); - testOk1(!timer->isScheduled(callbackTwo)); - testOk1(!timer->isScheduled(callbackThree)); - timer->scheduleAfterDelay(callbackOne,oneDelay); - timer->scheduleAfterDelay(callbackTwo,twoDelay); - timer->scheduleAfterDelay(callbackThree,threeDelay); - if(oneDelay>.1) testOk1(timer->isScheduled(callbackOne)); - if(twoDelay>.1) testOk1(timer->isScheduled(callbackTwo)); - if(threeDelay>.1) testOk1(timer->isScheduled(callbackThree)); + Timer timer("timer" ,middlePriority); - eventOne->wait(); - eventTwo->wait(); - eventThree->wait(); - double diff; - double delta; - diff = TimeStamp::diff( - callbackOne->getTimeStamp(),currentTimeStamp); - delta = diff - oneDelay; + Marker::shared_pointer marker(new Marker); + MyCallbackPtr callbackOne(new MyCallback("one")); + MyCallbackPtr callbackTwo(new MyCallback("two")); + MyCallbackPtr callbackThree(new MyCallback("three")); - if(delta<0.0) delta = -delta; - testOk1(delta<.1); - diff = TimeStamp::diff( - callbackTwo->getTimeStamp(),currentTimeStamp); - delta = diff - twoDelay; + for(unsigned n=0; ngetTimeStamp(),currentTimeStamp); - delta = diff - threeDelay; + testOk1(!timer.isScheduled(marker)); + timer.scheduleAfterDelay(marker, 0.01); + marker->wait.wait(); + // timer worker is blocked + + testOk1(!timer.isScheduled(callbackOne)); + testOk1(!timer.isScheduled(callbackTwo)); + testOk1(!timer.isScheduled(callbackThree)); + + callbackOne->clear(); + callbackTwo->clear(); + callbackThree->clear(); + + timer.scheduleAfterDelay(callbackOne,delays[oneOrd]); + timer.scheduleAfterDelay(callbackTwo,delays[twoOrd]); + timer.scheduleAfterDelay(callbackThree,delays[threeOrd]); + + testOk1(timer.isScheduled(callbackOne)); + testOk1(timer.isScheduled(callbackTwo)); + testOk1(timer.isScheduled(callbackThree)); + + marker->hold.signal(); // let the worker loose + + callbackOne->wait.wait(); + callbackTwo->wait.wait(); + callbackThree->wait.wait(); + + testOk1(!timer.isScheduled(callbackOne)); + testOk1(!timer.isScheduled(callbackTwo)); + testOk1(!timer.isScheduled(callbackThree)); + + { + epicsGuard G(MyCallback::gbl_mutex); + testOk(callbackOne->counter==1, "%s counter %u = 1", callbackOne->name.c_str(), callbackOne->counter); + testOk(callbackTwo->counter==1, "%s counter %u = 1", callbackTwo->name.c_str(), callbackTwo->counter); + testOk(callbackThree->counter==1, "%s counter %u = 1", callbackThree->name.c_str(), callbackThree->counter); + + testOk(callbackOne->first_gbl==oneOrd+1, "%s first_gbl %u = %u", callbackOne->name.c_str(), callbackOne->first_gbl, oneOrd+1); + testOk(callbackTwo->first_gbl==twoOrd+1, "%s first_gbl %u = %u", callbackTwo->name.c_str(), callbackTwo->first_gbl, twoOrd+1); + testOk(callbackThree->first_gbl==threeOrd+1, "%s first_gbl %u = %u", callbackThree->name.c_str(), callbackThree->first_gbl, threeOrd+1); + } - if(delta<0.0) delta = -delta; - testOk1(delta<.1); } - printf("testBasic PASSED\n"); } -static void testCancel() +static void testCancel(unsigned oneOrd, unsigned twoOrd, unsigned threeOrd, + unsigned oneReal, unsigned threeReal) { - testDiag("\n\ntestCancel oneDelay %lf twoDelay %lf threeDaley %lf\n", - oneDelay,twoDelay,threeDelay); + testDiag("testCancel oneOrd %u twoOrd %u threeOrd %u", + oneOrd,twoOrd,threeOrd); - string one("one"); - string two("two"); - string three("three"); - EventPtr eventOne(new Event()); - EventPtr eventTwo(new Event()); - EventPtr eventThree(new Event()); - TimerPtr timer(new Timer(string("timer"),middlePriority)); - MyCallbackPtr callbackOne(new MyCallback(one,eventOne)); - MyCallbackPtr callbackTwo(new MyCallback(two,eventTwo)); - MyCallbackPtr callbackThree(new MyCallback(three,eventThree)); - for(int n=0; nisScheduled(callbackOne)); - testOk1(!timer->isScheduled(callbackTwo)); - testOk1(!timer->isScheduled(callbackThree)); - timer->scheduleAfterDelay(callbackOne,oneDelay); - timer->scheduleAfterDelay(callbackTwo,twoDelay); - timer->scheduleAfterDelay(callbackThree,threeDelay); - timer->cancel(callbackTwo); - if(oneDelay>.1) testOk1(timer->isScheduled(callbackOne)); - testOk1(!timer->isScheduled(callbackTwo)); - if(threeDelay>.1) testOk1(timer->isScheduled(callbackThree)); + Timer timer("timer" ,middlePriority); - eventOne->wait(); - eventThree->wait(); - double diff; - double delta; - diff = TimeStamp::diff( - callbackOne->getTimeStamp(),currentTimeStamp); - delta = diff - oneDelay; + Marker::shared_pointer marker(new Marker); + MyCallbackPtr callbackOne(new MyCallback("one")); + MyCallbackPtr callbackTwo(new MyCallback("two")); + MyCallbackPtr callbackThree(new MyCallback("three")); - if(delta<0.0) delta = -delta; - testOk1(delta<.1); - diff = TimeStamp::diff( - callbackThree->getTimeStamp(),currentTimeStamp); - delta = diff - threeDelay; + for(unsigned n=0; nwait.wait(); + // timer worker is blocked + + testOk1(!timer.isScheduled(callbackOne)); + testOk1(!timer.isScheduled(callbackTwo)); + testOk1(!timer.isScheduled(callbackThree)); + + callbackOne->clear(); + callbackTwo->clear(); + callbackThree->clear(); + + timer.scheduleAfterDelay(callbackOne,delays[oneOrd]); + timer.scheduleAfterDelay(callbackTwo,delays[twoOrd]); + timer.scheduleAfterDelay(callbackThree,delays[threeOrd]); + + testOk1(timer.isScheduled(callbackOne)); + testOk1(timer.isScheduled(callbackTwo)); + testOk1(timer.isScheduled(callbackThree)); + + timer.cancel(callbackTwo); + + testOk1(timer.isScheduled(callbackOne)); + testOk1(!timer.isScheduled(callbackTwo)); + testOk1(timer.isScheduled(callbackThree)); + + marker->hold.signal(); // let the worker loose + + callbackOne->wait.wait(); + callbackThree->wait.wait(); + + testOk1(!timer.isScheduled(callbackOne)); + testOk1(!timer.isScheduled(callbackTwo)); + testOk1(!timer.isScheduled(callbackThree)); + + { + epicsGuard G(MyCallback::gbl_mutex); + testOk(callbackOne->counter==1, "%s counter %u = 1", callbackOne->name.c_str(), callbackOne->counter); + testOk(callbackTwo->counter==0, "%s counter %u = 0", callbackTwo->name.c_str(), callbackTwo->counter); + testOk(callbackThree->counter==1, "%s counter %u = 1", callbackThree->name.c_str(), callbackThree->counter); + + testOk(callbackOne->first_gbl==oneReal+1, "%s first_gbl %u = %u", callbackOne->name.c_str(), callbackOne->first_gbl, oneOrd+1); + testOk(callbackTwo->first_gbl==0, "%s first_gbl %u = %u", callbackTwo->name.c_str(), callbackTwo->first_gbl, 0); + testOk(callbackThree->first_gbl==threeReal+1, "%s first_gbl %u = %u", callbackThree->name.c_str(), callbackThree->first_gbl, threeOrd+1); + } - if(delta<0.0) delta = -delta; - testOk1(delta<.1); } - printf("testCancel PASSED\n"); } MAIN(testTimer) { - testPlan(171); - testDiag("Tests timer"); - oneDelay = .4; - twoDelay = .2; - threeDelay = .1; - printf("oneDelay %f twoDelay %f threeDelay %f\n", - oneDelay,twoDelay,threeDelay); - testBasic(); - testCancel(); - oneDelay = .1; - twoDelay = .2; - threeDelay = .4; - printf("oneDelay %f twoDelay %f threeDelay %f\n", - oneDelay,twoDelay,threeDelay); - testBasic(); - testCancel(); - oneDelay = .1; - twoDelay = .4; - threeDelay = .2; - printf("oneDelay %f twoDelay %f threeDelay %f\n", - oneDelay,twoDelay,threeDelay); - testBasic(); - testCancel(); - oneDelay = .0; - twoDelay = .0; - threeDelay = .0; - printf("oneDelay %f twoDelay %f threeDelay %f\n", - oneDelay,twoDelay,threeDelay); - testBasic(); - testCancel(); + testPlan(315); + try { + testDiag("Tests timer"); + + testBasic(2, 1, 0); + testCancel(2, 1, 0, 1, 0); + + testBasic(0, 1, 2); + testCancel(0, 1, 2, 0, 1); + + testBasic(0, 2, 1); + testCancel(0, 2, 1, 0, 1); + + }catch(std::exception& e) { + testFail("Unhandled exception: %s", e.what()); + } + return testDone(); }