spectrum2/3rdparty/cpprestsdk/include/pplx/pplxlinux.h
2015-11-19 15:19:14 +01:00

329 lines
8.7 KiB
C++

/***
* ==++==
*
* 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 <signal.h>
#include "pthread.h"
#include "cpprest/details/cpprest_compat.h"
#if defined(__APPLE__)
#include <dispatch/dispatch.h>
#include <boost/thread/mutex.hpp>
#include <boost/thread/condition_variable.hpp>
#else
#include <mutex>
#include <condition_variable>
#endif
#include "pplx/pplxinterface.h"
namespace pplx
{
#if defined(__APPLE__)
namespace cpprest_synchronization = ::boost;
#else
namespace cpprest_synchronization = ::std;
#endif
namespace details
{
namespace platform
{
/// <summary>
/// Returns a unique identifier for the execution thread where this routine in invoked
/// </summary>
_PPLXIMP long _pplx_cdecl GetCurrentThreadId();
/// <summary>
/// Yields the execution of the current execution thread - typically when spin-waiting
/// </summary>
_PPLXIMP void _pplx_cdecl YieldExecution();
/// <summary>
/// Caputeres the callstack
/// </summary>
__declspec(noinline) inline static size_t CaptureCallstack(void **, size_t, size_t)
{
return 0;
}
}
/// <summary>
/// Manual reset event
/// </summary>
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<cpprest_synchronization::mutex> lock(_lock);
_signaled = true;
_condition.notify_all();
}
void reset()
{
cpprest_synchronization::lock_guard<cpprest_synchronization::mutex> lock(_lock);
_signaled = false;
}
unsigned int wait(unsigned int timeout)
{
cpprest_synchronization::unique_lock<cpprest_synchronization::mutex> 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);
}
};
/// <summary>
/// Reader writer lock
/// </summary>
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);
}
};
/// <summary>
/// Recursive mutex
/// </summary>
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
/// <summary>
/// A generic RAII wrapper for locks that implements the critical_section interface
/// cpprest_synchronization::lock_guard
/// </summary>
template<class _Lock>
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<critical_section_t> scoped_critical_section_t;
typedef ::pplx::details::reader_writer_lock_impl reader_writer_lock_t;
typedef scoped_lock<reader_writer_lock_t> 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<recursive_lock_t> scoped_recursive_lock_t;
}
/// <summary>
/// Default scheduler type
/// </summary>
#if defined(__APPLE__)
typedef details::apple_scheduler default_scheduler_t;
#else
typedef details::linux_scheduler default_scheduler_t;
#endif
namespace details
{
/// <summary>
/// Terminate the process due to unhandled exception
/// </summary>
#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