lumiera_/tests/library/sync-waiting-test.cpp
Ichthyostega ada5cefaaf re-arrange tests according to layer structure
the buildsystem will now pick up and link
all test cases according to the layer, e.g.
backend tests will automatically be linked
against the backend + library solely.
2013-01-07 05:43:01 +01:00

185 lines
4.8 KiB
C++

/*
SyncWaiting(Test) - check the monitor object based wait/notification
Copyright (C) Lumiera.org
2008, Hermann Vosseler <Ichthyostega@web.de>
This program 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.
This program 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 this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
* *****************************************************/
#include "lib/test/run.hpp"
#include "lib/error.hpp"
#include "backend/thread-wrapper.hpp"
#include "lib/sync.hpp"
#include <tr1/functional>
using std::tr1::bind;
using test::Test;
namespace lib {
namespace test{
namespace { // private test classes and data...
/** Interface defining the basic interaction pattern for this test */
class Token
{
public:
/** blocking concurrent operation */
virtual void getIt() =0;
/** start the notification chain */
virtual void provide (uint val) =0;
/** harvesting the result...*/
uint result () { return sum_; }
protected:
volatile uint sum_, input_;
virtual ~Token() {}
Token() : sum_(0), input_(0) {}
};
/** demonstrates how to wait on a simple boolean flag */
class SyncOnBool
: public Token,
public Sync<NonrecursiveLock_Waitable>
{
protected:
volatile bool got_new_data_;
public:
SyncOnBool() : got_new_data_ (false) {}
void getIt()
{
Lock(this).wait (got_new_data_);
sum_ += input_;
}
void provide (uint val)
{
Lock sync(this);
input_ = val;
got_new_data_ = true;
sync.notifyAll();
}
};
/** this variant demonstrates how to wait on an condition
* defined in terms of a (bool) member function
*/
class SyncOnMemberPredicate
: public SyncOnBool
{
bool checkTheFlag() { return this->got_new_data_; }
public:
void getIt()
{
Lock await(this, &SyncOnMemberPredicate::checkTheFlag);
sum_ += input_;
}
};
} // (End) test classes and data....
/****************************************************************************
* @test concurrent waiting and notification, implemented via object monitor.
* This test covers the second part of the monitor pattern, which builds upon
* the locking part, additionally using an embedded condition. We provide
* several pre-configured ways of specifying the condition to wait upon.
* - check a boolean flag
* - evaluate a member function as predicate
*
* @see SyncLocking_test
* @see sync.hpp
*/
class SyncWaiting_test : public Test
{
virtual void
run (Arg)
{
SyncOnBool use_sync_var;
waitPingPong (use_sync_var);
SyncOnMemberPredicate use_member_pred;
waitPingPong (use_member_pred);
}
/**
* Helper actually performing the test:
* creates two threads and let them block and wait until a start value is given.
* When awakened, each thread should add the start value to a common sum field.
* @param tok object containing the monitor and condition to be tested.
*/
void
waitPingPong (Token& tok)
{
typedef backend::ThreadJoinable Thread;
Thread ping ("SyncWaiting ping", bind (&Token::getIt, &tok));
Thread pong ("SyncWaiting pong", bind (&Token::getIt, &tok));
CHECK (ping);
CHECK (pong);
CHECK (0 == tok.result());
usleep (100000); // if the threads don't block correctly, they've missed their chance by now...
// kick off the notification cascade...
uint val = (rand() % 1000);
tok.provide (val);
// wait for the two Threads to finish their handshake
pong.join();
ping.join();
CHECK (2*val == tok.result());
}
};
/** Register this test class... */
LAUNCHER (SyncWaiting_test, "unit common");
}} // namespace lib::test