1 /*---------------------------------------------------------------------------* 2 Project: Horizon 3 File: os_InterCoreCriticalSection.h 4 5 Copyright (C)2009 Nintendo Co., Ltd. All rights reserved. 6 7 These coded instructions, statements, and computer programs contain 8 proprietary information of Nintendo of America Inc. and/or Nintendo 9 Company Ltd., and are protected by Federal copyright law. They may 10 not be disclosed to third parties or copied or duplicated in any form, 11 in whole or in part, without the prior written consent of Nintendo. 12 13 $Rev: 31411 $ 14 *---------------------------------------------------------------------------*/ 15 16 /*! :private 17 @file 18 @brief InterCoreCriticalSection に関する API の宣言 19 20 :include nn/os.h 21 */ 22 23 #ifndef NN_OS_OS_INTERCORE_CRITICALSECTION_H_ 24 #define NN_OS_OS_INTERCORE_CRITICALSECTION_H_ 25 26 #include <nn/os/os_MemoryBarrierSelect.h> 27 #include <nn/os/os_WaitableCounter.h> 28 #include <nn/assert.h> 29 #include <nn/WithInitialize.h> 30 #include <nn/util/detail/util_ScopedLockImpl.h> 31 #include <nn/hw/ARM/reg_access.h> 32 33 #ifdef __cplusplus 34 35 namespace nn { namespace os { 36 37 /*! :private 38 @brief マルチコア間での排他制御を行うためのクラスです。 39 40 基本的な使い方などについては @ref nn::os::CriticalSection を参照してください。 41 */ 42 43 class InterCoreCriticalSection : private nn::util::NonCopyable<InterCoreCriticalSection> 44 { 45 private: 46 struct ReverseIfPositiveUpdater 47 { operatorReverseIfPositiveUpdater48 bool operator()(s32& x) 49 { 50 if( x > 0 ) 51 { 52 x = -x; 53 return true; 54 } 55 else 56 { 57 return false; 58 } 59 } 60 }; 61 62 struct ReverseUpdater 63 { 64 s32 afterUpdate; operatorReverseUpdater65 bool operator()(s32& x) 66 { 67 x = -x; 68 afterUpdate = x; 69 return true; 70 } 71 }; 72 73 public: 74 75 static const bool CAN_LOCK_RECURSIVELY = true; 76 77 /*! :private 78 @brief オブジェクトを構築します。 79 80 初期化しないコンストラクタと、初期化するコンストラクタが用意されています。 81 82 初期化しない場合、使用する前に、@ref nn::os::InterCoreCriticalSection::Initialize を呼んで明示的に初期化する必要があります。 83 */ InterCoreCriticalSection()84 InterCoreCriticalSection() : m_ThreadUniqueValue(GetInvalidThreadUniqueValue()), m_LockCount(-1) {} 85 86 /*! :private 87 @brief オブジェクトを構築し、初期化を行います。 88 */ InterCoreCriticalSection(const nn::WithInitialize &)89 InterCoreCriticalSection(const nn::WithInitialize&) { Initialize(); } 90 91 /*! :private 92 @brief オブジェクトを初期化します。 93 94 @return 無し。 95 */ Initialize()96 void Initialize() 97 { 98 *m_Counter = 1; 99 m_ThreadUniqueValue = GetInvalidThreadUniqueValue(); 100 m_LockCount = 0; 101 } 102 103 /*! :private 104 @brief オブジェクトの初期化を試みます。 105 106 @return 処理結果を返します。 107 */ TryInitialize()108 nn::Result TryInitialize() 109 { 110 Initialize(); 111 return ResultSuccess(); 112 } 113 114 /*! :private 115 @brief クリティカルセクションを破棄します。 116 117 デストラクタから自動的に呼び出されますが、明示的に呼ぶこともできます。 118 119 @return 無し。 120 */ Finalize()121 void Finalize() { m_LockCount = -1; } 122 123 /*! :private 124 @brief デストラクタです。 125 */ ~InterCoreCriticalSection()126 ~InterCoreCriticalSection() {} 127 128 /*! :private 129 @brief ロックして他のスレッドがクリティカルセクションに進入するのを防ぎます。ブロックします。 130 131 @return 無し。 132 */ Enter()133 void Enter() 134 { 135 NN_TASSERT_(IsInitialized()); 136 // 自スレッドがクリティカルセクションに進入していなければ 137 // クリティカルセクションに進入を試みます。 138 if (!LockedByCurrentThread() && !TryEnterImpl()) 139 { 140 EnterImpl(); 141 } 142 ++this->m_LockCount; 143 } 144 145 /*! :private 146 @brief ロックして他のスレッドがクリティカルセクションに進入するのを防ぎます。ブロックしません。 147 148 @return ロックに成功したかを返します。 149 */ TryEnter()150 bool TryEnter() 151 { 152 NN_TASSERT_(IsInitialized()); 153 // 自スレッドがクリティカルセクションに進入していなければ 154 // クリティカルセクションに進入を試みます。 155 if (LockedByCurrentThread() || TryEnterImpl()) 156 { 157 ++this->m_LockCount; 158 return true; 159 } 160 else 161 { 162 return false; 163 } 164 } 165 166 /*! :private 167 @brief アンロックして他のスレッドがクリティカルセクションに進入できるようにします。 168 169 @return 無し。 170 */ Leave()171 void Leave() 172 { 173 NN_TASSERT_(IsInitialized()); 174 NN_TASSERTMSG_(LockedByCurrentThread() && m_LockCount > 0, "InterCoreCriticalSection is not entered on the current thread."); 175 if (--this->m_LockCount == 0) 176 { 177 NN_TASSERTMSG_( *m_Counter < 0 , "InterCoreCriticalSection is not entered."); 178 179 // クリティカルセクションを取得中のスレッド ID をクリアします。 180 m_ThreadUniqueValue = GetInvalidThreadUniqueValue(); 181 182 // カウンタの符号を正に設定することでロックを解除します。 183 ReverseUpdater updater; 184 m_Counter->AtomicUpdateConditional(updater); 185 186 DataSynchronizationBarrier(); 187 188 // 待機している最も優先度の高いスレッドを起床します。 189 if( updater.afterUpdate > 1 ) 190 { 191 m_Counter.Signal(1); 192 } 193 } 194 } 195 196 /*! :private 197 @class nn::os::InterCoreCriticalSection::ScopedLock 198 199 @brief オブジェクトの生成時からオブジェクトの存在するスコープを抜けるまで間クリティカルセクションに入ります。 200 */ 201 class ScopedLock; 202 IsLocked()203 bool IsLocked() const 204 { 205 return (*m_Counter < 0); 206 } 207 208 private: 209 210 void EnterImpl(); 211 TryEnterImpl()212 bool TryEnterImpl() 213 { 214 ReverseIfPositiveUpdater updater; 215 bool ret = m_Counter->AtomicUpdateConditional(updater); 216 DataSynchronizationBarrier(); 217 if (ret) 218 { 219 // クリティカルセクションの進入に成功すれば 220 // カウンタの符号が正から負に変わります。 221 222 NN_TASSERT_(m_LockCount == 0); 223 224 // クリティカルセクションを取得したスレッド ID を保存します。 225 this->m_ThreadUniqueValue = GetThreadUniqueValue(); 226 return true; 227 } 228 else 229 { 230 return false; 231 } 232 } 233 234 // TODO: ARM に移すことを推奨します。 235 #ifdef NN_PROCESSOR_ARM946ES GetThreadUniqueValue()236 static uptr GetThreadUniqueValue() 237 { 238 return nn::os::CTR::ARM946ES::GetThreadId(); 239 } GetInvalidThreadUniqueValue()240 static uptr GetInvalidThreadUniqueValue() 241 { 242 return static_cast<uptr>(-1); 243 } 244 #else GetThreadUniqueValue()245 static uptr GetThreadUniqueValue() 246 { 247 uptr v; 248 HW_GET_CP15_THREAD_ID_USER_READ_ONLY(v); 249 return v; 250 } GetInvalidThreadUniqueValue()251 static uptr GetInvalidThreadUniqueValue() 252 { 253 return 0; 254 } 255 #endif 256 LockedByCurrentThread()257 bool LockedByCurrentThread() const 258 { 259 return GetThreadUniqueValue() == m_ThreadUniqueValue; 260 } 261 262 private: 263 nn::os::WaitableCounter m_Counter; 264 uptr m_ThreadUniqueValue; 265 s32 m_LockCount; IsInitialized()266 bool IsInitialized() const { return m_LockCount >= 0; } 267 }; 268 269 NN_UTIL_DETAIL_DEFINE_SCOPED_LOCK(InterCoreCriticalSection, Enter(), Leave()); 270 271 }} // namespace nn::os 272 273 #endif // __cplusplus 274 275 // 以下、C 用宣言 276 277 #include <nn/util/detail/util_CLibImpl.h> 278 279 #define NN_OS_INTERCORE_CRITICALSECTION_SIZE 12 280 281 NN_UTIL_DETAIL_CLIBIMPL_DEFINE_BUFFER_CLASS(nnosInterCoreCriticalSection, nn::os::InterCoreCriticalSection, NN_OS_INTERCORE_CRITICALSECTION_SIZE, u32); 282 283 NN_EXTERN_C void nnosInterCoreCriticalSectionInitialize(nnosInterCoreCriticalSection* this_); 284 285 NN_EXTERN_C bool nnosInterCoreCriticalSectionTryInitialize(nnosInterCoreCriticalSection* this_); 286 287 NN_EXTERN_C void nnosInterCoreCriticalSectionEnter(nnosInterCoreCriticalSection* this_); 288 289 NN_EXTERN_C bool nnosInterCoreCriticalSectionTryEnter(nnosInterCoreCriticalSection* this_); 290 291 NN_EXTERN_C void nnosInterCoreCriticalSectionLeave(nnosInterCoreCriticalSection* this_); 292 293 NN_EXTERN_C void nnosInterCoreCriticalSectionFinalize(nnosInterCoreCriticalSection* this_); 294 295 #endif 296