1 /*---------------------------------------------------------------------------* 2 Project: Horizon 3 File: fslow_SafeHandle.h 4 5 Copyright 2010 Nintendo. 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: 19964 $ 14 *---------------------------------------------------------------------------*/ 15 16 #ifndef NN_FSLOW_FSLOW_SAFEHANDLE_H_ 17 #define NN_FSLOW_FSLOW_SAFEHANDLE_H_ 18 19 #include <nn.h> 20 #include <nn/os/os_WaitableCounter.h> 21 #include <nn/util/util_NonCopyable.h> 22 #include <nn/WithInitialize.h> 23 #include <nn/os/os_CriticalSection.h> 24 25 namespace nn { namespace fslow { 26 27 /*---------------------------------------------------------------------------* 28 * ReaderWriterLockとして使用 29 * - 初期化前 : 0 30 * - 初期化後 : 1 31 * - ReaderLock : <正> インクリメント, <負> ロックは取れない 32 * - ReaderUnlock : 絶対値デクリメント 33 * - WriterLock : <正> 正負を反転し、-1 になるまで待つ 34 *---------------------------------------------------------------------------*/ 35 class SafeReferenceCounter : private nn::util::NonCopyable<SafeReferenceCounter> 36 { 37 private: 38 nn::os::WaitableCounter m_Counter; 39 40 struct IncrementIfNonPositive 41 { operatorIncrementIfNonPositive42 bool operator()(s32& x) const 43 { 44 if(x < 0) 45 { 46 return false; 47 } 48 else 49 { 50 ++x; 51 return true; 52 } 53 } 54 }; 55 56 struct AbsDecrement 57 { operatorAbsDecrement58 bool operator()(s32& x) const 59 { 60 if(x >= 0) 61 { 62 --x; 63 } 64 else 65 { 66 ++x; 67 } 68 return true; 69 } 70 }; 71 72 struct Negate 73 { operatorNegate74 bool operator()(s32& x) const 75 { 76 NN_TASSERT_(x > 0); 77 x = -x; 78 return true; 79 } 80 }; 81 82 public: 83 SafeReferenceCounter()84 SafeReferenceCounter() 85 { 86 *m_Counter = 0; 87 } 88 SafeReferenceCounter(nn::WithInitialize)89 SafeReferenceCounter(nn::WithInitialize) 90 { 91 *m_Counter = 1; 92 } 93 Initialize()94 void Initialize() 95 { 96 NN_TASSERT_(!IsInitialized()); 97 *m_Counter = 1; 98 } 99 Increment()100 bool Increment() 101 { 102 // ReaderLockを取る 103 NN_TASSERT_(IsInitialized()); 104 IncrementIfNonPositive f; 105 return m_Counter->AtomicUpdateConditional(f); 106 } 107 Decrement()108 void Decrement() 109 { 110 // ReaderUnlockする 111 NN_TASSERT_(IsInitialized()); 112 AbsDecrement f; 113 m_Counter->AtomicUpdateConditional(f); 114 if (*m_Counter == -1) 115 { 116 m_Counter.SignalAll(); 117 } 118 } 119 IsInitialized()120 bool IsInitialized() const 121 { 122 return *m_Counter != 0; 123 } 124 IsValid()125 bool IsValid() const 126 { 127 NN_TASSERT_(IsInitialized()); 128 return *m_Counter > 0; 129 } 130 IsLocked()131 bool IsLocked() const 132 { 133 NN_TASSERT_(IsInitialized()); 134 return (*m_Counter < -1) || (1 < *m_Counter); 135 } 136 PrepareFinalization()137 void PrepareFinalization() 138 { 139 // WriterLockの準備 (ReaderLockを取れなくする) 140 NN_TASSERT_(IsValid()); 141 Negate f; 142 m_Counter->AtomicUpdateConditional(f); 143 } 144 IsFinalizationPrepared()145 bool IsFinalizationPrepared() const 146 { 147 NN_TASSERT_(IsInitialized()); 148 return *m_Counter < 0; 149 } 150 TryFinalize()151 bool TryFinalize() 152 { 153 return m_Counter->CompareAndSwap(-1, 0) == 0; 154 } 155 Finalize()156 void Finalize() 157 { 158 // WriterLockが取れるまで待って終了 159 if(IsInitialized()) 160 { 161 if(IsValid()) 162 { 163 Negate f; 164 m_Counter->AtomicUpdateConditional(f); 165 } 166 m_Counter.WaitIfLessThan(-1); 167 *m_Counter = 0; 168 } 169 } 170 }; 171 172 173 /*---------------------------------------------------------------------------* 174 * ハンドル 175 *---------------------------------------------------------------------------*/ 176 class SafeHandleBase 177 { 178 protected: 179 bit32 m_Data[2]; 180 181 public: SafeHandleBase()182 SafeHandleBase() { Invalidate(); } 183 Invalidate()184 void Invalidate() { m_Data[0] = m_Data[1] = 0; } 185 IsValid()186 bool IsValid() const { return (m_Data[0] != 0) || (m_Data[1] != 0); } 187 188 operator bool() const { return IsValid(); } 189 bool operator!() const { return !IsValid(); } 190 bool operator==(const SafeHandleBase& rhs) const { return (m_Data[0] == rhs.m_Data[0]) && (m_Data[1] == rhs.m_Data[1]); } 191 bool operator!=(const SafeHandleBase& rhs) const { return (m_Data[0] != rhs.m_Data[0]) || (m_Data[1] != rhs.m_Data[1]); } 192 }; 193 194 /*---------------------------------------------------------------------------* 195 * アーカイブ用ハンドル 196 * - 永続ハンドル : <w0>オブジェクトアドレス, <w1>常に0 197 * - 非永続ハンドル : <w0[0:7]>固定値, <w0[8:31] w1[0:31]>インクリメント可能な固有値 198 *---------------------------------------------------------------------------*/ 199 class SafeHandle : public SafeHandleBase 200 { 201 public: SafeHandle()202 SafeHandle() {} SafeHandle(bit8 index)203 SafeHandle(bit8 index) { Initialize(index); } SafeHandle(void * pObject)204 SafeHandle(void* pObject) { Initialize(pObject); } 205 206 // 永続ハンドルとして初期化 Initialize(void * pObject)207 void Initialize(void* pObject) 208 { 209 NN_TASSERT_(!IsValid()); 210 m_Data[0] = reinterpret_cast<bit32>(pObject); 211 } 212 213 // 非永続ハンドルとして初期化 Initialize(bit8 fixedValue)214 void Initialize(bit8 fixedValue) 215 { 216 NN_TASSERT_(!IsValid()); 217 m_Data[0] = fixedValue; 218 m_Data[1] = 1; // 永続ハンドルとの区別 219 } 220 Finalize()221 void Finalize() { Invalidate(); } 222 IsPermanent()223 bool IsPermanent() const { return m_Data[1] == 0; } 224 GetObject()225 void* GetObject() const 226 { 227 NN_TASSERT_(IsPermanent()); 228 return reinterpret_cast<void*>(m_Data[0]); 229 } 230 GetFixedValue()231 bit8 GetFixedValue() const 232 { 233 NN_TASSERT_(!IsPermanent()); 234 return static_cast<bit8>(m_Data[0] & 0xFF); 235 } 236 237 SafeHandle& operator++(); 238 }; 239 240 // 無効ハンドル 241 typedef const SafeHandle InvalidSafeHandle; 242 243 244 /*---------------------------------------------------------------------------* 245 * アーカイブ用エントリ 246 *---------------------------------------------------------------------------*/ 247 class SafeHandleTableEntry 248 { 249 public: 250 static const s32 INVALID_INDEX = -1; 251 static const s32 MAX_INDEX = 255; 252 SafeHandleTableEntry()253 SafeHandleTableEntry() : 254 m_pObject(0), 255 m_DependencyIndex(0) {} ~SafeHandleTableEntry()256 ~SafeHandleTableEntry() {} 257 258 void Initialize(s32 index); 259 void Finalize(); 260 SafeHandle Activate(void* pObject, s32 dependencyIndex=INVALID_INDEX); 261 void Deactivate(); 262 263 bool Lock(); 264 void Unlock(); 265 void LockForUnregister(); GetObject()266 void* GetObject() { NN_TASSERT_(IsLocked()); return m_pObject; } 267 IsInitialized()268 bool IsInitialized() const { return m_Handle.IsValid(); } IsActivated()269 bool IsActivated() const { return m_AccessLockCounter.IsInitialized(); } HasHandle(const SafeHandle & handle)270 bool HasHandle(const SafeHandle& handle) const { return IsInitialized() && (handle == m_Handle); } IsLocked()271 bool IsLocked() const { return m_AccessLockCounter.IsValid(); } 272 GetHandle()273 SafeHandle GetHandle() const { return IsActivated() ? m_Handle : InvalidSafeHandle(); } HasDependencyIndex()274 bool HasDependencyIndex() const { return m_DependencyIndex != m_Handle.GetFixedValue(); } GetDependencyIndex()275 s32 GetDependencyIndex() const { return HasDependencyIndex() ? m_DependencyIndex : INVALID_INDEX; } 276 277 private: 278 SafeHandle m_Handle; 279 void* m_pObject; 280 SafeReferenceCounter m_AccessLockCounter; 281 bit8 m_DependencyIndex; // 自分のインデックス値 == 依存なし 282 NN_PADDING3; 283 }; 284 285 /*---------------------------------------------------------------------------* 286 * アーカイブ用ハンドルテーブル 287 *---------------------------------------------------------------------------*/ 288 class SafeHandleTable 289 { 290 public: SafeHandleTable()291 SafeHandleTable() : m_NumEntry(0), m_pEntryBuffer(0) {} ~SafeHandleTable()292 ~SafeHandleTable() {} 293 294 void Initialize(SafeHandleTableEntry* pEntryBuffer, s32 NumEntry); 295 void Finalize(); 296 IsInitialized()297 bool IsInitialized() const { return m_pEntryBuffer != 0; } 298 299 SafeHandle Register(void* pObject, SafeHandle dependencyHandle=InvalidSafeHandle()); 300 void Unregister(SafeHandle handle); 301 LockHandle(SafeHandle handle)302 void* LockHandle(SafeHandle handle) 303 { 304 SafeHandleTableEntry* entry = FindEntry(handle); 305 return LockEntry(entry, handle) ? entry->GetObject() : 0; 306 } 307 UnlockHandle(SafeHandle handle)308 void UnlockHandle(SafeHandle handle) { return UnlockEntry(FindEntry(handle)); } 309 310 friend class Accessor; 311 class Accessor 312 { 313 private: 314 SafeHandleTableEntry* m_pEntry; 315 316 protected: 317 GetPointer()318 void* GetPointer() const { return m_pEntry ? m_pEntry->GetObject() : 0; } 319 320 public: Accessor(SafeHandleTable & table,SafeHandle handle)321 Accessor(SafeHandleTable& table, SafeHandle handle) 322 { 323 SafeHandleTableEntry* entry = table.FindEntry(handle); 324 this->m_pEntry = LockEntry(entry, handle) ? entry : 0; 325 } 326 ~Accessor()327 ~Accessor() 328 { 329 if (m_pEntry) 330 { 331 UnlockEntry(m_pEntry); 332 } 333 } 334 335 operator bool() const { return GetPointer() != 0; } 336 bool operator!() const { return GetPointer() == 0; } 337 }; 338 339 private: 340 341 static bool LockEntry(SafeHandleTableEntry* pEntry, SafeHandle handle); 342 static void UnlockEntry(SafeHandleTableEntry* pEntry); 343 SafeHandleTableEntry* FindEntry(SafeHandle handle) const; 344 GetEntry(s32 index)345 SafeHandleTableEntry* GetEntry(s32 index) const 346 { 347 return (index < m_NumEntry) ? (m_pEntryBuffer + index) : 0; 348 } 349 350 s32 m_NumEntry; 351 SafeHandleTableEntry* m_pEntryBuffer; 352 mutable nn::os::CriticalSection m_CriticalSection; 353 354 SafeHandleTableEntry* FindFreeEntry() const; 355 void UnregisterRecursive(s32 index); 356 }; 357 358 //--- Tamplate 359 template <class TObject, s32 TNumEntry> 360 class SafeArchiveHandleTable 361 { 362 public: 363 typedef SafeHandle Handle; 364 typedef SafeHandleTableEntry Entry; 365 typedef SafeHandleTable Table; 366 SafeArchiveHandleTable()367 SafeArchiveHandleTable() { m_Table.Initialize(m_Entry, TNumEntry); } 368 ~SafeArchiveHandleTable()369 ~SafeArchiveHandleTable() { m_Table.Finalize(); } 370 371 Handle Register(TObject* pObject, Handle dependencyHandle=InvalidSafeHandle()) 372 { 373 return m_Table.Register(pObject, dependencyHandle); 374 } 375 Unregister(SafeHandle handle)376 void Unregister(SafeHandle handle) 377 { 378 m_Table.Unregister(handle); 379 } 380 LockHandle(SafeHandle handle)381 TObject* LockHandle(SafeHandle handle) 382 { 383 return reinterpret_cast<TObject*>(m_Table.LockHandle(handle)); 384 } 385 UnlockHandle(SafeHandle handle)386 void UnlockHandle(SafeHandle handle) 387 { 388 m_Table.UnlockHandle(handle); 389 } 390 HasHandle(SafeHandle handle)391 bool HasHandle(SafeHandle handle) 392 { 393 return (m_Table.FindEntry(handle) != 0); 394 } 395 396 private: 397 Entry m_Entry[TNumEntry]; // 別途確保することになるかもしれない 398 Table m_Table; 399 FindEntry(Handle handle)400 Entry* FindEntry(Handle handle) const { return m_Table.FindEntry(handle); } 401 402 public: 403 404 class Accessor : public SafeHandleTable::Accessor 405 { 406 public: Accessor(SafeArchiveHandleTable & table,Handle handle)407 Accessor(SafeArchiveHandleTable& table, Handle handle) : SafeHandleTable::Accessor(table.m_Table, handle) {} 408 GetPointer()409 TObject* GetPointer() { return static_cast<TObject*>(SafeHandleTable::Accessor::GetPointer()); } 410 411 TObject* operator->() { return GetPointer(); } 412 TObject& operator*() { return *GetPointer(); } 413 }; 414 415 }; 416 417 418 }} 419 420 #endif 421