Gazebo Common

API Reference

6.0.0
Event.hh
Go to the documentation of this file.
1/*
2 * Copyright (C) 2016 Open Source Robotics Foundation
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *
16*/
17#ifndef GZ_COMMON_EVENT_HH_
18#define GZ_COMMON_EVENT_HH_
19
20#include <atomic>
21#include <functional>
22#include <list>
23#include <map>
24#include <memory>
25#include <mutex>
26#include <utility>
27
28#include <gz/common/config.hh>
29#include <gz/common/events/Export.hh>
31
32namespace gz
33{
34 namespace common
35 {
38 class GZ_COMMON_EVENTS_VISIBLE Event
39 {
41 public: Event();
42
44 public: virtual ~Event();
45
48 public: virtual void Disconnect(int _id) = 0;
49
52 public: bool Signaled() const;
53
56 public: void SetSignaled(bool _sig);
57
59 private: bool signaled;
60 };
61
63 class GZ_COMMON_EVENTS_VISIBLE Connection
64 {
68 public: Connection(Event *_e, int _i);
69
71 public: ~Connection();
72
75 public: int Id() const;
76
78 private: Event *event = nullptr;
79
81 private: int id = -1;
82
83#ifdef _WIN32
84// Disable warning C4251
85#pragma warning(push)
86#pragma warning(disable: 4251)
87#endif
90#ifdef _WIN32
91#pragma warning(pop)
92#endif
93
95 public: template<typename T, typename N> friend class EventT;
96 };
97
102 template<typename T, typename N = void>
103 class EventT : public Event
104 {
107 "Event callback must have void return type");
108
110 public: EventT();
111
113 public: virtual ~EventT();
114
119 public: ConnectionPtr Connect(const CallbackT &_subscriber);
120
123 public: virtual void Disconnect(int _id);
124
127 public: unsigned int ConnectionCount() const;
128
130 public: template<typename ... Args>
131 void operator()(Args && ... args)
132 {
133 this->Signal(std::forward<Args>(args)...);
134 }
135
137 public: template <typename ... Args>
138 void Signal(Args && ... args)
139 {
140 this->Cleanup();
141
142 this->SetSignaled(true);
143 for (const auto &iter : this->connections)
144 {
145 if (iter.second->on)
146 iter.second->callback(std::forward<Args>(args)...);
147 }
148 }
149
153 private: void Cleanup();
154
156 private: class EventConnection
157 {
159 public: EventConnection(bool _on, const std::function<T> &_cb,
160 const ConnectionPtr &_publicConn)
161 : callback(_cb), publicConnection(_publicConn)
162 {
163 // Windows Visual Studio 2012 does not have atomic_bool constructor,
164 // so we have to set "on" using operator=
165 this->on = _on;
166 }
167
169 public: std::atomic_bool on;
170
172 public: std::function<T> callback;
173
177 public: std::weak_ptr<Connection> publicConnection;
178 };
179
182 typedef std::map<int, std::unique_ptr<EventConnection>> EvtConnectionMap;
183
185 private: EvtConnectionMap connections;
186
188 private: std::mutex mutex;
189
192 connectionsToRemove;
193 };
194
196 template<typename T, typename N>
198 : Event()
199 {
200 }
201
203 template<typename T, typename N>
205 {
206 // Clear the Event pointer on all connections so that they are not
207 // accessed after this Event is destructed.
208 for (auto &conn : this->connections)
209 {
210 auto publicCon = conn.second->publicConnection.lock();
211 if (publicCon)
212 {
213 publicCon->event = nullptr;
214 }
215 }
216 this->connections.clear();
217 }
218
221 template<typename T, typename N>
223 {
224 int index = 0;
225 if (!this->connections.empty())
226 {
227 auto const &iter = this->connections.rbegin();
228 index = iter->first + 1;
229 }
230 auto connection = ConnectionPtr(new Connection(this, index));
231 this->connections[index].reset(
232 new EventConnection(true, _subscriber, connection));
233 return connection;
234 }
235
238 template<typename T, typename N>
239 unsigned int EventT<T, N>::ConnectionCount() const
240 {
241 return this->connections.size();
242 }
243
246 template<typename T, typename N>
248 {
249 // Find the connection
250 auto const &it = this->connections.find(_id);
251
252 if (it != this->connections.end())
253 {
254 it->second->on = false;
255 // The destructor of std::function seems to crashes if the function it
256 // points to is in a shared library and has been unloaded by the time
257 // the destructor is invoked. It's not clear whether this is a bug in
258 // the implementation of std::function or not. To avoid the crash,
259 // we call the destructor here by setting `callback = nullptr` because
260 // it is likely that EventT::Disconnect is called before the shared
261 // library is unloaded via Connection::~Connection.
262 it->second->callback = nullptr;
263 this->connectionsToRemove.push_back(it);
264 }
265 }
266
268 template<typename T, typename N>
270 {
271 std::lock_guard<std::mutex> lock(this->mutex);
272 // Remove all queue connections.
273 for (auto &conn : this->connectionsToRemove)
274 this->connections.erase(conn);
275 this->connectionsToRemove.clear();
276 }
277 }
278}
279#endif