ChimeraTK-DeviceAccess 03.25.00
Loading...
Searching...
No Matches
testableRebotSleep_testingImpl.h
Go to the documentation of this file.
1// SPDX-FileCopyrightText: Deutsches Elektronen-Synchrotron DESY, MSK, ChimeraTK Project <chimeratk-support@desy.de>
2// SPDX-License-Identifier: LGPL-3.0-or-later
3#pragma once
4
5#include <boost/chrono.hpp>
6#include <boost/thread.hpp>
7
8#include <atomic>
9#include <iostream>
10#include <mutex>
11
12typedef boost::chrono::steady_clock::time_point TimePoint;
13
14namespace ChimeraTK {
16 public:
17 static boost::chrono::steady_clock::time_point now() {
18 std::cout << "TestIMPL:: returning now = " << (_epoch - _now).count() << std::endl;
19 return _now;
20 }
21 static boost::chrono::steady_clock::time_point _now;
22 static boost::chrono::steady_clock::time_point _epoch;
23
24 template<class Rep, class Period>
25 static void setTime(boost::chrono::duration<Rep, Period> timeSinceMyEpoch) {
26 _now = _epoch + timeSinceMyEpoch;
27 }
28 };
29 TimePoint RebotTestableClock::_epoch(boost::chrono::steady_clock::now());
31
32 // In a future implementation we might want to hold several synchronisers (one
33 // for each thread) in a loopup table. For now we the members static.
35 static std::mutex _lock;
36 // only modify this variable while holding the lock. You may read it without, that's why it's atomic.
37 static std::atomic<bool> _clientMayGetLock;
38 // may only be accessed while holding the lock.
39 static boost::chrono::steady_clock::time_point _nextRequestedWakeup;
40 // may only be modified once (set to true) by the client code (in sleep_until)
41 static std::atomic<bool> _clientHasReachedTestableMode;
42
43 // only used in the test thread
45 };
46
48 std::atomic<bool> RebotSleepSynchroniser::_clientMayGetLock(false);
49 boost::chrono::steady_clock::time_point RebotSleepSynchroniser::_nextRequestedWakeup = RebotTestableClock::_epoch;
52
53 namespace testable_rebot_sleep {
54 boost::chrono::steady_clock::time_point now() {
55 std::cout << "function TestIMPL:: returning now = "
56 << (RebotTestableClock::_now - RebotTestableClock::_epoch).count() << std::endl;
58 }
59
65 void sleep_until(boost::chrono::steady_clock::time_point t) {
67
68 // The application is done with whatever it was doing and going to sleep.
69 // This is the synchronisation point where we hand the lock back to the
70 // test thread.
73 }
74 else {
75 // We don't hold the lock yet, so we cannot unlock it. But the next time we reach this place we will.
77 }
78
79 std::cout << "application unlocked" << std::endl;
80
81 // Yield the thread (give away the rest of the time slice) until we are
82 // allowed to hold the lock. The actual waiting for execution is happening in
83 // the lock. This flag is only used to avoid the race condition that the
84 // application tries to lock before the test thread had the change to aquire
85 // the lock. For a proper handshake both test code and application must have
86 // locked before the other side relocks.
87 std::cout << "application yielding..." << std::endl;
88 do {
89 boost::this_thread::interruption_point();
90 boost::this_thread::yield();
92
93 std::cout << "application trying to lock" << std::endl;
95 // now that we are holding the lock we set _clientMayGetLock to false and
96 // wait for the test thread to signal us that we can take the lock again
98 std::cout << "application locked, mayget is false" << std::endl;
99 }
100
101 // don't use this directly, only through advance_until
104 std::cout << "test unlocked" << std::endl;
105
106 // the client must signal that it acquired the lock, otherwise we do not know
107 // if it excecuted its task or not. As long as the client is still allowed to
108 // get the lock, it has not had it, and we don't get it again.
109 std::cout << "test yielding..." << std::endl;
110 do {
111 boost::this_thread::yield();
113
114 std::cout << "test trying to lock" << std::endl;
116 // Signal to the client that you were holding the lock and the synchronisation
117 // is done. So the next time it checks the lock it is allowed to hold it.
119 // The client will block, trying to get the lock and woken up by the scheduler
120 // when it is freed again.
121 std::cout << "test locked, mayget is true" << std::endl;
122 }
123
124 template<class Rep, class Period>
125 void advance_until(boost::chrono::duration<Rep, Period> targetTimeRelativeMyEpoch) {
127 auto absoluteTargetTime = RebotTestableClock::_epoch + targetTimeRelativeMyEpoch;
128 std::cout << "advanving to " << (absoluteTargetTime - RebotTestableClock::_epoch).count() << std::endl;
129 std::cout << "next wakeup requested for "
131
132 while(RebotTestableClock::_now < absoluteTargetTime) {
133 if(RebotSleepSynchroniser::_nextRequestedWakeup <= absoluteTargetTime) {
136 }
137 else {
138 RebotTestableClock::_now = absoluteTargetTime;
139 }
140 }
141 }
142
143 // The client always starts without the lock because it starts a new thread and is only interacting with
144 // sleep_until(). So we have to wait in the test until the is waiting in sleep_until, then get the lock.
146 boost::this_thread::yield();
148 boost::this_thread::yield();
149 }
151 RebotSleepSynchroniser::_clientMayGetLock = true; // client may get the lock the next time the tests releases it.
152 RebotSleepSynchroniser::_testHasReachedTestableMode = true; // make sure this function is called first by an
153 // assertion in advance_until.
154 std::cout << "test locked initially , mayget is true" << std::endl;
155 }
156
157 } // namespace testable_rebot_sleep
158} // namespace ChimeraTK
static boost::chrono::steady_clock::time_point _epoch
static void setTime(boost::chrono::duration< Rep, Period > timeSinceMyEpoch)
static boost::chrono::steady_clock::time_point _now
static boost::chrono::steady_clock::time_point now()
boost::chrono::steady_clock::time_point now()
void sleep_until(boost::chrono::steady_clock::time_point t)
There are two implementations with the same signature: One that calls boost::thread::this_thread::sle...
void advance_until(boost::chrono::duration< Rep, Period > targetTimeRelativeMyEpoch)
static std::atomic< bool > _clientHasReachedTestableMode
static boost::chrono::steady_clock::time_point _nextRequestedWakeup
boost::chrono::steady_clock::time_point TimePoint