1 /*** 2 * Copyright (C) Microsoft. All rights reserved. 3 * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. 4 * 5 * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ 6 * 7 * Parallel Patterns Library implementation (common code across platforms) 8 * 9 * For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk 10 * 11 * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- 12 ****/ 13 14 #include "stdafx.h" 15 16 #if !defined(_WIN32) || CPPREST_FORCE_PPLX 17 #include "pplx/pplx.h" 18 #include <atomic> 19 20 namespace pplx 21 { 22 namespace details 23 { 24 /// <summary> 25 /// Spin lock to allow for locks to be used in global scope 26 /// </summary> 27 class _Spin_lock 28 { 29 public: _Spin_lock()30 _Spin_lock() : _M_lock() {} 31 lock()32 void lock() 33 { 34 while (_M_lock.test_and_set()) 35 { 36 pplx::details::platform::YieldExecution(); 37 } 38 } 39 unlock()40 void unlock() { _M_lock.clear(); } 41 42 private: 43 std::atomic_flag _M_lock; 44 }; 45 46 typedef ::pplx::scoped_lock<_Spin_lock> _Scoped_spin_lock; 47 } // namespace details 48 49 static struct _pplx_g_sched_t 50 { 51 typedef std::shared_ptr<pplx::scheduler_interface> sched_ptr; 52 _pplx_g_sched_tpplx::_pplx_g_sched_t53 _pplx_g_sched_t() { m_state.store(post_ctor, std::memory_order_relaxed); } 54 ~_pplx_g_sched_tpplx::_pplx_g_sched_t55 ~_pplx_g_sched_t() { m_state.store(post_dtor, std::memory_order_relaxed); } 56 get_schedulerpplx::_pplx_g_sched_t57 sched_ptr get_scheduler() 58 { 59 sched_ptr result; 60 switch (m_state.load(std::memory_order_relaxed)) 61 { 62 case post_ctor: 63 // This is the 99.9% case. 64 { 65 ::pplx::details::_Scoped_spin_lock lock(m_spinlock); 66 if (!m_scheduler) 67 { 68 m_scheduler = std::make_shared<::pplx::default_scheduler_t>(); 69 } 70 71 result = m_scheduler; 72 } // unlock 73 74 break; 75 default: 76 // This case means the global m_scheduler is not available. 77 // We spin off an individual scheduler instead. 78 result = std::make_shared<::pplx::default_scheduler_t>(); 79 break; 80 } 81 82 return result; 83 } 84 set_schedulerpplx::_pplx_g_sched_t85 void set_scheduler(sched_ptr scheduler) 86 { 87 const auto localState = m_state.load(std::memory_order_relaxed); 88 if (localState == pre_ctor || localState == post_dtor) 89 { 90 throw invalid_operation("Scheduler cannot be initialized now"); 91 } 92 93 ::pplx::details::_Scoped_spin_lock lock(m_spinlock); 94 95 if (m_scheduler) 96 { 97 throw invalid_operation("Scheduler is already initialized"); 98 } 99 100 m_scheduler = std::move(scheduler); 101 } 102 103 enum m_state_values 104 { 105 pre_ctor, 106 post_ctor, 107 post_dtor 108 }; 109 110 private: 111 std::atomic<m_state_values> m_state; 112 pplx::details::_Spin_lock m_spinlock; 113 sched_ptr m_scheduler; 114 } _pplx_g_sched; 115 get_ambient_scheduler()116_PPLXIMP std::shared_ptr<pplx::scheduler_interface> _pplx_cdecl get_ambient_scheduler() 117 { 118 return _pplx_g_sched.get_scheduler(); 119 } 120 set_ambient_scheduler(std::shared_ptr<pplx::scheduler_interface> _Scheduler)121_PPLXIMP void _pplx_cdecl set_ambient_scheduler(std::shared_ptr<pplx::scheduler_interface> _Scheduler) 122 { 123 _pplx_g_sched.set_scheduler(std::move(_Scheduler)); 124 } 125 126 } // namespace pplx 127 128 #endif 129