/*** * ==++== * * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * ==--== * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ * * Parallel Patterns Library implementation (common code across platforms) * * For the latest on this and related APIs, please see http://casablanca.codeplex.com. * * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- ****/ #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 { /// /// Spin lock to allow for locks to be used in global scope /// 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 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_cdecl get_ambient_scheduler() { return _pplx_g_sched.get_scheduler(); } _PPLXIMP void _pplx_cdecl set_ambient_scheduler(std::shared_ptr _Scheduler) { _pplx_g_sched.set_scheduler(std::move(_Scheduler)); } } // namespace pplx #endif