YARP
Yet Another Robot Platform
NetworkClock.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2006-2020 Istituto Italiano di Tecnologia (IIT)
3  * All rights reserved.
4  *
5  * This software may be modified and distributed under the terms of the
6  * BSD-3-Clause license. See the accompanying LICENSE file for details.
7  */
8 
9 #include <yarp/os/NetworkClock.h>
10 
11 #include <yarp/conf/numeric.h>
12 #include <yarp/conf/system.h>
13 
14 #include <yarp/os/NestedContact.h>
15 #include <yarp/os/NetInt32.h>
16 #include <yarp/os/Network.h>
17 #include <yarp/os/Os.h>
18 #include <yarp/os/Port.h>
19 #include <yarp/os/PortReader.h>
20 #include <yarp/os/Semaphore.h>
21 #include <yarp/os/SystemClock.h>
22 #include <yarp/os/SystemInfo.h>
24 
25 #include <cstring>
26 #include <list>
27 #include <mutex>
28 #include <utility>
29 
30 
31 using namespace yarp::os;
32 using namespace yarp::os::impl;
33 
34 namespace {
35 YARP_OS_LOG_COMPONENT(NETWORKCLOCK, "yarp.os.NetworkClock")
36 }
37 
39 {
40 public:
41  Private();
42  ~Private() override;
43 
44  bool read(ConnectionReader& reader) override;
45 
46  std::string clockName;
47 
48  using Waiters = std::list<std::pair<double, Semaphore*>>;
51 
52  std::mutex listMutex;
53  std::mutex timeMutex;
54 
55  std::int32_t sec{0};
56  std::int32_t nsec{0};
57  double _time{0};
58  bool closing{false};
59  bool initted{false};
60 };
61 
63  clockName("/clock"),
64  waiters(new Waiters())
65 {
66 }
67 
69 {
70  listMutex.lock();
71  closing = true;
72  port.interrupt();
73 
74  auto waiter_it = waiters->begin();
75  while (waiter_it != waiters->end()) {
76  Semaphore* waiterSemaphore = waiter_it->second;
77  waiter_it = waiters->erase(waiter_it);
78  if (waiterSemaphore != nullptr) {
79  waiterSemaphore->post();
80  }
81  }
82  delete waiters;
83  listMutex.unlock();
84 
86  style.persistent = true;
87  NetworkBase::disconnect(clockName, port.getName(), style);
88 }
89 
91 {
92  Bottle bot;
93  bool ok = bot.read(reader);
94 
95  if (closing) {
96  _time = -1;
97  return false;
98  }
99 
100  if (!ok && !closing) {
101  yCError(NETWORKCLOCK, "Error reading clock port");
102  return false;
103  }
104 
105  timeMutex.lock();
106  sec = bot.get(0).asInt32();
107  nsec = bot.get(1).asInt32();
108  _time = sec + (nsec * 1e-9);
109  initted = true;
110  timeMutex.unlock();
111 
112  listMutex.lock();
113  auto waiter_it = waiters->begin();
114  while (waiter_it != waiters->end()) {
115  if (waiter_it->first - _time < 1E-12) {
116  Semaphore* waiterSemaphore = waiter_it->second;
117  waiter_it = waiters->erase(waiter_it);
118  if (waiterSemaphore != nullptr) {
119  waiterSemaphore->post();
120  }
121  } else {
122  ++waiter_it;
123  }
124  }
125  listMutex.unlock();
126  return true;
127 }
128 
129 
130 NetworkClock::NetworkClock() :
131  mPriv(new Private)
132 {
133 }
134 
136 {
137  yCWarning(NETWORKCLOCK, "Destroying network clock");
138  delete mPriv;
139 }
140 
141 bool NetworkClock::open(const std::string& clockSourcePortName, std::string localPortName)
142 {
143  mPriv->port.setReadOnly();
144  mPriv->port.setReader(*mPriv);
145  if (!clockSourcePortName.empty()) {
146  mPriv->clockName = clockSourcePortName;
147  }
148  NestedContact nc(mPriv->clockName);
149 
151  style.persistent = true;
152 
153  if (localPortName.empty()) {
154  const int MAX_STRING_SIZE = 255;
155  char hostName[MAX_STRING_SIZE];
156  yarp::os::gethostname(hostName, MAX_STRING_SIZE);
157 
159 
160  localPortName = "/";
161  // Ports may be anonymous to not pollute the yarp name list
162  localPortName += std::string(hostName) + "/" + processInfo.name + "/" + std::string(std::to_string(processInfo.pid)) + "/clock:i";
163  }
164 
165  // if receiving port cannot be opened, return false.
166  bool ret = mPriv->port.open(localPortName);
167  if (!ret) {
168  return false;
169  }
170 
171  if (nc.getNestedName().empty()) {
172  Contact src = NetworkBase::queryName(mPriv->clockName);
173 
174  ret = NetworkBase::connect(mPriv->clockName, mPriv->port.getName(), style);
175 
176  if (!src.isValid()) {
177  yCError(NETWORKCLOCK, "Cannot find time port \"%s\" or a time topic \"%s@\"\n", mPriv->clockName.c_str(), mPriv->clockName.c_str());
178  }
179  }
180 
181  return ret;
182 }
183 
185 {
186  mPriv->timeMutex.lock();
187  double result = mPriv->_time;
188  mPriv->timeMutex.unlock();
189  return result;
190 }
191 
192 void NetworkClock::delay(double seconds)
193 {
194  if (seconds <= 1E-12) {
195  return;
196  }
197 
198  mPriv->listMutex.lock();
199  if (mPriv->closing) {
200  // We are shutting down. The time signal is no longer available.
201  // Make a short delay and return.
202  mPriv->listMutex.unlock();
203  SystemClock::delaySystem(seconds);
204  return;
205  }
206 
207  std::pair<double, Semaphore*> waiter(now() + seconds, new Semaphore(0));
208  mPriv->waiters->push_back(waiter);
209  mPriv->listMutex.unlock();
210 
211  waiter.second->wait();
212  delete waiter.second;
213  waiter.second = nullptr;
214 }
215 
217 {
218  return mPriv->initted;
219 }
yarp::os::Bottle
A simple collection of objects that can be described and transmitted in a portable way.
Definition: Bottle.h:73
SystemClock.h
Network.h
yarp::os::ContactStyle
Preferences for how to communicate with a contact.
Definition: ContactStyle.h:27
yarp::os::NestedContact
A placeholder for rich contact information.
Definition: NestedContact.h:27
yarp::sig::file::read
bool read(ImageOf< PixelRgb > &dest, const std::string &src, image_fileformat format=FORMAT_ANY)
Definition: ImageFile.cpp:827
yarp::os::Semaphore
A class for thread synchronization and mutual exclusion.
Definition: Semaphore.h:29
yCWarning
#define yCWarning(component,...)
Definition: LogComponent.h:146
NetInt32.h
Port.h
yarp::os::NetworkClock::isValid
bool isValid() const override
Check if time is valid (non-zero).
Definition: NetworkClock.cpp:216
yarp::os::NetworkClock::Private::timeMutex
std::mutex timeMutex
Definition: NetworkClock.cpp:53
numeric.h
yarp::os::SystemInfo::ProcessInfo::pid
int pid
Definition: SystemInfo.h:121
yarp::os::NetworkClock::Private::Waiters
std::list< std::pair< double, Semaphore * > > Waiters
Definition: NetworkClock.cpp:48
yarp::os::NetworkClock::Private::read
bool read(ConnectionReader &reader) override
Read this object from a network connection.
Definition: NetworkClock.cpp:90
yarp::os::NetworkClock::Private
Definition: NetworkClock.cpp:39
ret
bool ret
Definition: ImplementAxisInfo.cpp:72
yarp::os::NetworkClock::Private::clockName
std::string clockName
Definition: NetworkClock.cpp:46
yarp::os::NetworkClock::delay
void delay(double seconds) override
Wait for a certain number of seconds.
Definition: NetworkClock.cpp:192
LogComponent.h
NestedContact.h
yarp::os::Port
A mini-server for network communication.
Definition: Port.h:50
yarp::os::NetworkBase::queryName
static Contact queryName(const std::string &name)
Find out information about a registered name.
Definition: Network.cpp:998
yarp::os::NetworkClock::now
double now() override
Return the current time in seconds, relative to an arbitrary starting point.
Definition: NetworkClock.cpp:184
yarp::os::Semaphore::post
void post()
Increment the counter.
Definition: Semaphore.cpp:114
yarp::os::PortReader
Interface implemented by all objects that can read themselves from the network, such as Bottle object...
Definition: PortReader.h:28
yarp::os::Bottle::get
Value & get(size_type index) const
Reads a Value v from a certain part of the list.
Definition: Bottle.cpp:249
yarp::os::SystemInfo::ProcessInfo::name
std::string name
Definition: SystemInfo.h:117
yarp::os::SystemClock::delaySystem
static void delaySystem(double seconds)
Definition: SystemClock.cpp:32
yarp::os::NetworkClock::open
bool open(const std::string &clockSourcePortName, std::string localPortName="")
Definition: NetworkClock.cpp:141
yarp::os::NetworkBase::connect
static bool connect(const std::string &src, const std::string &dest, const std::string &carrier="", bool quiet=true)
Request that an output port connect to an input port.
Definition: Network.cpp:685
yarp::os::ContactStyle::persistent
bool persistent
Specify whether a requested connection should be persistent.
Definition: ContactStyle.h:66
Os.h
yarp::os::SystemInfo::getProcessInfo
static ProcessInfo getProcessInfo(int pid=0)
gets the operating system process information given by its PID.
Definition: SystemInfo.cpp:808
yarp::os::NetworkClock::Private::~Private
~Private() override
Definition: NetworkClock.cpp:68
yarp::os::gethostname
void gethostname(char *hostname, size_t size)
Portable wrapper for the gethostname() function.
Definition: Os.cpp:100
NetworkClock.h
yarp::os::NetworkClock::Private::port
Port port
Definition: NetworkClock.cpp:50
yarp::os::NetworkClock::Private::Private
Private()
Definition: NetworkClock.cpp:62
Semaphore.h
system.h
yarp::os::NetworkClock::Private::waiters
Waiters * waiters
Definition: NetworkClock.cpp:49
yarp::os::ConnectionReader
An interface for reading from a network connection.
Definition: ConnectionReader.h:40
yCError
#define yCError(component,...)
Definition: LogComponent.h:157
yarp::os::Value::asInt32
virtual std::int32_t asInt32() const
Get 32-bit integer value.
Definition: Value.cpp:207
yarp::os::NetworkClock::Private::listMutex
std::mutex listMutex
Definition: NetworkClock.cpp:52
yarp::os::SystemInfo::ProcessInfo
The ProcessInfo struct provides the operating system process information.
Definition: SystemInfo.h:116
yarp::os
An interface to the operating system, including Port based communication.
Definition: AbstractCarrier.h:17
yarp::os::Contact::isValid
bool isValid() const
Checks if a Contact is tagged as valid.
Definition: Contact.cpp:301
yarp::os::Bottle::read
bool read(ConnectionReader &reader) override
Set the bottle's value based on input from a network connection.
Definition: Bottle.cpp:243
yarp::os::Contact
Represents how to reach a part of a YARP network.
Definition: Contact.h:39
PortReader.h
YARP_OS_LOG_COMPONENT
#define YARP_OS_LOG_COMPONENT(name, name_string)
Definition: LogComponent.h:37
yarp::os::impl
The components from which ports and connections are built.
yarp::os::NetworkClock::~NetworkClock
virtual ~NetworkClock()
Definition: NetworkClock.cpp:135
yarp::os::NestedContact::getNestedName
std::string getNestedName() const
Definition: NestedContact.cpp:189
SystemInfo.h