/***
* Copyright (C) Microsoft. All rights reserved.
* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
*
* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
*
* Windows specific pplx implementations
*
* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk
*
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
****/
#pragma once
#if !defined(_WIN32) || _MSC_VER < 1800 || CPPREST_FORCE_PPLX
#include "cpprest/details/cpprest_compat.h"
#include "pplx/pplxinterface.h"
namespace pplx
{
namespace details
{
namespace platform
{
///
/// Returns a unique identifier for the execution thread where this routine in invoked
///
_PPLXIMP long __cdecl GetCurrentThreadId();
///
/// Yields the execution of the current execution thread - typically when spin-waiting
///
_PPLXIMP void __cdecl YieldExecution();
///
/// Captures the callstack
///
__declspec(noinline) _PPLXIMP size_t __cdecl CaptureCallstack(void**, size_t, size_t);
#if defined(__cplusplus_winrt)
///
// Internal API which retrieves the next async id.
///
_PPLXIMP unsigned int __cdecl GetNextAsyncId();
#endif
} // namespace platform
///
/// Manual reset event
///
class event_impl
{
public:
static const unsigned int timeout_infinite = 0xFFFFFFFF;
_PPLXIMP event_impl();
_PPLXIMP ~event_impl();
_PPLXIMP void set();
_PPLXIMP void reset();
_PPLXIMP unsigned int wait(unsigned int timeout);
unsigned int wait() { return wait(event_impl::timeout_infinite); }
private:
// Windows events
void* _M_impl;
event_impl(const event_impl&); // no copy constructor
event_impl const& operator=(const event_impl&); // no assignment operator
};
///
/// Mutex - lock for mutual exclusion
///
class critical_section_impl
{
public:
_PPLXIMP critical_section_impl();
_PPLXIMP ~critical_section_impl();
_PPLXIMP void lock();
_PPLXIMP void unlock();
private:
typedef void* _PPLX_BUFFER;
// Windows critical section
_PPLX_BUFFER _M_impl[8];
critical_section_impl(const critical_section_impl&); // no copy constructor
critical_section_impl const& operator=(const critical_section_impl&); // no assignment operator
};
#if _WIN32_WINNT >= _WIN32_WINNT_VISTA
///
/// Reader writer lock
///
class reader_writer_lock_impl
{
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
};
_PPLXIMP reader_writer_lock_impl();
_PPLXIMP void lock();
_PPLXIMP void lock_read();
_PPLXIMP void unlock();
private:
// Windows slim reader writer lock
void* _M_impl;
// Slim reader writer lock doesn't have a general 'unlock' method.
// We need to track how it was acquired and release accordingly.
// true - lock exclusive
// false - lock shared
bool m_locked_exclusive;
};
#endif // _WIN32_WINNT >= _WIN32_WINNT_VISTA
///
/// 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:
pplx::details::critical_section_impl _M_cs;
long _M_recursionCount;
volatile long _M_owner;
};
class windows_scheduler : public pplx::scheduler_interface
{
public:
_PPLXIMP virtual void schedule(TaskProc_t proc, _In_ void* param);
};
} // namespace details
///
/// A generic RAII wrapper for locks that implement the critical_section interface
/// std::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 ::pplx::details::critical_section_impl critical_section_t;
typedef scoped_lock scoped_critical_section_t;
#if _WIN32_WINNT >= _WIN32_WINNT_VISTA
typedef ::pplx::details::reader_writer_lock_impl reader_writer_lock_t;
typedef scoped_lock scoped_rw_lock_t;
typedef reader_writer_lock_t::scoped_lock_read scoped_read_lock_t;
#endif // _WIN32_WINNT >= _WIN32_WINNT_VISTA
typedef ::pplx::details::recursive_lock_impl recursive_lock_t;
typedef scoped_lock scoped_recursive_lock_t;
} // namespace extensibility
///
/// Default scheduler type
///
typedef details::windows_scheduler default_scheduler_t;
namespace details
{
///
/// Terminate the process due to unhandled exception
///
#ifndef _REPORT_PPLTASK_UNOBSERVED_EXCEPTION
#define _REPORT_PPLTASK_UNOBSERVED_EXCEPTION() \
do \
{ \
__debugbreak(); \
std::terminate(); \
} while (false)
#endif // _REPORT_PPLTASK_UNOBSERVED_EXCEPTION
} // namespace details
} // namespace pplx
#endif