1 /***
2 * ==++==
3 *
4 * Copyright (c) Microsoft Corporation. All rights reserved.
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
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 * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
18 *
19 * Linux specific pplx implementations
20 *
21 * For the latest on this and related APIs, please see http://casablanca.codeplex.com.
22 *
23 * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
24 ****/
25
26 #pragma once
27
28
29 #if (defined(_MSC_VER))
30 #error This file must not be included for Visual Studio
31 #endif
32
33 #ifndef _WIN32
34
35 #include <signal.h>
36 #include "pthread.h"
37 #include "cpprest/details/cpprest_compat.h"
38
39 #if defined(__APPLE__)
40 #include <dispatch/dispatch.h>
41 #include <boost/thread/mutex.hpp>
42 #include <boost/thread/condition_variable.hpp>
43 #else
44 #include <mutex>
45 #include <condition_variable>
46 #endif
47
48 #include "pplx/pplxinterface.h"
49
50
52 {
53 #if defined(__APPLE__)
54 namespace cpprest_synchronization = ::boost;
55 #else
56 namespace cpprest_synchronization = ::std;
57 #endif
58 namespace details
59 {
60 namespace platform
61 {
65 _PPLXIMP long _pplx_cdecl GetCurrentThreadId();
66
70 _PPLXIMP void _pplx_cdecl YieldExecution();
71
75 __declspec(noinline) inline static
size_t CaptureCallstack(
void **,
size_t,
size_t)
76 {
77 return 0;
78 }
79 }
80
85 {
86 private:
87 cpprest_synchronization::mutex _lock;
88 cpprest_synchronization::condition_variable _condition;
89 bool _signaled;
90 public:
91
92 static const unsigned int timeout_infinite = 0xFFFFFFFF;
93
95 : _signaled(false)
96 {
97 }
98
99 void set()
100 {
101 cpprest_synchronization::lock_guard<cpprest_synchronization::mutex> lock(_lock);
102 _signaled = true;
103 _condition.notify_all();
104 }
105
106 void reset()
107 {
108 cpprest_synchronization::lock_guard<cpprest_synchronization::mutex> lock(_lock);
109 _signaled = false;
110 }
111
112 unsigned int wait(unsigned int timeout)
113 {
114 cpprest_synchronization::unique_lock<cpprest_synchronization::mutex> lock(_lock);
115 if (timeout == event_impl::timeout_infinite)
116 {
117 _condition.wait(lock, [this]() -> bool { return _signaled; });
118 return 0;
119 }
120 else
121 {
122 cpprest_synchronization::chrono::milliseconds period(timeout);
123 auto status = _condition.wait_for(lock, period, [this]() -> bool { return _signaled; });
124 _ASSERTE(status == _signaled);
125 // Return 0 if the wait completed as a result of signaling the event. Otherwise, return timeout_infinite
126 // Note: this must be consistent with the behavior of the Windows version, which is based on WaitForSingleObjectEx
127 return status ? 0: event_impl::timeout_infinite;
128 }
129 }
130
131 unsigned int wait()
132 {
133 return wait(event_impl::timeout_infinite);
134 }
135 };
136
141 {
142 private:
143
144 pthread_rwlock_t _M_reader_writer_lock;
145
146 public:
147
149 {
150 public:
152 {
153 _M_reader_writer_lock.lock_read();
154 }
155
157 {
158 _M_reader_writer_lock.unlock();
159 }
160
161 private:
165 };
166
168 {
169 pthread_rwlock_init(&_M_reader_writer_lock, nullptr);
170 }
171
173 {
174 pthread_rwlock_destroy(&_M_reader_writer_lock);
175 }
176
177 void lock()
178 {
179 pthread_rwlock_wrlock(&_M_reader_writer_lock);
180 }
181
182 void lock_read()
183 {
184 pthread_rwlock_rdlock(&_M_reader_writer_lock);
185 }
186
187 void unlock()
188 {
189 pthread_rwlock_unlock(&_M_reader_writer_lock);
190 }
191 };
192
197 {
198 public:
199
201 : _M_owner(-1), _M_recursionCount(0)
202 {
203 }
204
206 {
207 _ASSERTE(_M_owner == -1);
208 _ASSERTE(_M_recursionCount == 0);
209 }
210
211 void lock()
212 {
213 auto id = ::pplx::details::platform::GetCurrentThreadId();
214
215 if ( _M_owner == id )
216 {
217 _M_recursionCount++;
218 }
219 else
220 {
221 _M_cs.lock();
222 _M_owner = id;
223 _M_recursionCount = 1;
224 }
225 }
226
227 void unlock()
228 {
229 _ASSERTE(_M_owner == ::pplx::details::platform::GetCurrentThreadId());
230 _ASSERTE(_M_recursionCount >= 1);
231
232 _M_recursionCount--;
233
234 if ( _M_recursionCount == 0 )
235 {
236 _M_owner = -1;
237 _M_cs.unlock();
238 }
239 }
240
241 private:
242 cpprest_synchronization::mutex _M_cs;
243 volatile long _M_owner;
244 long _M_recursionCount;
245 };
246
247 #if defined(__APPLE__)
248 class apple_scheduler : public pplx::scheduler_interface
249 #else
251 #endif
252 {
253 public:
254 _PPLXIMP
virtual void schedule(
TaskProc_t proc, _In_
void* param);
255 };
256
257 } // namespace details
258
263 template<class _Lock>
265 {
266 public:
267 explicit scoped_lock(_Lock& _Critical_section) : _M_critical_section(_Critical_section)
268 {
269 _M_critical_section.lock();
270 }
271
273 {
274 _M_critical_section.unlock();
275 }
276
277 private:
278 _Lock& _M_critical_section;
279
282 };
283
284 // The extensibility namespace contains the type definitions that are used internally
285 namespace extensibility
286 {
287 typedef ::pplx::details::event_impl event_t;
288
289 typedef cpprest_synchronization::mutex critical_section_t;
291
292 typedef ::pplx::details::reader_writer_lock_impl reader_writer_lock_t;
294 typedef ::pplx::extensibility::reader_writer_lock_t::scoped_lock_read scoped_read_lock_t;
295
296 typedef ::pplx::details::recursive_lock_impl recursive_lock_t;
298 }
299
303 #if defined(__APPLE__)
305 #else
307 #endif
308
309 namespace details
310 {
314 #ifndef _REPORT_PPLTASK_UNOBSERVED_EXCEPTION
315 #define _REPORT_PPLTASK_UNOBSERVED_EXCEPTION() do { \
316 raise(SIGTRAP); \
317 std::terminate(); \
318 } while(false)
319 #endif //_REPORT_PPLTASK_UNOBSERVED_EXCEPTION
320 }
321
322 //see: http://gcc.gnu.org/onlinedocs/gcc/Return-Address.html
323 // this is critical to inline
324 __attribute__ ((always_inline))
325 inline void* _ReturnAddress() { return __builtin_return_address(0); }
326
327 } // namespace pplx
328
329 #endif // !_WIN32
void(_pplx_cdecl * TaskProc_t)(void *)
An elementary abstraction for a task, defined as void (__cdecl * TaskProc_t)(void *)...
Definition: pplxinterface.h:59
A generic RAII wrapper for locks that implements the critical_section interface cpprest_synchronizati...
Definition: pplxlinux.h:264
Definition: pplxlinux.h:250
The pplx namespace provides classes and functions that give you access to the Concurrency Runtime...
Definition: pplx.h:81
struct __declspec(novtable) scheduler_interface
Scheduler Interface
Definition: pplxinterface.h:64
Definition: pplxlinux.h:148
Recursive mutex
Definition: pplxlinux.h:196
Manual reset event
Definition: pplxlinux.h:84
Reader writer lock
Definition: pplxlinux.h:140
details::linux_scheduler default_scheduler_t
Default scheduler type
Definition: pplxlinux.h:306