Fast RTPS  Version 2.11.2
Fast RTPS
TimedMutex.hpp
1 // Copyright 2018 Proyectos y Sistemas de Mantenimiento SL (eProsima).
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
19 #ifndef _UTILS_TIMEDMUTEX_HPP_
20 #define _UTILS_TIMEDMUTEX_HPP_
21 
22 #include <chrono>
23 #include <iostream>
24 
25 #if defined(_WIN32)
26 #include <thread>
27 extern int clock_gettime(
28  int,
29  struct timespec* tv);
30 #elif _GTHREAD_USE_MUTEX_TIMEDLOCK
31 #include <mutex>
32 #else
33 #include <pthread.h>
34 #endif // if defined(_WIN32)
35 
36 namespace eprosima {
37 namespace fastrtps {
38 
39 #if defined(_WIN32)
40 
41 class TimedMutex
42 {
43  // On MSVC 19.36.32528.95 `xtime` was changed into `_timespec64`.
44  // See https://github.com/eProsima/Fast-DDS/issues/3451
45  // See https://github.com/microsoft/STL/pull/3594
46 #if defined(_MSC_FULL_VER) && _MSC_FULL_VER >= 193632528
47  using xtime = _timespec64;
48 #endif // _MSC_FULL_VER check
49 
50 public:
51 
52  TimedMutex()
53  {
54  _Mtx_init(&mutex_, _Mtx_timed);
55  }
56 
57  TimedMutex(
58  const TimedMutex&) = delete;
59  TimedMutex& operator =(
60  const TimedMutex&) = delete;
61 
62  ~TimedMutex()
63  {
64  _Mtx_destroy(mutex_);
65  }
66 
67  void lock()
68  {
69  _Mtx_lock(mutex_);
70  }
71 
72  void unlock()
73  {
74  _Mtx_unlock(mutex_);
75  }
76 
77  template <class Rep, class Period>
78  bool try_lock_for(
79  const std::chrono::duration<Rep, Period>& rel_time)
80  {
81  return try_lock_until(std::chrono::steady_clock::now() + rel_time);
82  }
83 
84  template <class Clock, class Duration>
85  bool try_lock_until(
86  const std::chrono::time_point<Clock, Duration>& abs_time)
87  {
88  std::chrono::nanoseconds nsecs = abs_time - Clock::now();
89 
90  if (0 < nsecs.count())
91  {
92  struct timespec max_wait = {
93  0, 0
94  };
95  clock_gettime(1, &max_wait);
96  nsecs = nsecs + std::chrono::nanoseconds(max_wait.tv_nsec);
97  auto secs = std::chrono::duration_cast<std::chrono::seconds>(nsecs);
98  nsecs -= secs;
99  max_wait.tv_sec += secs.count();
100  max_wait.tv_nsec = (long)nsecs.count();
101  return (_Thrd_success == _Mtx_timedlock(mutex_, (xtime*)&max_wait));
102  }
103  else
104  {
105  return (_Thrd_success == _Mtx_trylock(mutex_));
106  }
107  }
108 
109  void* native_handle() noexcept
110  {
111  return mutex_;
112  }
113 
114 private:
115 
116  _Mtx_t mutex_;
117 };
118 
120 {
121 public:
122 
124  {
125  _Mtx_init(&mutex_, _Mtx_timed | _Mtx_recursive);
126  }
127 
129  const TimedMutex&) = delete;
130  RecursiveTimedMutex& operator =(
131  const TimedMutex&) = delete;
132 
134  {
135  _Mtx_destroy(mutex_);
136  }
137 
138  void lock()
139  {
140  _Mtx_lock(mutex_);
141  }
142 
143  void unlock()
144  {
145  _Mtx_unlock(mutex_);
146  }
147 
148  bool try_lock()
149  {
150  return (_Thrd_success == _Mtx_trylock(mutex_));
151  }
152 
153  template <class Rep, class Period>
154  bool try_lock_for(
155  const std::chrono::duration<Rep, Period>& rel_time)
156  {
157  return try_lock_until(std::chrono::steady_clock::now() + rel_time);
158  }
159 
160  template <class Clock, class Duration>
161  bool try_lock_until(
162  const std::chrono::time_point<Clock, Duration>& abs_time)
163  {
164  std::chrono::nanoseconds nsecs = abs_time - Clock::now();
165  if (0 < nsecs.count())
166  {
167  struct timespec max_wait = {
168  0, 0
169  };
170  clock_gettime(1, &max_wait);
171  nsecs = nsecs + std::chrono::nanoseconds(max_wait.tv_nsec);
172  auto secs = std::chrono::duration_cast<std::chrono::seconds>(nsecs);
173  nsecs -= secs;
174  max_wait.tv_sec += secs.count();
175  max_wait.tv_nsec = (long)nsecs.count();
176  return (_Thrd_success == _Mtx_timedlock(mutex_, (xtime*)&max_wait));
177  }
178  else
179  {
180  return (_Thrd_success == _Mtx_trylock(mutex_));
181  }
182  }
183 
184  void* native_handle() noexcept
185  {
186  return mutex_;
187  }
188 
189 private:
190 
191  _Mtx_t mutex_;
192 };
193 #elif _GTHREAD_USE_MUTEX_TIMEDLOCK || !defined(__unix__)
194 using TimedMutex = std::timed_mutex;
195 using RecursiveTimedMutex = std::recursive_timed_mutex;
196 #else
197 class TimedMutex
198 {
199 public:
200 
201  TimedMutex()
202  {
203  pthread_mutex_init(&mutex_, nullptr);
204  }
205 
206  TimedMutex(
207  const TimedMutex&) = delete;
208  TimedMutex& operator =(
209  const TimedMutex&) = delete;
210 
211  ~TimedMutex()
212  {
213  pthread_mutex_destroy(&mutex_);
214  }
215 
216  void lock()
217  {
218  pthread_mutex_lock(&mutex_);
219  }
220 
221  void unlock()
222  {
223  pthread_mutex_unlock(&mutex_);
224  }
225 
226  template <class Rep, class Period>
227  bool try_lock_for(
228  const std::chrono::duration<Rep, Period>& rel_time)
229  {
230  return try_lock_until(std::chrono::steady_clock::now() + rel_time);
231  }
232 
233  template <class Clock, class Duration>
234  bool try_lock_until(
235  const std::chrono::time_point<Clock, Duration>& abs_time)
236  {
237  std::chrono::nanoseconds nsecs = abs_time - Clock::now();
238  struct timespec max_wait = {
239  0, 0
240  };
241  clock_gettime(CLOCK_REALTIME, &max_wait);
242  nsecs = nsecs + std::chrono::nanoseconds(max_wait.tv_nsec);
243  auto secs = std::chrono::duration_cast<std::chrono::seconds>(nsecs);
244  nsecs -= secs;
245  max_wait.tv_sec += secs.count();
246  max_wait.tv_nsec = (long)nsecs.count();
247  return (0 == pthread_mutex_timedlock(&mutex_, &max_wait));
248  }
249 
250  pthread_mutex_t* native_handle() noexcept
251  {
252  return &mutex_;
253  }
254 
255 private:
256 
257  pthread_mutex_t mutex_;
258 };
259 
261 {
262 public:
263 
265  {
266  pthread_mutexattr_init(&mutex_attr_);
267  pthread_mutexattr_settype(&mutex_attr_, PTHREAD_MUTEX_RECURSIVE);
268  pthread_mutex_init(&mutex_, &mutex_attr_);
269  }
270 
272  const RecursiveTimedMutex&) = delete;
273  RecursiveTimedMutex& operator =(
274  const RecursiveTimedMutex&) = delete;
275 
277  {
278  pthread_mutex_destroy(&mutex_);
279  pthread_mutexattr_destroy(&mutex_attr_);
280  }
281 
282  void lock()
283  {
284  pthread_mutex_lock(&mutex_);
285  }
286 
287  void unlock()
288  {
289  pthread_mutex_unlock(&mutex_);
290  }
291 
292  bool try_lock()
293  {
294  return (0 == pthread_mutex_trylock(&mutex_));
295  }
296 
297  template <class Rep, class Period>
298  bool try_lock_for(
299  const std::chrono::duration<Rep, Period>& rel_time)
300  {
301  return try_lock_until(std::chrono::steady_clock::now() + rel_time);
302  }
303 
304  template <class Clock, class Duration>
305  bool try_lock_until(
306  const std::chrono::time_point<Clock, Duration>& abs_time)
307  {
308  std::chrono::nanoseconds nsecs = abs_time - Clock::now();
309  struct timespec max_wait = {
310  0, 0
311  };
312  clock_gettime(CLOCK_REALTIME, &max_wait);
313  nsecs = nsecs + std::chrono::nanoseconds(max_wait.tv_nsec);
314  auto secs = std::chrono::duration_cast<std::chrono::seconds>(nsecs);
315  nsecs -= secs;
316  max_wait.tv_sec += secs.count();
317  max_wait.tv_nsec = (long)nsecs.count();
318  return (0 == pthread_mutex_timedlock(&mutex_, &max_wait));
319  }
320 
321  pthread_mutex_t* native_handle() noexcept
322  {
323  return &mutex_;
324  }
325 
326 private:
327 
328  pthread_mutexattr_t mutex_attr_;
329 
330  pthread_mutex_t mutex_;
331 };
332 
333 #endif //_WIN32
334 
335 } //namespace fastrtps
336 } //namespace eprosima
337 
338 #endif // _UTILS_TIMEDMUTEX_HPP_
std::recursive_timed_mutex RecursiveTimedMutex
Definition: TimedMutex.hpp:195
std::timed_mutex TimedMutex
Definition: TimedMutex.hpp:194
eProsima namespace.
Definition: LibrarySettingsAttributes.h:23