/*** * ==++== * * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * ==--== * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ * * Linux specific pplx implementations * * For the latest on this and related APIs, please see http://casablanca.codeplex.com. * * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- ****/ #pragma once #if (defined(_MSC_VER)) #error This file must not be included for Visual Studio #endif #ifndef _WIN32 #include #include "pthread.h" #include "cpprest/details/cpprest_compat.h" #if defined(__APPLE__) #include #include #include #else #include #include #endif #include "pplx/pplxinterface.h" namespace pplx { #if defined(__APPLE__) namespace cpprest_synchronization = ::boost; #else namespace cpprest_synchronization = ::std; #endif namespace details { namespace platform { /// /// Returns a unique identifier for the execution thread where this routine in invoked /// _PPLXIMP long _pplx_cdecl GetCurrentThreadId(); /// /// Yields the execution of the current execution thread - typically when spin-waiting /// _PPLXIMP void _pplx_cdecl YieldExecution(); /// /// Caputeres the callstack /// __declspec(noinline) inline static size_t CaptureCallstack(void **, size_t, size_t) { return 0; } } /// /// Manual reset event /// class event_impl { private: cpprest_synchronization::mutex _lock; cpprest_synchronization::condition_variable _condition; bool _signaled; public: static const unsigned int timeout_infinite = 0xFFFFFFFF; event_impl() : _signaled(false) { } void set() { cpprest_synchronization::lock_guard lock(_lock); _signaled = true; _condition.notify_all(); } void reset() { cpprest_synchronization::lock_guard lock(_lock); _signaled = false; } unsigned int wait(unsigned int timeout) { cpprest_synchronization::unique_lock lock(_lock); if (timeout == event_impl::timeout_infinite) { _condition.wait(lock, [this]() -> bool { return _signaled; }); return 0; } else { cpprest_synchronization::chrono::milliseconds period(timeout); auto status = _condition.wait_for(lock, period, [this]() -> bool { return _signaled; }); _ASSERTE(status == _signaled); // Return 0 if the wait completed as a result of signaling the event. Otherwise, return timeout_infinite // Note: this must be consistent with the behavior of the Windows version, which is based on WaitForSingleObjectEx return status ? 0: event_impl::timeout_infinite; } } unsigned int wait() { return wait(event_impl::timeout_infinite); } }; /// /// Reader writer lock /// class reader_writer_lock_impl { private: pthread_rwlock_t _M_reader_writer_lock; public: class scoped_lock_read { public: explicit scoped_lock_read(reader_writer_lock_impl &_Reader_writer_lock) : _M_reader_writer_lock(_Reader_writer_lock) { _M_reader_writer_lock.lock_read(); } ~scoped_lock_read() { _M_reader_writer_lock.unlock(); } private: reader_writer_lock_impl& _M_reader_writer_lock; scoped_lock_read(const scoped_lock_read&); // no copy constructor scoped_lock_read const & operator=(const scoped_lock_read&); // no assignment operator }; reader_writer_lock_impl() { pthread_rwlock_init(&_M_reader_writer_lock, nullptr); } ~reader_writer_lock_impl() { pthread_rwlock_destroy(&_M_reader_writer_lock); } void lock() { pthread_rwlock_wrlock(&_M_reader_writer_lock); } void lock_read() { pthread_rwlock_rdlock(&_M_reader_writer_lock); } void unlock() { pthread_rwlock_unlock(&_M_reader_writer_lock); } }; /// /// Recursive mutex /// class recursive_lock_impl { public: recursive_lock_impl() : _M_owner(-1), _M_recursionCount(0) { } ~recursive_lock_impl() { _ASSERTE(_M_owner == -1); _ASSERTE(_M_recursionCount == 0); } void lock() { auto id = ::pplx::details::platform::GetCurrentThreadId(); if ( _M_owner == id ) { _M_recursionCount++; } else { _M_cs.lock(); _M_owner = id; _M_recursionCount = 1; } } void unlock() { _ASSERTE(_M_owner == ::pplx::details::platform::GetCurrentThreadId()); _ASSERTE(_M_recursionCount >= 1); _M_recursionCount--; if ( _M_recursionCount == 0 ) { _M_owner = -1; _M_cs.unlock(); } } private: cpprest_synchronization::mutex _M_cs; volatile long _M_owner; long _M_recursionCount; }; #if defined(__APPLE__) class apple_scheduler : public pplx::scheduler_interface #else class linux_scheduler : public pplx::scheduler_interface #endif { public: _PPLXIMP virtual void schedule( TaskProc_t proc, _In_ void* param); }; } // namespace details /// /// A generic RAII wrapper for locks that implements the critical_section interface /// cpprest_synchronization::lock_guard /// template class scoped_lock { public: explicit scoped_lock(_Lock& _Critical_section) : _M_critical_section(_Critical_section) { _M_critical_section.lock(); } ~scoped_lock() { _M_critical_section.unlock(); } private: _Lock& _M_critical_section; scoped_lock(const scoped_lock&); // no copy constructor scoped_lock const & operator=(const scoped_lock&); // no assignment operator }; // The extensibility namespace contains the type definitions that are used internally namespace extensibility { typedef ::pplx::details::event_impl event_t; typedef cpprest_synchronization::mutex critical_section_t; typedef scoped_lock scoped_critical_section_t; typedef ::pplx::details::reader_writer_lock_impl reader_writer_lock_t; typedef scoped_lock scoped_rw_lock_t; typedef ::pplx::extensibility::reader_writer_lock_t::scoped_lock_read scoped_read_lock_t; typedef ::pplx::details::recursive_lock_impl recursive_lock_t; typedef scoped_lock scoped_recursive_lock_t; } /// /// Default scheduler type /// #if defined(__APPLE__) typedef details::apple_scheduler default_scheduler_t; #else typedef details::linux_scheduler default_scheduler_t; #endif namespace details { /// /// Terminate the process due to unhandled exception /// #ifndef _REPORT_PPLTASK_UNOBSERVED_EXCEPTION #define _REPORT_PPLTASK_UNOBSERVED_EXCEPTION() do { \ raise(SIGTRAP); \ std::terminate(); \ } while(false) #endif //_REPORT_PPLTASK_UNOBSERVED_EXCEPTION } //see: http://gcc.gnu.org/onlinedocs/gcc/Return-Address.html // this is critical to inline __attribute__ ((always_inline)) inline void* _ReturnAddress() { return __builtin_return_address(0); } } // namespace pplx #endif // !_WIN32