Commit 8a65bcce by Amir Aharon

1.6.1 changes

parent 4b07616a
Showing with 3662 additions and 545 deletions
/***
* Copyright (C) Microsoft. All rights reserved.
* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
*
* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
*
* Standard macros and definitions.
* This header has minimal dependency on windows headers and is safe for use in the public API
*
* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk
*
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
****/
#pragma once
#if defined(_WIN32) // Settings specific to Windows
#if _MSC_VER >= 1900
#define CPPREST_NOEXCEPT noexcept
#else
#define CPPREST_NOEXCEPT
#endif
#define CASABLANCA_UNREFERENCED_PARAMETER(x) (x)
#include <sal.h>
#else // End settings specific to Windows
// Settings common to all but Windows
#define __declspec(x) __attribute__ ((x))
#define dllimport
#define novtable /* no novtable equivalent */
#define __assume(x) do { if (!(x)) __builtin_unreachable(); } while (false)
#define CASABLANCA_UNREFERENCED_PARAMETER(x) (void)x
#define CPPREST_NOEXCEPT noexcept
#include <assert.h>
#define _ASSERTE(x) assert(x)
#ifdef _In_
#undef _In_
#endif
#define _In_
#ifdef _Inout_
#undef _Inout_
#endif
#define _Inout_
#ifdef _Out_
#undef _Out_
#endif
#define _Out_
#ifdef _In_z_
#undef _In_z_
#endif
#define _In_z_
#ifdef _Out_z_
#undef _Out_z_
#endif
#define _Out_z_
#ifdef _Inout_z_
#undef _Inout_z_
#endif
#define _Inout_z_
#ifdef _In_opt_
#undef _In_opt_
#endif
#define _In_opt_
#ifdef _Out_opt_
#undef _Out_opt_
#endif
#define _Out_opt_
#ifdef _Inout_opt_
#undef _Inout_opt_
#endif
#define _Inout_opt_
#ifdef _Out_writes_
#undef _Out_writes_
#endif
#define _Out_writes_(x)
#ifdef _Out_writes_opt_
#undef _Out_writes_opt_
#endif
#define _Out_writes_opt_(x)
#ifdef _In_reads_
#undef _In_reads_
#endif
#define _In_reads_(x)
#ifdef _Inout_updates_bytes_
#undef _Inout_updates_bytes_
#endif
#define _Inout_updates_bytes_(x)
#if not defined __cdecl
#if defined cdecl
#define __cdecl __attribute__ ((cdecl))
#else
#define __cdecl
#endif
#if defined(__ANDROID__)
// This is needed to disable the use of __thread inside the boost library.
// Android does not support thread local storage -- if boost is included
// without this macro defined, it will create references to __tls_get_addr
// which (while able to link) will not be available at runtime and prevent
// the .so from loading.
#define BOOST_ASIO_DISABLE_THREAD_KEYWORD_EXTENSION
#endif
#ifdef __clang__
#include <cstdio>
#endif
#endif // defined(__APPLE__)
#endif
#ifdef _NO_ASYNCRTIMP
#define _ASYNCRTIMP
#else
#ifdef _ASYNCRT_EXPORT
#define _ASYNCRTIMP __declspec(dllexport)
#else
#define _ASYNCRTIMP __declspec(dllimport)
#endif
#endif
#ifdef CASABLANCA_DEPRECATION_NO_WARNINGS
#define CASABLANCA_DEPRECATED(x)
#else
#define CASABLANCA_DEPRECATED(x) __declspec(deprecated(x))
#endif
/***
* Copyright (C) Microsoft. All rights reserved.
* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
*
* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
*
* Parallel Patterns Library
*
* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk
*
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
****/
#pragma once
#ifndef _PPLX_H
#define _PPLX_H
#if (defined(_MSC_VER) && (_MSC_VER >= 1800)) && !CPPREST_FORCE_PPLX
#error This file must not be included for Visual Studio 12 or later
#endif
#ifndef _WIN32
#if defined(_WIN32) || defined(__cplusplus_winrt)
#define _WIN32
#endif
#endif // _WIN32
#ifdef _NO_PPLXIMP
#define _PPLXIMP
#else
#ifdef _PPLX_EXPORT
#define _PPLXIMP __declspec(dllexport)
#else
#define _PPLXIMP __declspec(dllimport)
#endif
#endif
#include "compat.h"
// Use PPLx
#ifdef _WIN32
#include "pplxwin.h"
#elif defined(__APPLE__)
#undef _PPLXIMP
#define _PPLXIMP
#include "pplxlinux.h"
#else
#include "pplxlinux.h"
#endif // _WIN32
// Common implementation across all the non-concrt versions
#include "pplxcancellation_token.h"
#include <functional>
// conditional expression is constant
#if defined(_MSC_VER)
#pragma warning(push)
#pragma warning(disable: 4127)
#endif
#pragma pack(push,_CRT_PACKING)
/// <summary>
/// The <c>pplx</c> namespace provides classes and functions that give you access to the Concurrency Runtime,
/// a concurrent programming framework for C++. For more information, see <see cref="Concurrency Runtime"/>.
/// </summary>
/**/
namespace pplx
{
/// <summary>
/// Sets the ambient scheduler to be used by the PPL constructs.
/// </summary>
_PPLXIMP void _pplx_cdecl set_ambient_scheduler(std::shared_ptr<pplx::scheduler_interface> _Scheduler);
/// <summary>
/// Gets the ambient scheduler to be used by the PPL constructs
/// </summary>
_PPLXIMP std::shared_ptr<pplx::scheduler_interface> _pplx_cdecl get_ambient_scheduler();
namespace details
{
//
// An internal exception that is used for cancellation. Users do not "see" this exception except through the
// resulting stack unwind. This exception should never be intercepted by user code. It is intended
// for use by the runtime only.
//
class _Interruption_exception : public std::exception
{
public:
_Interruption_exception(){}
};
template<typename _T>
struct _AutoDeleter
{
_AutoDeleter(_T *_PPtr) : _Ptr(_PPtr) {}
~_AutoDeleter () { delete _Ptr; }
_T *_Ptr;
};
struct _TaskProcHandle
{
_TaskProcHandle()
{
}
virtual ~_TaskProcHandle() {}
virtual void invoke() const = 0;
static void _pplx_cdecl _RunChoreBridge(void * _Parameter)
{
auto _PTaskHandle = static_cast<_TaskProcHandle *>(_Parameter);
_AutoDeleter<_TaskProcHandle> _AutoDeleter(_PTaskHandle);
_PTaskHandle->invoke();
}
};
enum _TaskInliningMode
{
// Disable inline scheduling
_NoInline = 0,
// Let runtime decide whether to do inline scheduling or not
_DefaultAutoInline = 16,
// Always do inline scheduling
_ForceInline = -1,
};
// This is an abstraction that is built on top of the scheduler to provide these additional functionalities
// - Ability to wait on a work item
// - Ability to cancel a work item
// - Ability to inline work on invocation of RunAndWait
class _TaskCollectionImpl
{
public:
typedef _TaskProcHandle _TaskProcHandle_t;
_TaskCollectionImpl(scheduler_ptr _PScheduler)
: _M_pScheduler(_PScheduler)
{
}
void _ScheduleTask(_TaskProcHandle_t* _PTaskHandle, _TaskInliningMode _InliningMode)
{
if (_InliningMode == _ForceInline)
{
_TaskProcHandle_t::_RunChoreBridge(_PTaskHandle);
}
else
{
_M_pScheduler->schedule(_TaskProcHandle_t::_RunChoreBridge, _PTaskHandle);
}
}
void _Cancel()
{
// No cancellation support
}
void _RunAndWait()
{
// No inlining support yet
_Wait();
}
void _Wait()
{
_M_Completed.wait();
}
void _Complete()
{
_M_Completed.set();
}
scheduler_ptr _GetScheduler() const
{
return _M_pScheduler;
}
// Fire and forget
static void _RunTask(TaskProc_t _Proc, void * _Parameter, _TaskInliningMode _InliningMode)
{
if (_InliningMode == _ForceInline)
{
_Proc(_Parameter);
}
else
{
// Schedule the work on the ambient scheduler
get_ambient_scheduler()->schedule(_Proc, _Parameter);
}
}
static bool _pplx_cdecl _Is_cancellation_requested()
{
// We do not yet have the ability to determine the current task. So return false always
return false;
}
private:
extensibility::event_t _M_Completed;
scheduler_ptr _M_pScheduler;
};
// For create_async lambdas that return a (non-task) result, we oversubscriber the current task for the duration of the
// lambda.
struct _Task_generator_oversubscriber {};
typedef _TaskCollectionImpl _TaskCollection_t;
typedef _TaskInliningMode _TaskInliningMode_t;
typedef _Task_generator_oversubscriber _Task_generator_oversubscriber_t;
} // namespace details
} // namespace pplx
#pragma pack(pop)
#if defined(_MSC_VER)
#pragma warning(pop)
#endif
#endif // _PPLX_H
/***
* Copyright (C) Microsoft. All rights reserved.
* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
*
* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
*
* PPL interfaces
*
* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk
*
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
****/
#pragma once
#ifndef _PPLXINTERFACE_H
#define _PPLXINTERFACE_H
#if (defined(_MSC_VER) && (_MSC_VER >= 1800)) && !CPPREST_FORCE_PPLX
#error This file must not be included for Visual Studio 12 or later
#endif
#if defined(_CRTBLD)
#elif defined(_WIN32)
#if (_MSC_VER >= 1700)
#define _USE_REAL_ATOMICS
#endif
#else // GCC compiler
#define _USE_REAL_ATOMICS
#endif
#include <memory>
#ifdef _USE_REAL_ATOMICS
#include <atomic>
#endif
#define _pplx_cdecl __cdecl
namespace pplx
{
/// <summary>
/// An elementary abstraction for a task, defined as <c>void (__cdecl * TaskProc_t)(void *)</c>. A <c>TaskProc</c> is called to
/// invoke the body of a task.
/// </summary>
/**/
typedef void (_pplx_cdecl * TaskProc_t)(void *);
/// <summary>
/// Scheduler Interface
/// </summary>
struct __declspec(novtable) scheduler_interface
{
virtual void schedule( TaskProc_t, _In_ void* ) = 0;
};
/// <summary>
/// Represents a pointer to a scheduler. This class exists to allow the
/// the specification of a shared lifetime by using shared_ptr or just
/// a plain reference by using raw pointer.
/// </summary>
struct scheduler_ptr
{
/// <summary>
/// Creates a scheduler pointer from shared_ptr to scheduler
/// </summary>
explicit scheduler_ptr(std::shared_ptr<scheduler_interface> scheduler) : m_sharedScheduler(std::move(scheduler))
{
m_scheduler = m_sharedScheduler.get();
}
/// <summary>
/// Creates a scheduler pointer from raw pointer to scheduler
/// </summary>
explicit scheduler_ptr(_In_opt_ scheduler_interface * pScheduler) : m_scheduler(pScheduler)
{
}
/// <summary>
/// Behave like a pointer
/// </summary>
scheduler_interface *operator->() const
{
return get();
}
/// <summary>
/// Returns the raw pointer to the scheduler
/// </summary>
scheduler_interface * get() const
{
return m_scheduler;
}
/// <summary>
/// Test whether the scheduler pointer is non-null
/// </summary>
operator bool() const { return get() != nullptr; }
private:
std::shared_ptr<scheduler_interface> m_sharedScheduler;
scheduler_interface * m_scheduler;
};
/// <summary>
/// Describes the execution status of a <c>task_group</c> or <c>structured_task_group</c> object. A value of this type is returned
/// by numerous methods that wait on tasks scheduled to a task group to complete.
/// </summary>
/// <seealso cref="task_group Class"/>
/// <seealso cref="task_group::wait Method"/>
/// <seealso cref="task_group::run_and_wait Method"/>
/// <seealso cref="structured_task_group Class"/>
/// <seealso cref="structured_task_group::wait Method"/>
/// <seealso cref="structured_task_group::run_and_wait Method"/>
/**/
enum task_group_status
{
/// <summary>
/// The tasks queued to the <c>task_group</c> object have not completed. Note that this value is not presently returned by
/// the Concurrency Runtime.
/// </summary>
/**/
not_complete,
/// <summary>
/// The tasks queued to the <c>task_group</c> or <c>structured_task_group</c> object completed successfully.
/// </summary>
/**/
completed,
/// <summary>
/// The <c>task_group</c> or <c>structured_task_group</c> object was canceled. One or more tasks may not have executed.
/// </summary>
/**/
canceled
};
namespace details
{
/// <summary>
/// Atomics
/// </summary>
#ifdef _USE_REAL_ATOMICS
typedef std::atomic<long> atomic_long;
typedef std::atomic<size_t> atomic_size_t;
template<typename _T>
_T atomic_compare_exchange(std::atomic<_T>& _Target, _T _Exchange, _T _Comparand)
{
_T _Result = _Comparand;
_Target.compare_exchange_strong(_Result, _Exchange);
return _Result;
}
template<typename _T>
_T atomic_exchange(std::atomic<_T>& _Target, _T _Value)
{
return _Target.exchange(_Value);
}
template<typename _T>
_T atomic_increment(std::atomic<_T>& _Target)
{
return _Target.fetch_add(1) + 1;
}
template<typename _T>
_T atomic_decrement(std::atomic<_T>& _Target)
{
return _Target.fetch_sub(1) - 1;
}
template<typename _T>
_T atomic_add(std::atomic<_T>& _Target, _T value)
{
return _Target.fetch_add(value) + value;
}
#else // not _USE_REAL_ATOMICS
typedef long volatile atomic_long;
typedef size_t volatile atomic_size_t;
template<class T>
inline T atomic_exchange(T volatile& _Target, T _Value)
{
return _InterlockedExchange(&_Target, _Value);
}
inline long atomic_increment(long volatile & _Target)
{
return _InterlockedIncrement(&_Target);
}
inline long atomic_add(long volatile & _Target, long value)
{
return _InterlockedExchangeAdd(&_Target, value) + value;
}
inline size_t atomic_increment(size_t volatile & _Target)
{
#if (defined(_M_IX86) || defined(_M_ARM))
return static_cast<size_t>(_InterlockedIncrement(reinterpret_cast<long volatile *>(&_Target)));
#else
return static_cast<size_t>(_InterlockedIncrement64(reinterpret_cast<__int64 volatile *>(&_Target)));
#endif
}
inline long atomic_decrement(long volatile & _Target)
{
return _InterlockedDecrement(&_Target);
}
inline size_t atomic_decrement(size_t volatile & _Target)
{
#if (defined(_M_IX86) || defined(_M_ARM))
return static_cast<size_t>(_InterlockedDecrement(reinterpret_cast<long volatile *>(&_Target)));
#else
return static_cast<size_t>(_InterlockedDecrement64(reinterpret_cast<__int64 volatile *>(&_Target)));
#endif
}
inline long atomic_compare_exchange(long volatile & _Target, long _Exchange, long _Comparand)
{
return _InterlockedCompareExchange(&_Target, _Exchange, _Comparand);
}
inline size_t atomic_compare_exchange(size_t volatile & _Target, size_t _Exchange, size_t _Comparand)
{
#if (defined(_M_IX86) || defined(_M_ARM))
return static_cast<size_t>(_InterlockedCompareExchange(reinterpret_cast<long volatile *>(_Target), static_cast<long>(_Exchange), static_cast<long>(_Comparand)));
#else
return static_cast<size_t>(_InterlockedCompareExchange64(reinterpret_cast<__int64 volatile *>(_Target), static_cast<__int64>(_Exchange), static_cast<__int64>(_Comparand)));
#endif
}
#endif // _USE_REAL_ATOMICS
}} // namespace pplx
#endif // _PPLXINTERFACE_H
/***
* Copyright (C) Microsoft. All rights reserved.
* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
*
* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
*
* Linux specific pplx implementations
*
* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk
*
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
****/
#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 "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 "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
This diff could not be displayed because it is too large.
/***
* 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 "compat.h"
#include "pplxinterface.h"
namespace pplx
{
namespace details
{
namespace platform
{
/// <summary>
/// Returns a unique identifier for the execution thread where this routine in invoked
/// </summary>
_PPLXIMP long __cdecl GetCurrentThreadId();
/// <summary>
/// Yields the execution of the current execution thread - typically when spin-waiting
/// </summary>
_PPLXIMP void __cdecl YieldExecution();
/// <summary>
/// Captures the callstack
/// </summary>
__declspec(noinline) _PPLXIMP size_t __cdecl CaptureCallstack(void **, size_t, size_t);
#if defined(__cplusplus_winrt)
/// <summary>
// Internal API which retrieves the next async id.
/// </summary>
_PPLXIMP unsigned int __cdecl GetNextAsyncId();
#endif
}
/// <summary>
/// Manual reset event
/// </summary>
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
};
/// <summary>
/// Mutex - lock for mutual exclusion
/// </summary>
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
/// <summary>
/// Reader writer lock
/// </summary>
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
/// <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 recursive_lock_impl::lock()
{
auto id = ::pplx::details::platform::GetCurrentThreadId();
if ( _M_owner == id )
{
_M_recursionCount++;
}
else
{
_M_cs.lock();
_M_owner = id;
_M_recursionCount = 1;
}
}
void recursive_lock_impl::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
/// <summary>
/// A generic RAII wrapper for locks that implement the critical_section interface
/// std::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 ::pplx::details::critical_section_impl critical_section_t;
typedef scoped_lock<critical_section_t> scoped_critical_section_t;
#if _WIN32_WINNT >= _WIN32_WINNT_VISTA
typedef ::pplx::details::reader_writer_lock_impl reader_writer_lock_t;
typedef scoped_lock<reader_writer_lock_t> 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<recursive_lock_t> scoped_recursive_lock_t;
}
/// <summary>
/// Default scheduler type
/// </summary>
typedef details::windows_scheduler default_scheduler_t;
namespace details
{
/// <summary>
/// Terminate the process due to unhandled exception
/// </summary>
#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
\ No newline at end of file
# Ignore everything...
/*
# ...except:
!include
!src
!.gitignore
!CMakeLists.txt
!LICENSE
!README.md
cmake_minimum_required(VERSION 3.2)
include(GNUInstallDirs)
project(pplx VERSION 2.9.1 DESCRIPTION "Extraction of Microsoft PPLX out of C++ REST SDK")
# add vcpkg toochain
include(/home/vscode/vcpkg/scripts/buildsystems/vcpkg.cmake)
find_package(Boost COMPONENTS thread date_time)
# Provide an option for choosing between shared or static library builds. Build as shared by default.
option(${PROJECT_NAME}_as_shared "build as a shared library" ON)
set(BUILD_SHARED_LIBS ${${PROJECT_NAME}_as_shared})
set(CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS} -std=c++17)
add_library(${PROJECT_NAME} "")
set_target_properties(${PROJECT_NAME} PROPERTIES VERSION ${PROJECT_VERSION} POSITION_INDEPENDENT_CODE ON)
target_include_directories(${PROJECT_NAME} PRIVATE ${Boost_INCLUDE_DIRS})
target_include_directories(${PROJECT_NAME} PRIVATE include)
target_sources(${PROJECT_NAME}
PUBLIC
"${CMAKE_CURRENT_SOURCE_DIR}/include/pplx/compat.h"
"${CMAKE_CURRENT_SOURCE_DIR}/include/pplx/pplxcancellation_token.h"
"${CMAKE_CURRENT_SOURCE_DIR}/include/pplx/pplx.h"
"${CMAKE_CURRENT_SOURCE_DIR}/include/pplx/pplxinterface.h"
"${CMAKE_CURRENT_SOURCE_DIR}/include/pplx/pplxtasks.h"
PRIVATE
"${CMAKE_CURRENT_SOURCE_DIR}/src/pplx.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/src/stdafx.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/src/stdafx.h"
)
# There's a dedicated thread pool implementation for the UNIX side, while Windows provides its own.
if(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
target_sources(${PROJECT_NAME}
PUBLIC
"${CMAKE_CURRENT_SOURCE_DIR}/include/pplx/pplxlinux.h"
PRIVATE
"${CMAKE_CURRENT_SOURCE_DIR}/src/pplxlinux.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/src/threadpool.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/src/threadpool.h"
)
elseif(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
target_sources(${PROJECT_NAME}
PUBLIC
"${CMAKE_CURRENT_SOURCE_DIR}/include/pplx/pplxlinux.h"
PRIVATE
"${CMAKE_CURRENT_SOURCE_DIR}/src/pplxapple.cpp"
)
elseif(WIN32)
target_sources(${PROJECT_NAME}
PUBLIC
"${CMAKE_CURRENT_SOURCE_DIR}/include/pplx/pplxwin.h"
PRIVATE
"${CMAKE_CURRENT_SOURCE_DIR}/src/pplxwin.cpp"
)
endif(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
set(include_install_dir "include")
set(lib_install_dir "lib")
set(bin_install_dir "bin")
install(
DIRECTORY "${PROJECT_SOURCE_DIR}/include/pplx"
DESTINATION ${include_install_dir}
)
install(TARGETS ${PROJECT_NAME}
RUNTIME DESTINATION ${bin_install_dir}
LIBRARY DESTINATION ${lib_install_dir}
ARCHIVE DESTINATION ${lib_install_dir}
)
PPLX - Extraction of Microsoft PPLX out of C++ REST SDK
The MIT License (MIT)
Copyright (c) Microsoft Corporation
All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
# Extraction of Microsoft PPLX out of C++ REST SDK
## Table of Contents
**[Description](#description)**<br>
**[How](#how)**<br>
**[Build](#build)**<br>
**[Examples](#examples)**<br>
**[References](#references)**<br>
## Description
PPLX is a trimmed version of PPL ([Parallel Patterns Library](https://msdn.microsoft.com/en-us/library/dd492418.aspx), Microsoft's offering for task parallelism, parallel algorithms and containers for C++), featuring only tasks and task continuations, with plain vanilla thread pool implementation underneath. Officially PPLX comes bundled within [C++ REST SDK](https://github.com/Microsoft/cpprestsdk), a cross-platform library from Microsoft for creating REST services. If you use something else for REST, but still want to utilize PPLX for generic concurrency, you have to include C++ REST SDK in its entirety, which is weird.
This project is an extraction of PPLX out of C++ REST SDK, presenting it in a form of a shared or static library. It is of some value for *\*nix* systems, where you don't have the luxury of using the full-fledged version – PPL<sup>[[1]](#r1 "Task Parallelism in C++: Patience. Trust. And Hope.")</sup>.
## How
What was done was basically extracting the minimum code subset representing PPLX out of a specific version of C++ REST SDK (refer to [``CMakeLists.txt``](./CMakeLists.txt) for the exact version number). While I tried to avoid touching the code base as much as possible, some adjustments still slipped in. Particularly, a few preprocessor include statements went through path and file name corrections due to header file relocations. For example:
```cpp
#include "cpprest/details/cpprest_compat.h"
```
has become:
```cpp
#include "compat.h"
```
## Build
### Requirements
* GCC >= 4.8, Visual Studio >= 2015
* CMake >= 3.2
* Boost Libraries >= 1.56
### Steps
Prepare CMake environment appropriately:
```commandline
$ mkdir build
$ cd build
$ cmake ..
```
Build via ``make`` on *\*nix* side:
```commandline
$ make
$ sudo make install
```
Build via VS on *Windows*:
* Open the corresponding solution in Visual Studio, run build appropriately;
* Copy the resultant DLL into a directory within your library search path.
## Examples
The concurrency model of PPL is quite similar to the one coming from the C++ Standard Library, with a slight skew towards the notion of task<sup>[[2]](#r2 "Microsoft Concurrency Runtime: Task Parallelism")</sup>. E.g. you launch an asynchronous operation by just creating a new task object (as opposed to an [`std::async<>`](https://en.cppreference.com/w/cpp/thread/async) call), and you basically deal with task objects rather than [*futures*](https://en.cppreference.com/w/cpp/thread/future). In the following example we'll obtain the angle between two Euclidean vectors from their dot product and magnitudes calculated concurrently.
```cpp
#include <algorithm>
#include <iostream>
#include <vector>
#include <cmath>
#include <pplx/pplxtasks.h>
int calcDotProduct(const std::vector<int>& a, const std::vector<int>& b)
{
return std::inner_product(a.begin(), a.end(), b.begin(), 0);
}
double calcMagnitude(const std::vector<int>& a)
{
return std::sqrt(calcDotProduct(a, a));
}
int main()
{
// To keep things simple let's assume we deal with non-zero vectors only.
const std::vector<int> v1 { 2, -4, 7 };
const std::vector<int> v2 { 5, 1, -3 };
// Form separate tasks for calculating the dot product and magnitudes.
pplx::task<int> v1v2Dot([&v1, &v2]() {
return calcDotProduct(v1, v2);
});
pplx::task<double> v1Magnitude([&v1]() {
return calcMagnitude(v1);
});
pplx::task<double> v2Magnitude([&v2]() {
return calcMagnitude(v2);
});
std::cout << "Angle between the vectors: "
<< std::acos((double)v1v2Dot.get() / (v1Magnitude.get() * v2Magnitude.get()))
<< " radians."
<< std::endl;
return 0;
}
```
## References
1. <a name="r1">[Task Parallelism in C++: Patience. Trust. And Hope.](https://martinghazaryan.com/2018/11/18/task-parallelism-in-c-patience-trust-and-hope/)</a>
2. <a name="r2">[Microsoft Concurrency Runtime: Task Parallelism](https://msdn.microsoft.com/en-us/library/dd492427.aspx)</a>
\ No newline at end of file
/***
* Copyright (C) Microsoft. All rights reserved.
* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
*
* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
*
* Standard macros and definitions.
* This header has minimal dependency on windows headers and is safe for use in the public API
*
* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk
*
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
****/
#pragma once
#if defined(_WIN32) // Settings specific to Windows
#if _MSC_VER >= 1900
#define CPPREST_NOEXCEPT noexcept
#else
#define CPPREST_NOEXCEPT
#endif
#define CASABLANCA_UNREFERENCED_PARAMETER(x) (x)
#include <sal.h>
#else // End settings specific to Windows
// Settings common to all but Windows
#define __declspec(x) __attribute__ ((x))
#define dllimport
#define novtable /* no novtable equivalent */
#define __assume(x) do { if (!(x)) __builtin_unreachable(); } while (false)
#define CASABLANCA_UNREFERENCED_PARAMETER(x) (void)x
#define CPPREST_NOEXCEPT noexcept
#include <assert.h>
#define _ASSERTE(x) assert(x)
#ifdef _In_
#undef _In_
#endif
#define _In_
#ifdef _Inout_
#undef _Inout_
#endif
#define _Inout_
#ifdef _Out_
#undef _Out_
#endif
#define _Out_
#ifdef _In_z_
#undef _In_z_
#endif
#define _In_z_
#ifdef _Out_z_
#undef _Out_z_
#endif
#define _Out_z_
#ifdef _Inout_z_
#undef _Inout_z_
#endif
#define _Inout_z_
#ifdef _In_opt_
#undef _In_opt_
#endif
#define _In_opt_
#ifdef _Out_opt_
#undef _Out_opt_
#endif
#define _Out_opt_
#ifdef _Inout_opt_
#undef _Inout_opt_
#endif
#define _Inout_opt_
#ifdef _Out_writes_
#undef _Out_writes_
#endif
#define _Out_writes_(x)
#ifdef _Out_writes_opt_
#undef _Out_writes_opt_
#endif
#define _Out_writes_opt_(x)
#ifdef _In_reads_
#undef _In_reads_
#endif
#define _In_reads_(x)
#ifdef _Inout_updates_bytes_
#undef _Inout_updates_bytes_
#endif
#define _Inout_updates_bytes_(x)
#if not defined __cdecl
#if defined cdecl
#define __cdecl __attribute__ ((cdecl))
#else
#define __cdecl
#endif
#if defined(__ANDROID__)
// This is needed to disable the use of __thread inside the boost library.
// Android does not support thread local storage -- if boost is included
// without this macro defined, it will create references to __tls_get_addr
// which (while able to link) will not be available at runtime and prevent
// the .so from loading.
#define BOOST_ASIO_DISABLE_THREAD_KEYWORD_EXTENSION
#endif
#ifdef __clang__
#include <cstdio>
#endif
#endif // defined(__APPLE__)
#endif
#ifdef _NO_ASYNCRTIMP
#define _ASYNCRTIMP
#else
#ifdef _ASYNCRT_EXPORT
#define _ASYNCRTIMP __declspec(dllexport)
#else
#define _ASYNCRTIMP __declspec(dllimport)
#endif
#endif
#ifdef CASABLANCA_DEPRECATION_NO_WARNINGS
#define CASABLANCA_DEPRECATED(x)
#else
#define CASABLANCA_DEPRECATED(x) __declspec(deprecated(x))
#endif
/***
* Copyright (C) Microsoft. All rights reserved.
* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
*
* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
*
* Parallel Patterns Library
*
* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk
*
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
****/
#pragma once
#ifndef _PPLX_H
#define _PPLX_H
#if (defined(_MSC_VER) && (_MSC_VER >= 1800)) && !CPPREST_FORCE_PPLX
#error This file must not be included for Visual Studio 12 or later
#endif
#ifndef _WIN32
#if defined(_WIN32) || defined(__cplusplus_winrt)
#define _WIN32
#endif
#endif // _WIN32
#ifdef _NO_PPLXIMP
#define _PPLXIMP
#else
#ifdef _PPLX_EXPORT
#define _PPLXIMP __declspec(dllexport)
#else
#define _PPLXIMP __declspec(dllimport)
#endif
#endif
#include "compat.h"
// Use PPLx
#ifdef _WIN32
#include "pplxwin.h"
#elif defined(__APPLE__)
#undef _PPLXIMP
#define _PPLXIMP
#include "pplxlinux.h"
#else
#include "pplxlinux.h"
#endif // _WIN32
// Common implementation across all the non-concrt versions
#include "pplxcancellation_token.h"
#include <functional>
// conditional expression is constant
#if defined(_MSC_VER)
#pragma warning(push)
#pragma warning(disable: 4127)
#endif
#pragma pack(push,_CRT_PACKING)
/// <summary>
/// The <c>pplx</c> namespace provides classes and functions that give you access to the Concurrency Runtime,
/// a concurrent programming framework for C++. For more information, see <see cref="Concurrency Runtime"/>.
/// </summary>
/**/
namespace pplx
{
/// <summary>
/// Sets the ambient scheduler to be used by the PPL constructs.
/// </summary>
_PPLXIMP void _pplx_cdecl set_ambient_scheduler(std::shared_ptr<pplx::scheduler_interface> _Scheduler);
/// <summary>
/// Gets the ambient scheduler to be used by the PPL constructs
/// </summary>
_PPLXIMP std::shared_ptr<pplx::scheduler_interface> _pplx_cdecl get_ambient_scheduler();
namespace details
{
//
// An internal exception that is used for cancellation. Users do not "see" this exception except through the
// resulting stack unwind. This exception should never be intercepted by user code. It is intended
// for use by the runtime only.
//
class _Interruption_exception : public std::exception
{
public:
_Interruption_exception(){}
};
template<typename _T>
struct _AutoDeleter
{
_AutoDeleter(_T *_PPtr) : _Ptr(_PPtr) {}
~_AutoDeleter () { delete _Ptr; }
_T *_Ptr;
};
struct _TaskProcHandle
{
_TaskProcHandle()
{
}
virtual ~_TaskProcHandle() {}
virtual void invoke() const = 0;
static void _pplx_cdecl _RunChoreBridge(void * _Parameter)
{
auto _PTaskHandle = static_cast<_TaskProcHandle *>(_Parameter);
_AutoDeleter<_TaskProcHandle> _AutoDeleter(_PTaskHandle);
_PTaskHandle->invoke();
}
};
enum _TaskInliningMode
{
// Disable inline scheduling
_NoInline = 0,
// Let runtime decide whether to do inline scheduling or not
_DefaultAutoInline = 16,
// Always do inline scheduling
_ForceInline = -1,
};
// This is an abstraction that is built on top of the scheduler to provide these additional functionalities
// - Ability to wait on a work item
// - Ability to cancel a work item
// - Ability to inline work on invocation of RunAndWait
class _TaskCollectionImpl
{
public:
typedef _TaskProcHandle _TaskProcHandle_t;
_TaskCollectionImpl(scheduler_ptr _PScheduler)
: _M_pScheduler(_PScheduler)
{
}
void _ScheduleTask(_TaskProcHandle_t* _PTaskHandle, _TaskInliningMode _InliningMode)
{
if (_InliningMode == _ForceInline)
{
_TaskProcHandle_t::_RunChoreBridge(_PTaskHandle);
}
else
{
_M_pScheduler->schedule(_TaskProcHandle_t::_RunChoreBridge, _PTaskHandle);
}
}
void _Cancel()
{
// No cancellation support
}
void _RunAndWait()
{
// No inlining support yet
_Wait();
}
void _Wait()
{
_M_Completed.wait();
}
void _Complete()
{
_M_Completed.set();
}
scheduler_ptr _GetScheduler() const
{
return _M_pScheduler;
}
// Fire and forget
static void _RunTask(TaskProc_t _Proc, void * _Parameter, _TaskInliningMode _InliningMode)
{
if (_InliningMode == _ForceInline)
{
_Proc(_Parameter);
}
else
{
// Schedule the work on the ambient scheduler
get_ambient_scheduler()->schedule(_Proc, _Parameter);
}
}
static bool _pplx_cdecl _Is_cancellation_requested()
{
// We do not yet have the ability to determine the current task. So return false always
return false;
}
private:
extensibility::event_t _M_Completed;
scheduler_ptr _M_pScheduler;
};
// For create_async lambdas that return a (non-task) result, we oversubscriber the current task for the duration of the
// lambda.
struct _Task_generator_oversubscriber {};
typedef _TaskCollectionImpl _TaskCollection_t;
typedef _TaskInliningMode _TaskInliningMode_t;
typedef _Task_generator_oversubscriber _Task_generator_oversubscriber_t;
} // namespace details
} // namespace pplx
#pragma pack(pop)
#if defined(_MSC_VER)
#pragma warning(pop)
#endif
#endif // _PPLX_H
/***
* Copyright (C) Microsoft. All rights reserved.
* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
*
* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
*
* PPL interfaces
*
* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk
*
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
****/
#pragma once
#ifndef _PPLXINTERFACE_H
#define _PPLXINTERFACE_H
#if (defined(_MSC_VER) && (_MSC_VER >= 1800)) && !CPPREST_FORCE_PPLX
#error This file must not be included for Visual Studio 12 or later
#endif
#if defined(_CRTBLD)
#elif defined(_WIN32)
#if (_MSC_VER >= 1700)
#define _USE_REAL_ATOMICS
#endif
#else // GCC compiler
#define _USE_REAL_ATOMICS
#endif
#include <memory>
#ifdef _USE_REAL_ATOMICS
#include <atomic>
#endif
#define _pplx_cdecl __cdecl
namespace pplx
{
/// <summary>
/// An elementary abstraction for a task, defined as <c>void (__cdecl * TaskProc_t)(void *)</c>. A <c>TaskProc</c> is called to
/// invoke the body of a task.
/// </summary>
/**/
typedef void (_pplx_cdecl * TaskProc_t)(void *);
/// <summary>
/// Scheduler Interface
/// </summary>
struct __declspec(novtable) scheduler_interface
{
virtual void schedule( TaskProc_t, _In_ void* ) = 0;
};
/// <summary>
/// Represents a pointer to a scheduler. This class exists to allow the
/// the specification of a shared lifetime by using shared_ptr or just
/// a plain reference by using raw pointer.
/// </summary>
struct scheduler_ptr
{
/// <summary>
/// Creates a scheduler pointer from shared_ptr to scheduler
/// </summary>
explicit scheduler_ptr(std::shared_ptr<scheduler_interface> scheduler) : m_sharedScheduler(std::move(scheduler))
{
m_scheduler = m_sharedScheduler.get();
}
/// <summary>
/// Creates a scheduler pointer from raw pointer to scheduler
/// </summary>
explicit scheduler_ptr(_In_opt_ scheduler_interface * pScheduler) : m_scheduler(pScheduler)
{
}
/// <summary>
/// Behave like a pointer
/// </summary>
scheduler_interface *operator->() const
{
return get();
}
/// <summary>
/// Returns the raw pointer to the scheduler
/// </summary>
scheduler_interface * get() const
{
return m_scheduler;
}
/// <summary>
/// Test whether the scheduler pointer is non-null
/// </summary>
operator bool() const { return get() != nullptr; }
private:
std::shared_ptr<scheduler_interface> m_sharedScheduler;
scheduler_interface * m_scheduler;
};
/// <summary>
/// Describes the execution status of a <c>task_group</c> or <c>structured_task_group</c> object. A value of this type is returned
/// by numerous methods that wait on tasks scheduled to a task group to complete.
/// </summary>
/// <seealso cref="task_group Class"/>
/// <seealso cref="task_group::wait Method"/>
/// <seealso cref="task_group::run_and_wait Method"/>
/// <seealso cref="structured_task_group Class"/>
/// <seealso cref="structured_task_group::wait Method"/>
/// <seealso cref="structured_task_group::run_and_wait Method"/>
/**/
enum task_group_status
{
/// <summary>
/// The tasks queued to the <c>task_group</c> object have not completed. Note that this value is not presently returned by
/// the Concurrency Runtime.
/// </summary>
/**/
not_complete,
/// <summary>
/// The tasks queued to the <c>task_group</c> or <c>structured_task_group</c> object completed successfully.
/// </summary>
/**/
completed,
/// <summary>
/// The <c>task_group</c> or <c>structured_task_group</c> object was canceled. One or more tasks may not have executed.
/// </summary>
/**/
canceled
};
namespace details
{
/// <summary>
/// Atomics
/// </summary>
#ifdef _USE_REAL_ATOMICS
typedef std::atomic<long> atomic_long;
typedef std::atomic<size_t> atomic_size_t;
template<typename _T>
_T atomic_compare_exchange(std::atomic<_T>& _Target, _T _Exchange, _T _Comparand)
{
_T _Result = _Comparand;
_Target.compare_exchange_strong(_Result, _Exchange);
return _Result;
}
template<typename _T>
_T atomic_exchange(std::atomic<_T>& _Target, _T _Value)
{
return _Target.exchange(_Value);
}
template<typename _T>
_T atomic_increment(std::atomic<_T>& _Target)
{
return _Target.fetch_add(1) + 1;
}
template<typename _T>
_T atomic_decrement(std::atomic<_T>& _Target)
{
return _Target.fetch_sub(1) - 1;
}
template<typename _T>
_T atomic_add(std::atomic<_T>& _Target, _T value)
{
return _Target.fetch_add(value) + value;
}
#else // not _USE_REAL_ATOMICS
typedef long volatile atomic_long;
typedef size_t volatile atomic_size_t;
template<class T>
inline T atomic_exchange(T volatile& _Target, T _Value)
{
return _InterlockedExchange(&_Target, _Value);
}
inline long atomic_increment(long volatile & _Target)
{
return _InterlockedIncrement(&_Target);
}
inline long atomic_add(long volatile & _Target, long value)
{
return _InterlockedExchangeAdd(&_Target, value) + value;
}
inline size_t atomic_increment(size_t volatile & _Target)
{
#if (defined(_M_IX86) || defined(_M_ARM))
return static_cast<size_t>(_InterlockedIncrement(reinterpret_cast<long volatile *>(&_Target)));
#else
return static_cast<size_t>(_InterlockedIncrement64(reinterpret_cast<__int64 volatile *>(&_Target)));
#endif
}
inline long atomic_decrement(long volatile & _Target)
{
return _InterlockedDecrement(&_Target);
}
inline size_t atomic_decrement(size_t volatile & _Target)
{
#if (defined(_M_IX86) || defined(_M_ARM))
return static_cast<size_t>(_InterlockedDecrement(reinterpret_cast<long volatile *>(&_Target)));
#else
return static_cast<size_t>(_InterlockedDecrement64(reinterpret_cast<__int64 volatile *>(&_Target)));
#endif
}
inline long atomic_compare_exchange(long volatile & _Target, long _Exchange, long _Comparand)
{
return _InterlockedCompareExchange(&_Target, _Exchange, _Comparand);
}
inline size_t atomic_compare_exchange(size_t volatile & _Target, size_t _Exchange, size_t _Comparand)
{
#if (defined(_M_IX86) || defined(_M_ARM))
return static_cast<size_t>(_InterlockedCompareExchange(reinterpret_cast<long volatile *>(_Target), static_cast<long>(_Exchange), static_cast<long>(_Comparand)));
#else
return static_cast<size_t>(_InterlockedCompareExchange64(reinterpret_cast<__int64 volatile *>(_Target), static_cast<__int64>(_Exchange), static_cast<__int64>(_Comparand)));
#endif
}
#endif // _USE_REAL_ATOMICS
}} // namespace pplx
#endif // _PPLXINTERFACE_H
/***
* Copyright (C) Microsoft. All rights reserved.
* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
*
* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
*
* Linux specific pplx implementations
*
* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk
*
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
****/
#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 "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 "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
This diff could not be displayed because it is too large.
/***
* 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 "compat.h"
#include "pplxinterface.h"
namespace pplx
{
namespace details
{
namespace platform
{
/// <summary>
/// Returns a unique identifier for the execution thread where this routine in invoked
/// </summary>
_PPLXIMP long __cdecl GetCurrentThreadId();
/// <summary>
/// Yields the execution of the current execution thread - typically when spin-waiting
/// </summary>
_PPLXIMP void __cdecl YieldExecution();
/// <summary>
/// Captures the callstack
/// </summary>
__declspec(noinline) _PPLXIMP size_t __cdecl CaptureCallstack(void **, size_t, size_t);
#if defined(__cplusplus_winrt)
/// <summary>
// Internal API which retrieves the next async id.
/// </summary>
_PPLXIMP unsigned int __cdecl GetNextAsyncId();
#endif
}
/// <summary>
/// Manual reset event
/// </summary>
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
};
/// <summary>
/// Mutex - lock for mutual exclusion
/// </summary>
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
/// <summary>
/// Reader writer lock
/// </summary>
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
/// <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 recursive_lock_impl::lock()
{
auto id = ::pplx::details::platform::GetCurrentThreadId();
if ( _M_owner == id )
{
_M_recursionCount++;
}
else
{
_M_cs.lock();
_M_owner = id;
_M_recursionCount = 1;
}
}
void recursive_lock_impl::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
/// <summary>
/// A generic RAII wrapper for locks that implement the critical_section interface
/// std::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 ::pplx::details::critical_section_impl critical_section_t;
typedef scoped_lock<critical_section_t> scoped_critical_section_t;
#if _WIN32_WINNT >= _WIN32_WINNT_VISTA
typedef ::pplx::details::reader_writer_lock_impl reader_writer_lock_t;
typedef scoped_lock<reader_writer_lock_t> 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<recursive_lock_t> scoped_recursive_lock_t;
}
/// <summary>
/// Default scheduler type
/// </summary>
typedef details::windows_scheduler default_scheduler_t;
namespace details
{
/// <summary>
/// Terminate the process due to unhandled exception
/// </summary>
#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
\ No newline at end of file
/***
* Copyright (C) Microsoft. All rights reserved.
* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
*
* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
*
* Parallel Patterns Library implementation (common code across platforms)
*
* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk
*
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
****/
#include "stdafx.h"
#if !defined(_WIN32) || _MSC_VER < 1800 || CPPREST_FORCE_PPLX
#include "pplx/pplx.h"
// Disable false alarm code analyze warning
#if defined(_MSC_VER)
#pragma warning (disable : 26165 26110)
#endif
namespace pplx
{
namespace details
{
/// <summary>
/// Spin lock to allow for locks to be used in global scope
/// </summary>
class _Spin_lock
{
public:
_Spin_lock()
: _M_lock(0)
{
}
void lock()
{
if ( details::atomic_compare_exchange(_M_lock, 1l, 0l) != 0l )
{
do
{
pplx::details::platform::YieldExecution();
} while ( details::atomic_compare_exchange(_M_lock, 1l, 0l) != 0l );
}
}
void unlock()
{
// fence for release semantics
details::atomic_exchange(_M_lock, 0l);
}
private:
atomic_long _M_lock;
};
typedef ::pplx::scoped_lock<_Spin_lock> _Scoped_spin_lock;
} // namespace details
static struct _pplx_g_sched_t
{
typedef std::shared_ptr<pplx::scheduler_interface> sched_ptr;
_pplx_g_sched_t()
{
m_state = post_ctor;
}
~_pplx_g_sched_t()
{
m_state = post_dtor;
}
sched_ptr get_scheduler()
{
switch (m_state)
{
case post_ctor:
// This is the 99.9% case.
if (!m_scheduler)
{
::pplx::details::_Scoped_spin_lock lock(m_spinlock);
if (!m_scheduler)
{
m_scheduler = std::make_shared< ::pplx::default_scheduler_t>();
}
}
return m_scheduler;
default:
// This case means the global m_scheduler is not available.
// We spin off an individual scheduler instead.
return std::make_shared< ::pplx::default_scheduler_t>();
}
}
void set_scheduler(sched_ptr scheduler)
{
if (m_state == pre_ctor || m_state == post_dtor) {
throw invalid_operation("Scheduler cannot be initialized now");
}
::pplx::details::_Scoped_spin_lock lock(m_spinlock);
if (m_scheduler != nullptr)
{
throw invalid_operation("Scheduler is already initialized");
}
m_scheduler = std::move(scheduler);
}
enum
{
pre_ctor = 0,
post_ctor = 1,
post_dtor = 2
} m_state;
private:
pplx::details::_Spin_lock m_spinlock;
sched_ptr m_scheduler;
} _pplx_g_sched;
_PPLXIMP std::shared_ptr<pplx::scheduler_interface> _pplx_cdecl get_ambient_scheduler()
{
return _pplx_g_sched.get_scheduler();
}
_PPLXIMP void _pplx_cdecl set_ambient_scheduler(std::shared_ptr<pplx::scheduler_interface> _Scheduler)
{
_pplx_g_sched.set_scheduler(std::move(_Scheduler));
}
} // namespace pplx
#endif
/***
* Copyright (C) Microsoft. All rights reserved.
* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
*
* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
*
* Apple-specific pplx implementations
*
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
****/
#include <errno.h>
#include <sys/time.h>
#include <pthread.h>
#include <dispatch/dispatch.h>
#include <libkern/OSAtomic.h>
#include "stdafx.h"
#include "pplx/pplx.h"
// DEVNOTE:
// The use of mutexes is suboptimal for synchronization of task execution.
// Given that scheduler implementations should use GCD queues, there are potentially better mechanisms available to coordinate tasks (such as dispatch groups).
namespace pplx
{
namespace details {
namespace platform
{
_PPLXIMP long GetCurrentThreadId()
{
pthread_t threadId = pthread_self();
return (long)threadId;
}
void YieldExecution()
{
sleep(0);
}
} // namespace platform
void apple_scheduler::schedule( TaskProc_t proc, void* param)
{
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async_f(queue, param, proc);
}
} // namespace details
} // pplx
/***
* Copyright (C) Microsoft. All rights reserved.
* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
*
* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
*
* Parallel Patterns Library - Linux version
*
* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk
*
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
****/
#include "stdafx.h"
#include "pplx/pplx.h"
#include "threadpool.h"
#include "sys/syscall.h"
#ifdef _WIN32
#error "ERROR: This file should only be included in non-windows Build"
#endif
namespace pplx
{
namespace details {
namespace platform
{
_PPLXIMP long GetCurrentThreadId()
{
return reinterpret_cast<long>(reinterpret_cast<void*>(pthread_self()));
}
_PPLXIMP void YieldExecution()
{
boost::this_thread::yield();
}
}
_PPLXIMP void linux_scheduler::schedule(TaskProc_t proc, void* param)
{
crossplat::threadpool::shared_instance().schedule(boost::bind(proc, param));
}
} // namespace details
} // namespace pplx
/***
* 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 implementation of PPL constructs
*
* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk
*
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
****/
#include "stdafx.h"
#if !defined(_WIN32) || _MSC_VER < 1800 || CPPREST_FORCE_PPLX
#include "pplx/pplxwin.h"
// Disable false alarm code analysis warning
#pragma warning (disable : 26165 26110)
namespace pplx
{
namespace details
{
namespace platform
{
_PPLXIMP long __cdecl GetCurrentThreadId()
{
return (long)(::GetCurrentThreadId());
}
_PPLXIMP void __cdecl YieldExecution()
{
YieldProcessor();
}
_PPLXIMP size_t __cdecl CaptureCallstack(void **stackData, size_t skipFrames, size_t captureFrames)
{
(stackData);
(skipFrames);
(captureFrames);
size_t capturedFrames = 0;
// RtlCaptureSTackBackTrace is not available in MSDK, so we only call it under Desktop or _DEBUG MSDK.
// For MSDK unsupported version, we will return zero frame number.
#if !defined(__cplusplus_winrt)
capturedFrames = RtlCaptureStackBackTrace(static_cast<DWORD>(skipFrames + 1), static_cast<DWORD>(captureFrames), stackData, nullptr);
#endif
return capturedFrames;
}
#if defined(__cplusplus_winrt)
volatile long s_asyncId = 0;
_PPLXIMP unsigned int __cdecl GetNextAsyncId()
{
return static_cast<unsigned int>(_InterlockedIncrement(&s_asyncId));
}
#endif // defined(__cplusplus_winrt)
void InitializeCriticalSection(LPCRITICAL_SECTION _cs)
{
#ifndef __cplusplus_winrt
// InitializeCriticalSection can cause STATUS_NO_MEMORY see C28125
__try {
::InitializeCriticalSection(_cs);
}
__except(GetExceptionCode() == STATUS_NO_MEMORY ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH)
{
throw ::std::bad_alloc();
}
#else
InitializeCriticalSectionEx(_cs, 0, 0);
#endif // !__cplusplus_winrt
}
}
//
// Event implementation
//
_PPLXIMP event_impl::event_impl()
{
static_assert(sizeof(HANDLE) <= sizeof(_M_impl), "HANDLE version mismatch");
#ifndef __cplusplus_winrt
_M_impl = CreateEvent(NULL, true, false, NULL);
#else
_M_impl = CreateEventEx(NULL, NULL, CREATE_EVENT_MANUAL_RESET, EVENT_ALL_ACCESS);
#endif // !__cplusplus_winrt
if( _M_impl != NULL )
{
ResetEvent(static_cast<HANDLE>(_M_impl));
}
}
_PPLXIMP event_impl::~event_impl()
{
CloseHandle(static_cast<HANDLE>(_M_impl));
}
_PPLXIMP void event_impl::set()
{
SetEvent(static_cast<HANDLE>(_M_impl));
}
_PPLXIMP void event_impl::reset()
{
ResetEvent(static_cast<HANDLE>(_M_impl));
}
_PPLXIMP unsigned int event_impl::wait(unsigned int timeout)
{
DWORD waitTime = (timeout == event_impl::timeout_infinite) ? INFINITE : (DWORD)timeout;
DWORD status = WaitForSingleObjectEx(static_cast<HANDLE>(_M_impl), waitTime, 0);
_ASSERTE((status == WAIT_OBJECT_0) || (waitTime != INFINITE));
return (status == WAIT_OBJECT_0) ? 0 : event_impl::timeout_infinite;
}
//
// critical_section implementation
//
// TFS# 612702 -- this implementation is unnecessarily recursive. See bug for details.
_PPLXIMP critical_section_impl::critical_section_impl()
{
static_assert(sizeof(CRITICAL_SECTION) <= sizeof(_M_impl), "CRITICAL_SECTION version mismatch");
platform::InitializeCriticalSection(reinterpret_cast<LPCRITICAL_SECTION>(&_M_impl));
}
_PPLXIMP critical_section_impl::~critical_section_impl()
{
DeleteCriticalSection(reinterpret_cast<LPCRITICAL_SECTION>(&_M_impl));
}
_PPLXIMP void critical_section_impl::lock()
{
EnterCriticalSection(reinterpret_cast<LPCRITICAL_SECTION>(&_M_impl));
}
_PPLXIMP void critical_section_impl::unlock()
{
LeaveCriticalSection(reinterpret_cast<LPCRITICAL_SECTION>(&_M_impl));
}
#if _WIN32_WINNT >= _WIN32_WINNT_VISTA
//
// reader_writer_lock implementation
//
_PPLXIMP reader_writer_lock_impl::reader_writer_lock_impl()
: m_locked_exclusive(false)
{
static_assert(sizeof(SRWLOCK) <= sizeof(_M_impl), "SRWLOCK version mismatch");
InitializeSRWLock(reinterpret_cast<PSRWLOCK>(&_M_impl));
}
_PPLXIMP void reader_writer_lock_impl::lock()
{
AcquireSRWLockExclusive(reinterpret_cast<PSRWLOCK>(&_M_impl));
m_locked_exclusive = true;
}
_PPLXIMP void reader_writer_lock_impl::lock_read()
{
AcquireSRWLockShared(reinterpret_cast<PSRWLOCK>(&_M_impl));
}
_PPLXIMP void reader_writer_lock_impl::unlock()
{
if(m_locked_exclusive)
{
m_locked_exclusive = false;
ReleaseSRWLockExclusive(reinterpret_cast<PSRWLOCK>(&_M_impl));
}
else
{
ReleaseSRWLockShared(reinterpret_cast<PSRWLOCK>(&_M_impl));
}
}
#endif // _WIN32_WINNT >= _WIN32_WINNT_VISTA
//
// scheduler implementation
//
#if defined(__cplusplus_winrt)
_PPLXIMP void windows_scheduler::schedule( TaskProc_t proc, _In_ void* param)
{
auto workItemHandler = ref new Windows::System::Threading::WorkItemHandler([proc, param](Windows::Foundation::IAsyncAction ^ )
{
proc(param);
});
Windows::System::Threading::ThreadPool::RunAsync(workItemHandler);
}
#else
#if _WIN32_WINNT < _WIN32_WINNT_VISTA
struct _Scheduler_Param
{
TaskProc_t m_proc;
void * m_param;
_Scheduler_Param(TaskProc_t proc, _In_ void * param)
: m_proc(proc), m_param(param)
{
}
static DWORD CALLBACK DefaultWorkCallback(LPVOID lpParameter)
{
auto schedulerParam = (_Scheduler_Param *)(lpParameter);
schedulerParam->m_proc(schedulerParam->m_param);
delete schedulerParam;
return 1;
}
};
_PPLXIMP void windows_scheduler::schedule( TaskProc_t proc, _In_ void* param)
{
auto schedulerParam = new _Scheduler_Param(proc, param);
auto work = QueueUserWorkItem(_Scheduler_Param::DefaultWorkCallback, schedulerParam, WT_EXECUTELONGFUNCTION);
if (!work)
{
delete schedulerParam;
throw utility::details::create_system_error(GetLastError());
}
}
#else
struct _Scheduler_Param
{
TaskProc_t m_proc;
void * m_param;
_Scheduler_Param(TaskProc_t proc, _In_ void * param)
: m_proc(proc), m_param(param)
{
}
static void CALLBACK DefaultWorkCallback(PTP_CALLBACK_INSTANCE, PVOID pContext, PTP_WORK)
{
auto schedulerParam = (_Scheduler_Param *)(pContext);
schedulerParam->m_proc(schedulerParam->m_param);
delete schedulerParam;
}
};
_PPLXIMP void windows_scheduler::schedule( TaskProc_t proc, _In_ void* param)
{
auto schedulerParam = new _Scheduler_Param(proc, param);
auto work = CreateThreadpoolWork(_Scheduler_Param::DefaultWorkCallback, schedulerParam, NULL);
if (work == nullptr)
{
delete schedulerParam;
throw utility::details::create_system_error(GetLastError());
}
SubmitThreadpoolWork(work);
CloseThreadpoolWork(work);
}
#endif // _WIN32_WINNT < _WIN32_WINNT_VISTA
#endif
} // namespace details
} // namespace pplx
#endif
\ No newline at end of file
/***
* Copyright (C) Microsoft. All rights reserved.
* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
*
*
* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk
*
* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
**/
// stdafx.cpp :
// Include the standard header and generate the precompiled header.
#include "stdafx.h"
/***
* Copyright (C) Microsoft. All rights reserved.
* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
*
* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
*
* Pre-compiled headers
*
* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk
*
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
****/
#pragma once
#if defined(__clang__)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunused-local-typedef"
#pragma clang diagnostic ignored "-Winfinite-recursion"
#endif
#include "pplx/compat.h"
#ifdef _WIN32
#ifdef CPPREST_TARGET_XP
#include <winsdkver.h>
#ifndef _WIN32_WINNT
#define _WIN32_WINNT _WIN32_WINNT_WS03 //Windows XP with SP2
#endif
#endif
#include <SDKDDKVer.h>
// use the debug version of the CRT if _DEBUG is defined
#ifdef _DEBUG
#define _CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <crtdbg.h>
#endif
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
// Windows Header Files:
#define NOMINMAX
#endif
#include <windows.h>
#include <objbase.h>
// Windows Header Files:
#if !defined(__cplusplus_winrt)
#include <winhttp.h>
#endif // #if !defined(__cplusplus_winrt)
#else // LINUX or APPLE
#define __STDC_LIMIT_MACROS
#include <stdint.h>
#include <cstdint>
#include <string>
#include <sstream>
#include <thread>
#include <atomic>
#include <signal.h>
#include "pthread.h"
#if (defined(ANDROID) || defined(__ANDROID__))
// Boost doesn't recognize libstdcpp on top of clang correctly
#include "boost/config.hpp"
#include "boost/config/stdlib/libstdcpp3.hpp"
#undef BOOST_NO_CXX11_SMART_PTR
#undef BOOST_NO_CXX11_NULLPTR
#endif
#include "boost/thread/mutex.hpp"
#include "boost/thread/condition_variable.hpp"
#include "boost/date_time/posix_time/posix_time_types.hpp"
#include "boost/bind/bind.hpp"
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/syscall.h>
#endif // _WIN32
// Macro indicating the C++ Rest SDK product itself is being built.
// This is to help track how many developers are directly building from source themselves.
#define _CASA_BUILD_FROM_SRC
#include <iostream>
#include <fstream>
#include <algorithm>
#include <exception>
#include <assert.h>
#include <streambuf>
#include <mutex>
#include <array>
#include <vector>
#include <memory>
#include <thread>
#if defined(max)
#error: max macro defined -- make sure to #define NOMINMAX before including windows.h
#endif
#if defined(min)
#error: min macro defined -- make sure to #define NOMINMAX before including windows.h
#endif
#if defined(__clang__)
#pragma clang diagnostic pop
#endif
/***
* Copyright (C) Microsoft. All rights reserved.
* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
*
* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
**/
#include "stdafx.h"
#include "threadpool.h"
#if defined(__ANDROID__)
#include <android/log.h>
#include <jni.h>
#endif
namespace crossplat
{
#if (defined(ANDROID) || defined(__ANDROID__))
// This pointer will be 0-initialized by default (at load time).
std::atomic<JavaVM*> JVM;
static void abort_if_no_jvm()
{
if (JVM == nullptr)
{
__android_log_print(ANDROID_LOG_ERROR, "CPPRESTSDK", "%s", "The CppREST SDK must be initialized before first use on android: https://github.com/Microsoft/cpprestsdk/wiki/How-to-build-for-Android");
std::abort();
}
}
JNIEnv* get_jvm_env()
{
abort_if_no_jvm();
JNIEnv* env = nullptr;
auto result = JVM.load()->AttachCurrentThread(&env, nullptr);
if (result != JNI_OK)
{
throw std::runtime_error("Could not attach to JVM");
}
return env;
}
threadpool& threadpool::shared_instance()
{
abort_if_no_jvm();
static threadpool s_shared(40);
return s_shared;
}
#else
// initialize the static shared threadpool
threadpool& threadpool::shared_instance()
{
static threadpool s_shared(40);
return s_shared;
}
#endif
}
#if defined(__ANDROID__)
void cpprest_init(JavaVM* vm) {
crossplat::JVM = vm;
}
#endif
/***
* Copyright (C) Microsoft. All rights reserved.
* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
*
*
* Simple Linux implementation of a static thread pool.
*
* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk
*
* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
***/
#pragma once
#include <pthread.h>
#include <vector>
#if defined(__clang__)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wconversion"
#pragma clang diagnostic ignored "-Wunreachable-code"
#pragma clang diagnostic ignored "-Winfinite-recursion"
#endif
#include "boost/asio.hpp"
#if defined(__clang__)
#pragma clang diagnostic pop
#endif
#if (defined(ANDROID) || defined(__ANDROID__))
#include <atomic>
#include <jni.h>
#include "pplx/pplx.h"
#endif
namespace crossplat {
#if (defined(ANDROID) || defined(__ANDROID__))
// IDEA: Break this section into a separate android/jni header
extern std::atomic<JavaVM*> JVM;
JNIEnv* get_jvm_env();
struct java_local_ref_deleter
{
void operator()(jobject lref) const
{
crossplat::get_jvm_env()->DeleteLocalRef(lref);
}
};
template<class T>
using java_local_ref = std::unique_ptr<typename std::remove_pointer<T>::type, java_local_ref_deleter>;
#endif
class threadpool
{
public:
threadpool(size_t n)
: m_service(n),
m_work(m_service)
{
for (size_t i = 0; i < n; i++)
add_thread();
}
static threadpool& shared_instance();
~threadpool()
{
m_service.stop();
for (auto iter = m_threads.begin(); iter != m_threads.end(); ++iter)
{
pthread_t t = *iter;
void* res;
pthread_join(t, &res);
}
}
template<typename T>
void schedule(T task)
{
m_service.post(task);
}
boost::asio::io_service& service()
{
return m_service;
}
private:
struct _cancel_thread { };
void add_thread()
{
pthread_t t;
auto result = pthread_create(&t, nullptr, &thread_start, this);
if (result == 0)
m_threads.push_back(t);
}
void remove_thread()
{
schedule([]() -> void { throw _cancel_thread(); });
}
#if (defined(ANDROID) || defined(__ANDROID__))
static void detach_from_java(void*)
{
JVM.load()->DetachCurrentThread();
}
#endif
static void* thread_start(void *arg)
{
#if (defined(ANDROID) || defined(__ANDROID__))
// Calling get_jvm_env() here forces the thread to be attached.
get_jvm_env();
pthread_cleanup_push(detach_from_java, nullptr);
#endif
threadpool* _this = reinterpret_cast<threadpool*>(arg);
try
{
_this->m_service.run();
}
catch (const _cancel_thread&)
{
// thread was cancelled
}
catch (...)
{
// Something bad happened
#if (defined(ANDROID) || defined(__ANDROID__))
// Reach into the depths of the 'droid!
// NOTE: Uses internals of the bionic library
// Written against android ndk r9d, 7/26/2014
__pthread_cleanup_pop(&__cleanup, true);
throw;
#endif
}
#if (defined(ANDROID) || defined(__ANDROID__))
pthread_cleanup_pop(true);
#endif
return arg;
}
std::vector<pthread_t> m_threads;
boost::asio::io_service m_service;
boost::asio::io_service::work m_work;
};
}
...@@ -3,7 +3,7 @@ project(Microservice) ...@@ -3,7 +3,7 @@ project(Microservice)
# version stuff # version stuff
set (Microservice_VERSION_MAJOR 1) set (Microservice_VERSION_MAJOR 1)
set (Microservice_VERSION_MINOR 6) set (Microservice_VERSION_MINOR 6)
set (Microservice_VERSION_PATCH 0) set (Microservice_VERSION_PATCH 1)
set(Microservice_VERSION_STRING ${Microservice_VERSION_MAJOR}.${Microservice_VERSION_MINOR}.${Microservice_VERSION_PATCH}) set(Microservice_VERSION_STRING ${Microservice_VERSION_MAJOR}.${Microservice_VERSION_MINOR}.${Microservice_VERSION_PATCH})
# type build flags # type build flags
...@@ -30,7 +30,7 @@ find_package(cereal CONFIG REQUIRED) ...@@ -30,7 +30,7 @@ find_package(cereal CONFIG REQUIRED)
# libcpprest is here for pplx tasks # libcpprest is here for pplx tasks
# linked libs and their locations # linked libs and their locations
set ( PROJECT_LINK_LIBS -lPocoFoundation -lhiredis -lcpprest -lcppmetrics -lboost_random -lboost_chrono set ( PROJECT_LINK_LIBS -lPocoFoundation -lhiredis -lcppmetrics -lpplx -lboost_random -lboost_chrono
-lboost_system -lboost_thread -lboost_date_time -lboost_regex -lboost_filesystem -lpthread -lboost_system -lboost_thread -lboost_date_time -lboost_regex -lboost_filesystem -lpthread
-lboost_random -lboost_chrono -lboost_system -lboost_thread -lssl -lboost_random -lboost_chrono -lboost_system -lboost_thread -lssl
-lcrypto -lzmqpp -lzmq -levpp -levent -lfmt -ldl) -lcrypto -lzmqpp -lzmq -levpp -levent -lfmt -ldl)
...@@ -60,22 +60,22 @@ file(GLOB_RECURSE SOURCES "src/*.cpp" "src/*.h") ...@@ -60,22 +60,22 @@ file(GLOB_RECURSE SOURCES "src/*.cpp" "src/*.h")
set (3PARTY_SOURCES ) set (3PARTY_SOURCES )
# remove RMQ for now # remove RMQ for now
get_filename_component(RMQHandler_file_path ${CMAKE_CURRENT_SOURCE_DIR}/src/handlers/Microservice_RMQHandler.cpp ABSOLUTE) # get_filename_component(RMQHandler_file_path ${CMAKE_CURRENT_SOURCE_DIR}/src/handlers/Microservice_RMQHandler.cpp ABSOLUTE)
get_filename_component(RMQRequest_file_path ${CMAKE_CURRENT_SOURCE_DIR}/src/impl/Microservice_IRequestRMQImpl.cpp ABSOLUTE) # get_filename_component(RMQRequest_file_path ${CMAKE_CURRENT_SOURCE_DIR}/src/impl/Microservice_IRequestRMQImpl.cpp ABSOLUTE)
get_filename_component(RMQResponse_file_path ${CMAKE_CURRENT_SOURCE_DIR}/src/impl/Microservice_IResponseRMQImpl.cpp ABSOLUTE) # get_filename_component(RMQResponse_file_path ${CMAKE_CURRENT_SOURCE_DIR}/src/impl/Microservice_IResponseRMQImpl.cpp ABSOLUTE)
get_filename_component(RMQServer_file_path ${CMAKE_CURRENT_SOURCE_DIR}/src/impl/servers/Microservice_IRestServerRMQImpl.cpp ABSOLUTE) # get_filename_component(RMQServer_file_path ${CMAKE_CURRENT_SOURCE_DIR}/src/impl/servers/Microservice_IRestServerRMQImpl.cpp ABSOLUTE)
get_filename_component(RMQClient_file_path ${CMAKE_CURRENT_SOURCE_DIR}/src/impl/clients/MSICommandClientRMQImpl.cpp ABSOLUTE) # get_filename_component(RMQClient_file_path ${CMAKE_CURRENT_SOURCE_DIR}/src/impl/clients/MSICommandClientRMQImpl.cpp ABSOLUTE)
get_filename_component(LOG4Cpp_file_path ${CMAKE_CURRENT_SOURCE_DIR}/src/impl/Microservices_ILoggerLog4cppImpl.cpp ABSOLUTE) # get_filename_component(LOG4Cpp_file_path ${CMAKE_CURRENT_SOURCE_DIR}/src/impl/Microservices_ILoggerLog4cppImpl.cpp ABSOLUTE)
message("${RMQHandler_file_path}") # message("${RMQHandler_file_path}")
list(REMOVE_ITEM SOURCES "${RMQHandler_file_path}" # list(REMOVE_ITEM SOURCES "${RMQHandler_file_path}"
"${RMQRequest_file_path}" # "${RMQRequest_file_path}"
"${RMQResponse_file_path}" # "${RMQResponse_file_path}"
"${RMQServer_file_path}" # "${RMQServer_file_path}"
"${RMQClient_file_path}" # "${RMQClient_file_path}"
"${LOG4Cpp_file_path}") # "${LOG4Cpp_file_path}")
message("${SOURCES}") message("${SOURCES}")
#Generate the shared library from the sources #Generate the shared library from the sources
...@@ -143,21 +143,10 @@ install(FILES ${INSTALL_FILES} DESTINATION include/microservice/utils) ...@@ -143,21 +143,10 @@ install(FILES ${INSTALL_FILES} DESTINATION include/microservice/utils)
# 3party libs # 3party libs
INSTALL( DIRECTORY 3party/lib DESTINATION lib/3party ) INSTALL( DIRECTORY 3party/lib DESTINATION lib/3party )
# internal libs # internal libs
#file (GLOB INSTALL_FILES "../internals/lib/libRabbitmq.*")
#install(FILES ${INSTALL_FILES} DESTINATION lib/internals)
#include 3party files #include 3party files
#INSTALL( DIRECTORY 3party/cereal-1.2.1/include DESTINATION include/3party/cereal-1.2.1 )
#INSTALL( DIRECTORY /3party/rapidjson-cereal-1.2.1 DESTINATION include/3party )
INSTALL( DIRECTORY 3party/include/cppmetrics DESTINATION include/3party/cppmetrics ) INSTALL( DIRECTORY 3party/include/cppmetrics DESTINATION include/3party/cppmetrics )
# file (GLOB INSTALL_FILES "../3party/mongoose/mongoose.*") INSTALL( DIRECTORY 3party/include/pplx DESTINATION include/3party/pplx )
# install(FILES ${INSTALL_FILES} DESTINATION include/3party/mongoose)
#INSTALL( DIRECTORY ../3party/cpprest/Release/include DESTINATION include/3party/cpprest )
# INSTALL( DIRECTORY ../3party/evpp/build-release/include DESTINATION include/3party/evpp )
# INSTALL( DIRECTORY ../3party/rabbitmq DESTINATION include/3party )
#INSTALL( DIRECTORY ../internals/include/Rabbitmq DESTINATION include/internals )
# INSTALL( DIRECTORY /usr/include/hiredis DESTINATION include/3party )
# INSTALL( DIRECTORY ../3party/flatbuffers/include DESTINATION include/3party/flatbuffers )
#CPack #CPack
include (InstallRequiredSystemLibraries) include (InstallRequiredSystemLibraries)
......
## C++ Microservice Framework ## C++ Microservice Framework
* to create microservice docker run script/build_microservice_docker.sh [version] * to create microservice docker run script/build_microservice_docker.sh [version]
## VERSIONS: ## VERSIONS:
# 1.6.1
- remove RabbitMQ for now, remove log4cpp, cpprestsdk
- use stripped version off pplx (without cpprestsdk)
# 1.6.0 # 1.6.0
- change workspace to vscode remote containers - change workspace to vscode remote containers
- install most of dependencies either with apt or vcpkg in the remote container - install most of dependencies either with apt or vcpkg in the remote container
......
...@@ -33,6 +33,6 @@ RemoteVSContainers and c++17 feature: ...@@ -33,6 +33,6 @@ RemoteVSContainers and c++17 feature:
- Check CMake https://cmake.org/cmake/help/v3.11/module/FetchContent.html for fetching external project directly from github - Check CMake https://cmake.org/cmake/help/v3.11/module/FetchContent.html for fetching external project directly from github
- remove cppmetrics for now, after add influxdb from https://github.com/awegrzyn/influxdb-cxx and create our own cppmetrics (maybe open source) - remove cppmetrics for now, after add influxdb from https://github.com/awegrzyn/influxdb-cxx and create our own cppmetrics (maybe open source)
or fork it for c++17 and no boost or fork it for c++17 and no boost
- remove cpprest + remove cpprest
- remove pplx tasks, and replace with evpp for client async - remove pplx tasks
- replace boost with std - replace boost with std
#!/bin/bash #!/bin/bash
#
# File: install-dependencies.sh
# Author: amir
#
# Created on May 8, 2016, 9:59:18 AM
#
# apt-get install -y libhiredis-dev libzmq3-dev liblog4cpp5-dev \
# libgoogle-glog-dev libboost-all-dev libssl-dev uuid-dev libzmqpp-dev libmhash-dev libevent-dev \
# libpoco-dev libcpprest-dev
source /home/vscode/.bashrc source /home/vscode/.bashrc
echo "checking for vcpkg changes and update..."
cd vcpkg && git fetch
HEADHASH=$(git rev-parse HEAD)
UPSTREAMHASH=$(git rev-parse master@{upstream})
if [ "$HEADHASH" != "$UPSTREAMHASH" ]
then
echo "new vckpg changes.. pulling and re-bulding vcpkg"
git pull && /home/vscode/vcpkg/bootstrap-vcpkg.sh
else
echo "no vcpkg changes"
fi
echo "Installing vcpkg packages..." echo "Installing vcpkg packages..."
cd vcpkg && git pull #cd vcpkg && git pull && /home/vscode/vcpkg/bootstrap-vcpkg.sh
#/home/vscode/vcpkg/vcpkg install evpp spdlog nlohmann-json cereal rapidjson flatbuffers poco hiredis glog log4cpp libuuid cppzmq #/home/vscode/vcpkg/vcpkg install evpp spdlog nlohmann-json cereal rapidjson flatbuffers poco hiredis glog log4cpp libuuid cppzmq
/home/vscode/vcpkg/vcpkg install evpp spdlog nlohmann-json cereal rapidjson flatbuffers poco hiredis glog log4cpp libuuid boost-foreach cpprestsdk /home/vscode/vcpkg/vcpkg install evpp spdlog nlohmann-json cereal rapidjson flatbuffers poco hiredis glog libuuid boost-foreach
...@@ -18,7 +18,7 @@ ...@@ -18,7 +18,7 @@
#include "common/MSTypes.h" #include "common/MSTypes.h"
#include "params/MSCommandParams.h" #include "params/MSCommandParams.h"
#include "json.hpp" #include "json.hpp"
#include <boost/function.hpp> //#include <boost/function.hpp>
#include <cereal/archives/json.hpp> #include <cereal/archives/json.hpp>
#include <rapidjson/document.h> #include <rapidjson/document.h>
#include <atomic> #include <atomic>
......
/*
* cMicroservice_RestHandler.cpp
*
* Created on: Mar 23, 2015
* Author: amir
*/
#include <stringbuffer.h>
#include <map>
#include <deque>
//#include <mongoose.h>
// #include <civetweb.h>
#include <stdlib.h>
#include <stringbuffer.h> //rapidjson string
#include <writer.h> //rapidjson writer
#include <document.h> //rapidjson
#include "../handlers/Microservice_RMQHandler.h"
#include "../Microservice_BaseRestResponse.h"
#include "../impl/Microservice_IRequestRMQImpl.h"
#include "../impl/Microservice_IResponseRMQImpl.h"
#include <sstream>
cMicroservice_RMQHandler::cMicroservice_RMQHandler(std::string apiContextPath,Microservice_RestHandler* pc_Handler):
mpc_Handler(pc_Handler)
{
mpc_Buffer = new msrapidjson::StringBuffer(0,nsMicroservice_Constants::MAX_JSON_BUFFER);
mpc_Writer = new JsonStringWriter(*mpc_Buffer);
mpc_RequestContext = new cMicroservice_RequestContext(this,
//mpc_Writer,
new cMicroservice_IResponseRMQImpl(),
new cMicroservice_IRequestRMQImpl());
this->apiContextPath = apiContextPath;
}
/**
* handling the request
* setting the request context
* getting the method and activating the adequate function
* @param conn
*/
void cMicroservice_RMQHandler::HandleRequest(cRMQ_Message* pc_Message)
{
/*
* get request context
*/
SetRequestContext(pc_Message);
/*
* now check the method
*/
cMicroservice_Enums::eMethod e_Method = GetMethod(pc_Message);
switch (e_Method)
{
case cMicroservice_Enums::eGet:
DoGet(mpc_RequestContext);
break;
case cMicroservice_Enums::ePost:
DoPost(mpc_RequestContext);
break;
case cMicroservice_Enums::ePut:
DoPut(mpc_RequestContext);
break;
case cMicroservice_Enums::eDelete:
DoDelete(mpc_RequestContext);
break;
default:
SendErrorResp(mpc_RequestContext->mpti_Response,nsMicroservice_Constants::METHOD_NOT_IMPLEMENTED);
break;
}
}
/**
* getting the query params
* @param conn
*/
void cMicroservice_RMQHandler::GetQueryParams(cRMQ_Message* pc_Message)
{
/*
* getting query parameters
*/
if (pc_Message->getQueryParams().length() < 1)
return;
DequeStringMap* pc_queryParams = &mpc_RequestContext->mc_QueryParameters;
strncpy(mba_Buff, pc_Message->getQueryParams().c_str(), nsMicroservice_Constants::MAX_URI_LENGTH);
char* pba_token = strtok(mba_Buff, nsMicroservice_Constants::AND_SEPERATOR);
while (pba_token)
{
// x=y or just x
char* pba_Equal = strchr(pba_token, '=');
if (pba_Equal)
{
*pba_Equal = CNULL;
DequeStringMap::iterator t_QueryParamIter = pc_queryParams->find(pba_token);
if (t_QueryParamIter != pc_queryParams->end())
{
// existing query key >> adding to deque
t_QueryParamIter->second.push_back(pba_Equal + 1);
}
else
{
// new one
std::deque<std::string> t_QueryDeque;
t_QueryDeque.push_back(pba_Equal + 1);
(*pc_queryParams)[pba_token] = t_QueryDeque;
}
}
else
{
// insert empty deque - cannot insert null value
std::deque<std::string> t_QueryDeque;
(*pc_queryParams)[pba_token] = t_QueryDeque;
}
pba_token = strtok(NULL, nsMicroservice_Constants::AND_SEPERATOR);
}
}
/**
* - getting/setting request/response ifaces
* - getting params
* - getting query parameters
* @param mg_connection
*/
void cMicroservice_RMQHandler::SetRequestContext(cRMQ_Message* pc_Message)
{
mpc_RequestContext->Reset();
/*
* getting/setting request/response ifaces
*/
((cMicroservice_IRequestRMQImpl*)mpc_RequestContext->mpti_Request)->setMessage(pc_Message);
/*
* getting params
*/
const char* pba_ParamsStr = pc_Message->getPath().c_str() + apiContextPath.length();
strncpy(mba_Buff,pba_ParamsStr,nsMicroservice_Constants::MAX_URI_LENGTH);
char* pba_token = strtok(mba_Buff,nsMicroservice_Constants::SLASH_SEPERATOR);
while(pba_token)
{
mpc_RequestContext->mc_Params.push_back(pba_token);
pba_token = strtok(NULL,nsMicroservice_Constants::SLASH_SEPERATOR);
}
/*
* getting query parameters
*/
GetQueryParams(pc_Message);
}
void cMicroservice_RMQHandler::SendErrorResp(nsMicroservice_Iface::IResponse* pti_Response,std::string error)
{
/*
* create error rest response
*/
// snprintf(mba_ErrorBuff,
// nsMicroservice_Constants::MAX_ERROR_BUFF_URI_LENGTH,
// nsMicroservice_Constants::ERROR_REST_RESPONSE_TEMPLATE,
// error.c_str());
std::ostringstream c_OutputStream;
c_OutputStream << nsMicroservice_Constants::ERROR_REST_RESPONSE_TEMPLATE_PREFIX
<< error.c_str()
<< nsMicroservice_Constants::ERROR_REST_RESPONSE_TEMPLATE_SUFFIX
<< '}';
/*
* send it
*/
pti_Response->Send(c_OutputStream.str().c_str());
// pti_Response->Send(mba_ErrorBuff);
}
void cMicroservice_RMQHandler::WriteObjectToResponse(nsMicroservice_Iface::IResponse* pti_Response,msrapidjson::Document& t_ObjectDoc)
{
std::ostringstream c_OutputStream;
if(!t_ObjectDoc.IsNull()) {
msrapidjson::StringBuffer buffer;
msrapidjson::Writer<msrapidjson::StringBuffer> writer(buffer);
t_ObjectDoc.Accept(writer);
c_OutputStream << nsMicroservice_Constants::SUCCESS_REST_RESPONSE_TEMPLATE << buffer.GetString() << '}';
} else {
c_OutputStream << nsMicroservice_Constants::SUCCESS_NULL_REST_RESPONSE_TEMPLATE << '}';
}
pti_Response->Send(c_OutputStream.str().c_str());
// std::ostringstream c_OutputStream;
// t_ObjectDoc.Accept(*this->mpc_Writer);
// c_OutputStream << nsMicroservice_Constants::SUCCESS_REST_RESPONSE_TEMPLATE << mpc_Buffer->GetString() << '}';
// pti_Response->Send(c_OutputStream.str().c_str());
// // clear
// mpc_Buffer->Clear();
}
void cMicroservice_RMQHandler::WriteObjectToResponse(nsMicroservice_Iface::IResponse* pti_Response,cMicroservice_BaseRestResponse& t_BaseRestResponse)
{
if(t_BaseRestResponse.IsSuccess()){
WriteObjectToResponse(pti_Response,t_BaseRestResponse.GetObjectNode());
}
else{
SendErrorResp(pti_Response,t_BaseRestResponse.GetError());
}
}
void cMicroservice_RMQHandler::WriteStringToResponse(nsMicroservice_Iface::IResponse* pti_Response,const char* pba_Doc)
{
std::ostringstream c_OutputStream;
c_OutputStream << nsMicroservice_Constants::SUCCESS_REST_RESPONSE_TEMPLATE << pba_Doc << '}';
pti_Response->Send(c_OutputStream.str().c_str());
}
bool cMicroservice_RMQHandler::ReadObjectFromRequest(nsMicroservice_Iface::IRequest* pti_Request,msrapidjson::Document& t_ObjectDoc)
{
const char* pba_Content = pti_Request->GetContent();
if (pba_Content)
{
if (!t_ObjectDoc.Parse<0>(pba_Content).HasParseError())
return true;
}
return false;
}
/**
* resolving the http method
* @param conn
* @return
*/
cMicroservice_Enums::eMethod cMicroservice_RMQHandler::GetMethod(cRMQ_Message* pc_Message)
{
cMicroservice_Enums::eMethod e_Method = cMicroservice_Enums::eMaxMethods;
for (int i = 0; i < cMicroservice_Enums::eMaxMethods; i++)
{
if (!strcmp(pc_Message->getMethod().c_str(), gbaa_Microservice_MethodNames[i]))
{
e_Method = (cMicroservice_Enums::eMethod) (i);
break;
}
}
return e_Method;
}
/*
* Microservice_RestHandler.h
*
* Created on: Mar 23, 2015
* Author: amir
*/
#ifndef MICROSERVICE_RMQ_HANDLER_H_
#define MICROSERVICE_RMQ_HANDLER_H_
#include <common/Microservice_Defines.h>
#include <common/Microservice_Iface.h>
#include <stddef.h>
#include <writer.h>
#include <stringbuffer.h>
#include "Microservice_RestHandler.h"
class cMicroservice_RequestContext;
class cRMQ_Message;
class cMicroservice_RMQHandler : public nsMicroservice_Iface::IContainer
{
private:
JsonStringWriter *mpc_Writer;
rapidjson::StringBuffer* mpc_Buffer;
std::string apiContextPath;
Microservice_RestHandler* mpc_Handler;
nsMicroservice_Iface::ILogger* mpc_Logger;
cMicroservice_RequestContext* mpc_RequestContext;
char mba_Buff[nsMicroservice_Constants::MAX_URI_LENGTH];
char mba_ErrorBuff[nsMicroservice_Constants::MAX_ERROR_BUFF_URI_LENGTH];
cMicroservice_Enums::eMethod GetMethod(cRMQ_Message* pc_Message);
// inlines
void DoGet(cMicroservice_RequestContext* pc_ReqCtx) { mpc_Handler->DoRead(pc_ReqCtx); }
void DoPost(cMicroservice_RequestContext* pc_ReqCtx){ mpc_Handler->DoCreate(pc_ReqCtx); }
void DoPut(cMicroservice_RequestContext* pc_ReqCtx) { mpc_Handler->DoUpdate(pc_ReqCtx); }
void DoDelete(cMicroservice_RequestContext* pc_ReqCtx){ mpc_Handler->DoDelete(pc_ReqCtx); }
/**
* prepare the request context
* @param mg_connection
* @return
*/
void SetRequestContext(cRMQ_Message* pc_Message);
void GetQueryParams(cRMQ_Message* pc_Message);
public:
cMicroservice_RMQHandler(std::string apiContextPath,Microservice_RestHandler* pc_Handler);
void withLogger(nsMicroservice_Iface::ILogger* pc_Logger) { this->mpc_Logger = pc_Logger; }
void HandleRequest(cRMQ_Message* message);
void SendErrorResp(nsMicroservice_Iface::IResponse* pti_Response,std::string error);
void WriteObjectToResponse(nsMicroservice_Iface::IResponse* pti_Response,rapidjson::Document& t_ObjectDoc);
void WriteObjectToResponse(nsMicroservice_Iface::IResponse* pti_Response,cMicroservice_BaseRestResponse& t_BaseRestResponse);
void WriteStringToResponse(nsMicroservice_Iface::IResponse* pti_Response,const char* pba_Doc);
bool ReadObjectFromRequest(nsMicroservice_Iface::IRequest* pti_Request,rapidjson::Document& t_ObjectDoc);
// void Publish(std::string& t_Topic, std::string& t_Message) {}
// void Subscribe(std::string& t_Topic, nsMicroservice_Iface::INotifyCallback& t_NotifyHandler) {}
// void Unsubscribe(std::string& t_Topic) {}
};
#endif /* MICROSERVICE_RMQ_HANDLER_H_ */
/*
* Microservice_IRequestRMQImpl.cpp
*
* Created on: Mar 23, 2015
* Author: amir
*/
#include "Microservice_IRequestRMQImpl.h"
cMicroservice_IRequestRMQImpl::cMicroservice_IRequestRMQImpl(): mpc_Message(NULL)
{
}
const char* cMicroservice_IRequestRMQImpl::GetQueryString()
{
if (mpc_Message)
return mpc_Message->getQueryParams().c_str();
return nullptr;
}
const char* cMicroservice_IRequestRMQImpl::GetRelativePath()
{
if (mpc_Message)
return mpc_Message->getPath().c_str();
return nullptr;
}
const char* cMicroservice_IRequestRMQImpl::GetContent()
{
if (mpc_Message)
mpc_Message->getContent().c_str();
return nullptr;
}
/*
* Microservice_IRequestRMQImpl.h
*
* Created on: Mar 23, 2015
* Author: amir
*/
#ifndef MICROSERVICE_IREQUEST_RMQ_IMPL_H_
#define MICROSERVICE_IREQUEST_RMQ_IMPL_H_
#include <common/Microservice_Iface.h>
#include "RMQ_Message.h"
class cMicroservice_IRequestRMQImpl: public nsMicroservice_Iface::IRequest
{
cRMQ_Message* mpc_Message;
public:
cMicroservice_IRequestRMQImpl();
const char* GetQueryString();
const char* GetRelativePath();
const char* GetContent();
void Reset() { mpc_Message = NULL; }
void setMessage(cRMQ_Message* pc_Message) { this->mpc_Message = pc_Message;}
};
#endif // MICROSERVICE_IREQUEST_RMQ_IMPL_H_
/*
* Microservice_IResponseRMQImpl.cpp
*
* Created on: Mar 25, 2015
* Author: amir
*/
#include "Microservice_IResponseRMQImpl.h"
#include "RMQ_Message.h"
cMicroservice_IResponseRMQImpl::cMicroservice_IResponseRMQImpl():
mpc_Channel(NULL)
{
// TODO Auto-generated constructor stub
}
void cMicroservice_IResponseRMQImpl::Send(const char* response)
{
cRMQ_Message message;
message.setContent(response);
mpc_Channel->SendMessage(&message, ms_exchange, ms_bindingKey);
}
nsMicroservice_Iface::IResponse *cMicroservice_IResponseRMQImpl::clone() {
return nullptr;
}
/*
* Microservice_IResponseRestImpl.h
*
* Created on: Mar 25, 2015
* Author: amir
*/
#ifndef MICROSERVICE_IRESPONSE_RMQ_IMPL_H_
#define MICROSERVICE_IRESPONSE_RMQ_IMPL_H_
#include <common/Microservice_Iface.h>
#include "RMQ_Channel.h"
class cMicroservice_IResponseRMQImpl: public nsMicroservice_Iface::IResponse
{
protected:
cRMQ_Channel *mpc_Channel;
std::string ms_exchange;
std::string ms_bindingKey;
public:
cMicroservice_IResponseRMQImpl();
void Send(const char* response);
void Reset() {mpc_Channel = NULL; }
void Init(cRMQ_Channel* pc_Channel, std::string exchange, std::string bindingKey)
{
this->mpc_Channel = pc_Channel;
this->ms_exchange = exchange;
this->ms_bindingKey = bindingKey;
}
virtual nsMicroservice_Iface::IResponse *clone() override;
};
#endif // MICROSERVICE_IRESPONSE_RMQ_IMPL_H_
...@@ -5,14 +5,16 @@ ...@@ -5,14 +5,16 @@
#ifndef MICROSERVICE_CLIENTFACTORY_H #ifndef MICROSERVICE_CLIENTFACTORY_H
#define MICROSERVICE_CLIENTFACTORY_H #define MICROSERVICE_CLIENTFACTORY_H
#include "common/Microservice_Iface.h"
#include <params/Microservice_Params.h>
#include <impl/clients/MSICommandClientRMQImpl.h> // #include <impl/clients/MSICommandClientRMQImpl.h>
/** /**
* specific clients factory * specific clients factory
*/ */
class MSICommandClientRMQImpl; //class MSICommandClientRMQImpl;
class cMicroservice_Client; class cMicroservice_Client;
class ClientFactory { class ClientFactory {
......
...@@ -5,8 +5,7 @@ ...@@ -5,8 +5,7 @@
* Author: amir * Author: amir
*/ */
#include <impl/Microservice_IRequestRMQImpl.h> #include "Microservice_IRequestRMQImpl.h"
#include <General_Def.h>
cMicroservice_IRequestRMQImpl::cMicroservice_IRequestRMQImpl(): mpc_Message(NULL) cMicroservice_IRequestRMQImpl::cMicroservice_IRequestRMQImpl(): mpc_Message(NULL)
{ {
...@@ -16,19 +15,19 @@ const char* cMicroservice_IRequestRMQImpl::GetQueryString() ...@@ -16,19 +15,19 @@ const char* cMicroservice_IRequestRMQImpl::GetQueryString()
{ {
if (mpc_Message) if (mpc_Message)
return mpc_Message->getQueryParams().c_str(); return mpc_Message->getQueryParams().c_str();
return NULL; return nullptr;
} }
const char* cMicroservice_IRequestRMQImpl::GetRelativePath() const char* cMicroservice_IRequestRMQImpl::GetRelativePath()
{ {
if (mpc_Message) if (mpc_Message)
return mpc_Message->getUri().c_str(); return mpc_Message->getPath().c_str();
return NULL; return nullptr;
} }
char* cMicroservice_IRequestRMQImpl::GetContent() const char* cMicroservice_IRequestRMQImpl::GetContent()
{ {
if (mpc_Message) if (mpc_Message)
mpc_Message->getContent().c_str(); mpc_Message->getContent().c_str();
return NULL; return nullptr;
} }
...@@ -10,22 +10,22 @@ ...@@ -10,22 +10,22 @@
#include <common/Microservice_Iface.h> #include <common/Microservice_Iface.h>
#include "RMQ_MessageRest.h" #include "RMQ_Message.h"
class cMicroservice_IRequestRMQImpl: public nsMicroservice_Iface::IRequest class cMicroservice_IRequestRMQImpl: public nsMicroservice_Iface::IRequest
{ {
cRMQ_MessageRest* mpc_Message; cRMQ_Message* mpc_Message;
public: public:
cMicroservice_IRequestRMQImpl(); cMicroservice_IRequestRMQImpl();
const char* GetQueryString(); const char* GetQueryString();
const char* GetRelativePath(); const char* GetRelativePath();
char* GetContent(); const char* GetContent();
void Reset() { mpc_Message = NULL; } void Reset() { mpc_Message = NULL; }
void setMessage(cRMQ_MessageRest* pc_Message) { this->mpc_Message = pc_Message;} void setMessage(cRMQ_Message* pc_Message) { this->mpc_Message = pc_Message;}
}; };
#endif // MICROSERVICE_IREQUEST_RMQ_IMPL_H_ #endif // MICROSERVICE_IREQUEST_RMQ_IMPL_H_
...@@ -4,9 +4,9 @@ ...@@ -4,9 +4,9 @@
* Created on: Mar 25, 2015 * Created on: Mar 25, 2015
* Author: amir * Author: amir
*/ */
#include <impl/Microservice_IResponseRMQImpl.h> #include "Microservice_IResponseRMQImpl.h"
#include "RMQ_MessageRest.h" #include "RMQ_Message.h"
cMicroservice_IResponseRMQImpl::cMicroservice_IResponseRMQImpl(): cMicroservice_IResponseRMQImpl::cMicroservice_IResponseRMQImpl():
mpc_Channel(NULL) mpc_Channel(NULL)
...@@ -16,7 +16,11 @@ mpc_Channel(NULL) ...@@ -16,7 +16,11 @@ mpc_Channel(NULL)
void cMicroservice_IResponseRMQImpl::Send(const char* response) void cMicroservice_IResponseRMQImpl::Send(const char* response)
{ {
cRMQ_MessageRest RespMessage; cRMQ_Message message;
RespMessage.setContent(response); message.setContent(response);
mpc_Channel->SendMessage(&RespMessage); mpc_Channel->SendMessage(&message, ms_exchange, ms_bindingKey);
}
nsMicroservice_Iface::IResponse *cMicroservice_IResponseRMQImpl::clone() {
return nullptr;
} }
...@@ -13,14 +13,25 @@ ...@@ -13,14 +13,25 @@
class cMicroservice_IResponseRMQImpl: public nsMicroservice_Iface::IResponse class cMicroservice_IResponseRMQImpl: public nsMicroservice_Iface::IResponse
{ {
protected:
cRMQ_Channel *mpc_Channel; cRMQ_Channel *mpc_Channel;
std::string ms_exchange;
std::string ms_bindingKey;
public: public:
cMicroservice_IResponseRMQImpl(); cMicroservice_IResponseRMQImpl();
void Send(const char* response); void Send(const char* response);
void Reset() {mpc_Channel = NULL; } void Reset() {mpc_Channel = NULL; }
void setChannel(cRMQ_Channel* pc_Channel) { this->mpc_Channel = pc_Channel;} void Init(cRMQ_Channel* pc_Channel, std::string exchange, std::string bindingKey)
{
this->mpc_Channel = pc_Channel;
this->ms_exchange = exchange;
this->ms_bindingKey = bindingKey;
}
virtual nsMicroservice_Iface::IResponse *clone() override;
}; };
#endif // MICROSERVICE_IRESPONSE_RMQ_IMPL_H_ #endif // MICROSERVICE_IRESPONSE_RMQ_IMPL_H_
...@@ -5,27 +5,33 @@ ...@@ -5,27 +5,33 @@
* Author: amir * Author: amir
*/ */
#include <handlers/Microservice_RMQHandler.h>
#include <stringbuffer.h> #include <stringbuffer.h>
#include <General_Def.h>
#include <map> #include <map>
#include <deque> #include <deque>
#include <mongoose.h> //#include <mongoose.h>
#include <impl/Microservice_IRequestRMQImpl.h> // #include <civetweb.h>
#include <impl/Microservice_IResponseRMQImpl.h> #include <stdlib.h>
#include <stringbuffer.h> //rapidjson string #include <stringbuffer.h> //rapidjson string
#include <writer.h> //rapidjson writer #include <writer.h> //rapidjson writer
#include <document.h> //rapidjson #include <document.h> //rapidjson
#include "../handlers/Microservice_RMQHandler.h"
#include "../Microservice_BaseRestResponse.h"
#include "../impl/Microservice_IRequestRMQImpl.h"
#include "../impl/Microservice_IResponseRMQImpl.h"
#include <sstream> #include <sstream>
cMicroservice_RMQHandler::cMicroservice_RMQHandler(std::string apiContextPath,cMicroservice_BaseHandler* pc_Handler): cMicroservice_RMQHandler::cMicroservice_RMQHandler(std::string apiContextPath,Microservice_RestHandler* pc_Handler):
mpc_Handler(pc_Handler) mpc_Handler(pc_Handler)
{ {
mpc_Buffer = new rapidjson::StringBuffer(0,nsMicroservice_Constants::MAX_JSON_BUFFER); mpc_Buffer = new msrapidjson::StringBuffer(0,nsMicroservice_Constants::MAX_JSON_BUFFER);
mpc_Writer = new JsonStringWriter(*mpc_Buffer); mpc_Writer = new JsonStringWriter(*mpc_Buffer);
mpc_RequestContext = new cMicroservice_RequestContext(this, mpc_RequestContext = new cMicroservice_RequestContext(this,
mpc_Writer, //mpc_Writer,
new cMicroservice_IResponseRMQImpl(), new cMicroservice_IResponseRMQImpl(),
new cMicroservice_IRequestRMQImpl()); new cMicroservice_IRequestRMQImpl());
this->apiContextPath = apiContextPath; this->apiContextPath = apiContextPath;
...@@ -37,7 +43,7 @@ mpc_Handler(pc_Handler) ...@@ -37,7 +43,7 @@ mpc_Handler(pc_Handler)
* getting the method and activating the adequate function * getting the method and activating the adequate function
* @param conn * @param conn
*/ */
void cMicroservice_RMQHandler::HandleRequest(cRMQ_MessageRest* pc_Message) void cMicroservice_RMQHandler::HandleRequest(cRMQ_Message* pc_Message)
{ {
/* /*
* get request context * get request context
...@@ -71,7 +77,7 @@ void cMicroservice_RMQHandler::HandleRequest(cRMQ_MessageRest* pc_Message) ...@@ -71,7 +77,7 @@ void cMicroservice_RMQHandler::HandleRequest(cRMQ_MessageRest* pc_Message)
* getting the query params * getting the query params
* @param conn * @param conn
*/ */
void cMicroservice_RMQHandler::GetQueryParams(cRMQ_MessageRest* pc_Message) void cMicroservice_RMQHandler::GetQueryParams(cRMQ_Message* pc_Message)
{ {
/* /*
* getting query parameters * getting query parameters
...@@ -80,7 +86,7 @@ void cMicroservice_RMQHandler::GetQueryParams(cRMQ_MessageRest* pc_Message) ...@@ -80,7 +86,7 @@ void cMicroservice_RMQHandler::GetQueryParams(cRMQ_MessageRest* pc_Message)
return; return;
DequeStringMap* pc_queryParams = &mpc_RequestContext->mc_QueryParameters; DequeStringMap* pc_queryParams = &mpc_RequestContext->mc_QueryParameters;
strlcpy(mba_Buff, pc_Message->getQueryParams().c_str(), nsMicroservice_Constants::MAX_URI_LENGTH); strncpy(mba_Buff, pc_Message->getQueryParams().c_str(), nsMicroservice_Constants::MAX_URI_LENGTH);
char* pba_token = strtok(mba_Buff, nsMicroservice_Constants::AND_SEPERATOR); char* pba_token = strtok(mba_Buff, nsMicroservice_Constants::AND_SEPERATOR);
while (pba_token) while (pba_token)
...@@ -120,7 +126,7 @@ void cMicroservice_RMQHandler::GetQueryParams(cRMQ_MessageRest* pc_Message) ...@@ -120,7 +126,7 @@ void cMicroservice_RMQHandler::GetQueryParams(cRMQ_MessageRest* pc_Message)
* - getting query parameters * - getting query parameters
* @param mg_connection * @param mg_connection
*/ */
void cMicroservice_RMQHandler::SetRequestContext(cRMQ_MessageRest* pc_Message) void cMicroservice_RMQHandler::SetRequestContext(cRMQ_Message* pc_Message)
{ {
mpc_RequestContext->Reset(); mpc_RequestContext->Reset();
/* /*
...@@ -130,8 +136,8 @@ void cMicroservice_RMQHandler::SetRequestContext(cRMQ_MessageRest* pc_Message) ...@@ -130,8 +136,8 @@ void cMicroservice_RMQHandler::SetRequestContext(cRMQ_MessageRest* pc_Message)
/* /*
* getting params * getting params
*/ */
const char* pba_ParamsStr = pc_Message->getUri().c_str() + apiContextPath.length(); const char* pba_ParamsStr = pc_Message->getPath().c_str() + apiContextPath.length();
strlcpy(mba_Buff,pba_ParamsStr,nsMicroservice_Constants::MAX_URI_LENGTH); strncpy(mba_Buff,pba_ParamsStr,nsMicroservice_Constants::MAX_URI_LENGTH);
char* pba_token = strtok(mba_Buff,nsMicroservice_Constants::SLASH_SEPERATOR); char* pba_token = strtok(mba_Buff,nsMicroservice_Constants::SLASH_SEPERATOR);
while(pba_token) while(pba_token)
{ {
...@@ -150,24 +156,55 @@ void cMicroservice_RMQHandler::SendErrorResp(nsMicroservice_Iface::IResponse* pt ...@@ -150,24 +156,55 @@ void cMicroservice_RMQHandler::SendErrorResp(nsMicroservice_Iface::IResponse* pt
/* /*
* create error rest response * create error rest response
*/ */
snprintf(mba_ErrorBuff, // snprintf(mba_ErrorBuff,
nsMicroservice_Constants::MAX_ERROR_BUFF_URI_LENGTH, // nsMicroservice_Constants::MAX_ERROR_BUFF_URI_LENGTH,
nsMicroservice_Constants::ERROR_REST_RESPONSE_TEMPLATE, // nsMicroservice_Constants::ERROR_REST_RESPONSE_TEMPLATE,
error.c_str()); // error.c_str());
std::ostringstream c_OutputStream;
c_OutputStream << nsMicroservice_Constants::ERROR_REST_RESPONSE_TEMPLATE_PREFIX
<< error.c_str()
<< nsMicroservice_Constants::ERROR_REST_RESPONSE_TEMPLATE_SUFFIX
<< '}';
/* /*
* send it * send it
*/ */
pti_Response->Send(mba_ErrorBuff); pti_Response->Send(c_OutputStream.str().c_str());
// pti_Response->Send(mba_ErrorBuff);
} }
void cMicroservice_RMQHandler::WriteObjectToResponse(nsMicroservice_Iface::IResponse* pti_Response,rapidjson::Document& t_ObjectDoc) void cMicroservice_RMQHandler::WriteObjectToResponse(nsMicroservice_Iface::IResponse* pti_Response,msrapidjson::Document& t_ObjectDoc)
{ {
std::ostringstream c_OutputStream; std::ostringstream c_OutputStream;
t_ObjectDoc.Accept(*this->mpc_Writer);
c_OutputStream << nsMicroservice_Constants::SUCCESS_REST_RESPONSE_TEMPLATE << mpc_Buffer->GetString() << '}'; if(!t_ObjectDoc.IsNull()) {
msrapidjson::StringBuffer buffer;
msrapidjson::Writer<msrapidjson::StringBuffer> writer(buffer);
t_ObjectDoc.Accept(writer);
c_OutputStream << nsMicroservice_Constants::SUCCESS_REST_RESPONSE_TEMPLATE << buffer.GetString() << '}';
} else {
c_OutputStream << nsMicroservice_Constants::SUCCESS_NULL_REST_RESPONSE_TEMPLATE << '}';
}
pti_Response->Send(c_OutputStream.str().c_str()); pti_Response->Send(c_OutputStream.str().c_str());
// clear
mpc_Buffer->Clear(); // std::ostringstream c_OutputStream;
// t_ObjectDoc.Accept(*this->mpc_Writer);
// c_OutputStream << nsMicroservice_Constants::SUCCESS_REST_RESPONSE_TEMPLATE << mpc_Buffer->GetString() << '}';
// pti_Response->Send(c_OutputStream.str().c_str());
// // clear
// mpc_Buffer->Clear();
}
void cMicroservice_RMQHandler::WriteObjectToResponse(nsMicroservice_Iface::IResponse* pti_Response,cMicroservice_BaseRestResponse& t_BaseRestResponse)
{
if(t_BaseRestResponse.IsSuccess()){
WriteObjectToResponse(pti_Response,t_BaseRestResponse.GetObjectNode());
}
else{
SendErrorResp(pti_Response,t_BaseRestResponse.GetError());
}
} }
void cMicroservice_RMQHandler::WriteStringToResponse(nsMicroservice_Iface::IResponse* pti_Response,const char* pba_Doc) void cMicroservice_RMQHandler::WriteStringToResponse(nsMicroservice_Iface::IResponse* pti_Response,const char* pba_Doc)
...@@ -177,8 +214,7 @@ void cMicroservice_RMQHandler::WriteStringToResponse(nsMicroservice_Iface::IResp ...@@ -177,8 +214,7 @@ void cMicroservice_RMQHandler::WriteStringToResponse(nsMicroservice_Iface::IResp
pti_Response->Send(c_OutputStream.str().c_str()); pti_Response->Send(c_OutputStream.str().c_str());
} }
bool cMicroservice_RMQHandler::ReadObjectFromRequest(nsMicroservice_Iface::IRequest* pti_Request,msrapidjson::Document& t_ObjectDoc)
bool cMicroservice_RMQHandler::ReadObjectFromRequest(nsMicroservice_Iface::IRequest* pti_Request,rapidjson::Document& t_ObjectDoc)
{ {
const char* pba_Content = pti_Request->GetContent(); const char* pba_Content = pti_Request->GetContent();
if (pba_Content) if (pba_Content)
...@@ -195,7 +231,7 @@ bool cMicroservice_RMQHandler::ReadObjectFromRequest(nsMicroservice_Iface::IRequ ...@@ -195,7 +231,7 @@ bool cMicroservice_RMQHandler::ReadObjectFromRequest(nsMicroservice_Iface::IRequ
* @param conn * @param conn
* @return * @return
*/ */
cMicroservice_Enums::eMethod cMicroservice_RMQHandler::GetMethod(cRMQ_MessageRest* pc_Message) cMicroservice_Enums::eMethod cMicroservice_RMQHandler::GetMethod(cRMQ_Message* pc_Message)
{ {
cMicroservice_Enums::eMethod e_Method = cMicroservice_Enums::eMaxMethods; cMicroservice_Enums::eMethod e_Method = cMicroservice_Enums::eMaxMethods;
for (int i = 0; i < cMicroservice_Enums::eMaxMethods; i++) for (int i = 0; i < cMicroservice_Enums::eMaxMethods; i++)
......
...@@ -13,12 +13,11 @@ ...@@ -13,12 +13,11 @@
#include <stddef.h> #include <stddef.h>
#include <writer.h> #include <writer.h>
#include <stringbuffer.h> #include <stringbuffer.h>
#include <handlers/Microservice_RestHandler.h> #include "Microservice_RestHandler.h"
class cMicroservice_RequestContext; class cMicroservice_RequestContext;
class cRMQ_MessageRest; class cRMQ_Message;
class cMicroservice_RMQHandler : public nsMicroservice_Iface::IContainer class cMicroservice_RMQHandler : public nsMicroservice_Iface::IContainer
{ {
...@@ -26,12 +25,13 @@ private: ...@@ -26,12 +25,13 @@ private:
JsonStringWriter *mpc_Writer; JsonStringWriter *mpc_Writer;
rapidjson::StringBuffer* mpc_Buffer; rapidjson::StringBuffer* mpc_Buffer;
std::string apiContextPath; std::string apiContextPath;
cMicroservice_BaseHandler* mpc_Handler; Microservice_RestHandler* mpc_Handler;
nsMicroservice_Iface::ILogger* mpc_Logger;
cMicroservice_RequestContext* mpc_RequestContext; cMicroservice_RequestContext* mpc_RequestContext;
char mba_Buff[nsMicroservice_Constants::MAX_URI_LENGTH]; char mba_Buff[nsMicroservice_Constants::MAX_URI_LENGTH];
char mba_ErrorBuff[nsMicroservice_Constants::MAX_ERROR_BUFF_URI_LENGTH]; char mba_ErrorBuff[nsMicroservice_Constants::MAX_ERROR_BUFF_URI_LENGTH];
cMicroservice_Enums::eMethod GetMethod(cRMQ_MessageRest* pc_Message); cMicroservice_Enums::eMethod GetMethod(cRMQ_Message* pc_Message);
// inlines // inlines
void DoGet(cMicroservice_RequestContext* pc_ReqCtx) { mpc_Handler->DoRead(pc_ReqCtx); } void DoGet(cMicroservice_RequestContext* pc_ReqCtx) { mpc_Handler->DoRead(pc_ReqCtx); }
...@@ -43,27 +43,25 @@ private: ...@@ -43,27 +43,25 @@ private:
* @param mg_connection * @param mg_connection
* @return * @return
*/ */
void SetRequestContext(cRMQ_MessageRest* pc_Message); void SetRequestContext(cRMQ_Message* pc_Message);
void GetQueryParams(cRMQ_MessageRest* pc_Message); void GetQueryParams(cRMQ_Message* pc_Message);
public: public:
cMicroservice_RMQHandler(std::string apiContextPath,cMicroservice_BaseHandler* pc_Handler); cMicroservice_RMQHandler(std::string apiContextPath,Microservice_RestHandler* pc_Handler);
void withLogger(nsMicroservice_Iface::ILogger* pc_Logger) { this->mpc_Logger = pc_Logger; }
void HandleRequest(cRMQ_MessageRest* message); void HandleRequest(cRMQ_Message* message);
void SendErrorResp(nsMicroservice_Iface::IResponse* pti_Response,std::string error); void SendErrorResp(nsMicroservice_Iface::IResponse* pti_Response,std::string error);
void WriteObjectToResponse(nsMicroservice_Iface::IResponse* pti_Response,rapidjson::Document& t_ObjectDoc); void WriteObjectToResponse(nsMicroservice_Iface::IResponse* pti_Response,rapidjson::Document& t_ObjectDoc);
void WriteObjectToResponse(nsMicroservice_Iface::IResponse* pti_Response,cMicroservice_BaseRestResponse& t_BaseRestResponse);
void WriteStringToResponse(nsMicroservice_Iface::IResponse* pti_Response,const char* pba_Doc); void WriteStringToResponse(nsMicroservice_Iface::IResponse* pti_Response,const char* pba_Doc);
bool ReadObjectFromRequest(nsMicroservice_Iface::IRequest* pti_Request,rapidjson::Document& t_ObjectDoc); bool ReadObjectFromRequest(nsMicroservice_Iface::IRequest* pti_Request,rapidjson::Document& t_ObjectDoc);
void Publish(std::string& t_Topic, std::string& t_Message) {} // void Publish(std::string& t_Topic, std::string& t_Message) {}
void Subscribe(std::string& t_Topic, nsMicroservice_Iface::INotifyCallback& t_NotifyHandler) {} // void Subscribe(std::string& t_Topic, nsMicroservice_Iface::INotifyCallback& t_NotifyHandler) {}
void Unsubscribe(std::string& t_Topic) {} // void Unsubscribe(std::string& t_Topic) {}
void WriteObjectToResponse(nsMicroservice_Iface::IResponse* pti_Response, cMicroservice_BaseRestResponse& t_BaseRestResponse) {}
}; };
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment