YARP
Yet Another Robot Platform
 
Loading...
Searching...
No Matches
Time.cpp
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2006-2021 Istituto Italiano di Tecnologia (IIT)
3 * SPDX-FileCopyrightText: 2006, 2011 Anne van Rossum <anne@almende.com>
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7#include <yarp/os/Time.h>
8
9#include <yarp/os/Network.h>
11#include <yarp/os/SystemClock.h>
12#include <yarp/os/Thread.h>
16
17#include <mutex>
18
19#if defined(_WIN32)
20// for WIN32 MM functions
21# include <mmsystem.h>
22#endif
23
24using namespace yarp::os;
25
26namespace {
27YARP_OS_LOG_COMPONENT(TIME, "yarp.os.Time")
28} // namespace
29
30namespace {
31
32bool clock_owned = false;
33bool network_clock_ok = false;
34Clock* pclock = nullptr;
36
37std::mutex& getTimeMutex()
38{
39 static std::mutex mutex;
40 return mutex;
41}
42
44{
45 yCError(TIME, "Warning an issue has been found, please update the code.");
46 yCError(TIME, " Clock is not initialized.");
47 yCError(TIME, " This means YARP framework has not been properly initialized.");
48 yCError(TIME, " The clock can be initialized with one of the following methods:");
49 yCError(TIME, " - Create yarp::os::Network object or call yarp::os::Network::init()");
50 yCError(TIME, " - Call useSystemClock()");
51 yCError(TIME, " otherwise use yarp::os::SystemClock::nowSystem() and yarp::os::SystemClock::delaySystem() instead of Time::now() and Time::delay()");
52}
53
55{
56 if (pclock == nullptr) {
57 /*
58 * Assuming this should never happen, if we do get here, what shall be done??
59 *
60 * 1: create system clock
61 * If we get here, probably there is some sort of race condition while changing the clock,
62 * so creating a system clock may not be what we want to do, and this may interfere with the
63 * clock really wanted by the user, i.e. this system clock may be destroyed again to
64 * instantiate the good one, leaving space for another possible race condition.
65 *
66 * 2: use the system clock only for this call
67 *
68 * 3: exit now and ask user to correctly initialize the framework
69 * This is better because it shows initialization problems right from the start and help user
70 * to fix the code, which may otherwise lead to undefined behaviour.
71 *
72 * So now initialize a system clock and exit.
73 */
75 std::exit(-1);
76 }
77 return pclock;
78}
79} // namespace
80
81
83{
84 if (pclock != nullptr) {
85 delete pclock;
86 pclock = nullptr;
87 }
89}
90
92{
93#if defined(_WIN32)
94 // only does something on Microsoft Windows
96 timeGetDevCaps(&tm, sizeof(TIMECAPS));
97 timeBeginPeriod(tm.wPeriodMin);
98#endif
99}
100
102{
103#if defined(_WIN32)
104 // only does something on Microsoft Windows
105 TIMECAPS tm;
106 timeGetDevCaps(&tm, sizeof(TIMECAPS));
107 timeEndPeriod(tm.wPeriodMin);
108#endif
109}
110
112{
113 if (isSystemClock()) {
115 }
116
117 Clock* clk = getClock();
118 clk->delay(seconds);
119}
120
121double Time::now()
122{
123 if (isSystemClock()) {
124 return SystemClock::nowSystem();
125 }
126
127 Clock* clk = getClock();
128 return clk->now();
129}
130
132{
134}
135
136
138{
139 if (!isSystemClock()) {
140 getTimeMutex().lock();
141
144
145 pclock = new SystemClock();
148 clock_owned = true;
149
150 if (old_clock_owned && (old_pclock != nullptr)) {
151 delete old_pclock;
152 }
153
154 getTimeMutex().unlock();
155 }
156}
157
158/* Creation of network clock may fail for different causes:
159 * - cannot open port
160 * - cannot connect to nameserver
161 *
162 * They may be handled in different ways, for example for the firsts two cases, it simply fails and
163 * continue with system clock. Failure should be reported to the user and 'pclock' pointer will be temporary
164 * set to NULL (which is an INVALID value).
165 * isSystemClock() will still return true because it is the clock currently active.
166 *
167 * In case the source clock is not yet publishing time data, we wait here for the first valid clock, this way
168 * the application will not start until the clock is correctly configured.
169 * In this situation
170 * - isSystemClock() will be false
171 * - isNetworkClock() will be true
172 * - isValid() will be false until the first clock message is received, then it'll be true
173 *
174 * As soon as the clock starts being published, the networkClock has to acknowledge it and 'attach' to it. Clock will
175 * then be valid.
176 */
177void Time::useNetworkClock(const std::string& clock, const std::string& localPortName)
178{
179 // re-create the clock also in case we already use a network clock, because
180 // the input clock port may be different or the clock producer may be changed (different
181 // clock source publishing on the same port/topic), so we may need to reconnect.
182 getTimeMutex().lock();
183
184 Clock* old_pclock = pclock; // store current clock pointer to delete it afterward
186 auto* _networkClock = new NetworkClock();
187 if (_networkClock == nullptr) {
188 yCFatal(TIME, "failed creating NetworkClock client");
189 return;
190 }
192 network_clock_ok = true; // see if it is really needed
193 // updating clock pointer with the new one already initialized.
194
196 clock_owned = true;
198 } else {
199 yCFatal(TIME, "failed creating NetworkClock client, cannot open input port");
200 return;
201 }
202
203 if (old_clock_owned && (old_pclock != nullptr)) {
204 delete old_pclock;
205 }
206
207 getTimeMutex().unlock();
208
209 int i = -1;
210 while ((pclock != nullptr) && !pclock->isValid()) {
211 i++;
212 if ((i % 50) == 0) {
213 yCInfo(TIME, "Waiting for clock server to start broadcasting data ...");
214 i = 0;
215 }
217 }
218}
219
221{
222 if (clock == nullptr) {
223 yCFatal(TIME, "failed configuring CustomClock client");
224 return;
225 }
226
227 if (!clock->isValid()) {
228 yCFatal(TIME, "Error: CustomClock is not valid");
229 return;
230 }
231
232 getTimeMutex().lock();
233
234 // store current clock pointer to delete it afterward
237
238 pclock = clock;
240 clock_owned = false;
241
242 // delete old clock
243 if (old_clock_owned && (old_pclock != nullptr)) {
244 delete old_pclock;
245 }
246
247 getTimeMutex().unlock();
248}
249
254
256{
258}
259
264
266{
268}
269
274
276{
277 std::string clockTypeString;
278 if (type == -1) {
279 type = yarp_clock_type;
280 }
281
282 switch (type) {
284 clockTypeString = "System clock";
285 break;
286
288 clockTypeString = "Network clock";
289 break;
290
292 clockTypeString = "Custom clock";
293 break;
294
296 clockTypeString = "Clock has not been initialized yet: This should never happen. Is the object yarp::os::Network been initialized?";
297 break;
298
299 default:
300 clockTypeString = "Unknown clock: This should never happen. Is the object yarp::os::Network been initialized?";
301 break;
302 }
303 return clockTypeString;
304}
305
306
308{
309 // The clock must never be NULL here
310 return getClock()->isValid();
311}
A mini-server for performing network communication in the background.
bool open(const std::string &name) override
Start port operation, with a specific name, with automatically-chosen network parameters.
static double nowSystem()
static void delaySystem(double seconds)
static void yield()
Reschedule the execution of current thread, allowing other threads to run.
Definition Thread.cpp:150
#define yCInfo(component,...)
#define yCError(component,...)
#define yCAssert(component, x)
#define yCFatal(component,...)
#define YARP_OS_LOG_COMPONENT(name, name_string)
yarpClockType getClockType()
Definition Time.cpp:270
bool isNetworkClock()
Check if YARP is providing network time.
Definition Time.cpp:260
void useSystemClock()
Configure YARP to use system time (this is the default).
Definition Time.cpp:137
bool isClockInitialized()
Check if YARP clock is initialized.
Definition Time.cpp:250
bool isValid()
Check if time is valid (non-zero).
Definition Time.cpp:307
void yield()
The calling thread releases its remaining quantum upon calling this function.
Definition Time.cpp:131
double now()
Return the current time in seconds, relative to an arbitrary starting point.
Definition Time.cpp:121
void useNetworkClock(const std::string &clock, const std::string &localPortName="")
Configure YARP to read time from a specified topic.
Definition Time.cpp:177
void delay(double seconds)
Wait for a certain number of seconds.
Definition Time.cpp:111
void useCustomClock(Clock *clock)
Configure YARP clients to use a custom clock source provided by the user.
Definition Time.cpp:220
bool isCustomClock()
Check if YARP is using a user-defined custom time.
Definition Time.cpp:265
bool isSystemClock()
Check if YARP is providing system time.
Definition Time.cpp:255
std::string clockTypeToString(yarpClockType type)
Converts clock type enum into string.
Definition Time.cpp:275
void startTurboBoost()
For OS where it makes sense sets the scheduler to be called more often.
Definition Time.cpp:91
An interface to the operating system, including Port based communication.
yarpClockType
Definition Time.h:25
@ YARP_CLOCK_UNINITIALIZED
Definition Time.h:26
@ YARP_CLOCK_CUSTOM
Definition Time.h:30
@ YARP_CLOCK_SYSTEM
Definition Time.h:28
@ YARP_CLOCK_NETWORK
Definition Time.h:29