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>
27extern 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
36namespace eprosima {
37namespace fastrtps {
38
39#if defined(_WIN32)
40
41class 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
50public:
51
53 {
54 _Mtx_init(&mutex_, _Mtx_timed);
55 }
56
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
114private:
115
116 _Mtx_t mutex_;
117};
118
120{
121public:
122
124 {
125 _Mtx_init(&mutex_, _Mtx_timed | _Mtx_recursive);
126 }
127
129 const TimedMutex&) = delete;
130 RecursiveTimedMutex& operator =(
131 const TimedMutex&) = delete;
132
133 ~RecursiveTimedMutex()
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
189private:
190
191 _Mtx_t mutex_;
192};
193#elif _GTHREAD_USE_MUTEX_TIMEDLOCK || !defined(__unix__)
194using TimedMutex = std::timed_mutex;
195using RecursiveTimedMutex = std::recursive_timed_mutex;
196#else
197class TimedMutex
198{
199public:
200
201 TimedMutex()
202 {
203 pthread_mutex_init(&mutex_, nullptr);
204 }
205
207 const TimedMutex&) = delete;
208 TimedMutex& operator =(
209 const TimedMutex&) = delete;
210
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
255private:
256
257 pthread_mutex_t mutex_;
258};
259
261{
262public:
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
276 ~RecursiveTimedMutex()
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
326private:
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