This resolves a long-standing issue: we could not use proper include paths for test-helper code that was defined alongside the tests. Since some test-helper code must now be relocated into the »Vault«-Layer, I took the opportunity to finally resolve this annoyance. The solution is two-fold * introduce a dedicated test-support library * remove the quirks that were necessary to support some plain-C tests Together, this allows to raise the include-directory by one level, and then to adjust all folder names so that they match the namespace
118 lines
3.1 KiB
C++
118 lines
3.1 KiB
C++
/*
|
||
SyncWaiting(Test) - check the monitor object based wait/notification
|
||
|
||
Copyright (C)
|
||
2008, Hermann Vosseler <Ichthyostega@web.de>
|
||
|
||
**Lumiera** 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. See the file COPYING for further details.
|
||
|
||
* *****************************************************************/
|
||
|
||
/** @file sync-waiting-test.cpp
|
||
** unit test \ref SyncWaiting_test
|
||
*/
|
||
|
||
|
||
#include "test/run.hpp"
|
||
#include "lib/error.hpp"
|
||
|
||
#include "lib/thread.hpp"
|
||
#include "lib/sync.hpp"
|
||
|
||
#include <atomic>
|
||
|
||
using test::Test;
|
||
using std::atomic_uint;
|
||
using std::atomic_bool;
|
||
using std::this_thread::sleep_for;
|
||
using std::chrono_literals::operator ""ms;
|
||
|
||
|
||
namespace lib {
|
||
namespace test{
|
||
|
||
namespace { // test subject...
|
||
|
||
/** demonstrates how to wait on a simple boolean flag */
|
||
class SyncOnBool
|
||
: public Sync<NonrecursiveLock_Waitable>
|
||
{
|
||
atomic_uint sum_{0}, input_{0};
|
||
atomic_bool got_new_data_{false};
|
||
|
||
public:
|
||
void getIt()
|
||
{
|
||
Lock await{this, [&]{ return bool(got_new_data_); }};
|
||
sum_ += input_;
|
||
}
|
||
|
||
void provide (uint val)
|
||
{
|
||
Lock sync{this};
|
||
input_ = val;
|
||
got_new_data_ = true;
|
||
sync.notify_all();
|
||
}
|
||
|
||
/** harvesting the result...*/
|
||
uint result () { return sum_; }
|
||
};
|
||
}//(End) test subject.
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
/************************************************************************//**
|
||
* @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. Two interwoven
|
||
* threads are created, both blocked until a start value is given. Once awakened,
|
||
* each thread should add the start value to a common sum field.
|
||
* @see SyncLocking_test
|
||
* @see sync.hpp
|
||
*/
|
||
class SyncWaiting_test : public Test
|
||
{
|
||
|
||
virtual void
|
||
run (Arg)
|
||
{
|
||
seedRand();
|
||
SyncOnBool token;
|
||
|
||
ThreadJoinable ping ("SyncWaiting ping", [&]{ token.getIt(); });
|
||
ThreadJoinable pong ("SyncWaiting pong", [&]{ token.getIt(); });
|
||
|
||
CHECK (ping);
|
||
CHECK (pong);
|
||
CHECK (0 == token.result());
|
||
|
||
sleep_for (100ms); // if the threads don't block correctly, they've missed their chance by now...
|
||
|
||
// kick off the notification cascade...
|
||
uint val = rani(1000);
|
||
token.provide (val);
|
||
|
||
// wait for the two Threads to finish their handshake
|
||
pong.join();
|
||
ping.join();
|
||
|
||
CHECK (2*val == token.result());
|
||
}
|
||
};
|
||
|
||
|
||
|
||
/** Register this test class... */
|
||
LAUNCHER (SyncWaiting_test, "unit common");
|
||
|
||
|
||
|
||
}} // namespace lib::test
|