1 /*---------------------------------------------------------------------------* 2 Project: Horizon 3 File: fslow_SafeHandle.h 4 5 Copyright 2010 Nintendo. All rights reserved. 6 These coded instructions, statements, and computer programs contain 7 proprietary information of Nintendo of America Inc. and/or Nintendo 8 Company Ltd., and are protected by Federal copyright law. They may 9 not be disclosed to third parties or copied or duplicated in any form, 10 in whole or in part, without the prior written consent of Nintendo. 11 $Rev: 19964 $ 12 *--------------------------------------------------------------------------- 13 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 * Use as ReaderWriterLock 29 * Pre-initialization : 0 30 * - After-initialization : 1 31 * - ReaderLock : (positive) increment, (negative) do not unlock 32 * - ReaderUnlock : Absolute value decrement 33 * - WriterLock : (positive) reverse sign and wait until -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 // Remove ReaderLock 103 NN_TASSERT_(IsInitialized()); 104 IncrementIfNonPositive f; 105 return m_Counter->AtomicUpdateConditional(f); 106 } 107 Decrement()108 void Decrement() 109 { 110 // Do 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 // Prepare WriterLock (Disables removal of 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 // Wait until WriterLock is removed, and then terminate 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 * Handle 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 * Archive handle 196 * - Permanent handle: <w0> object address, <w1> always 0 197 * - Non-permanent handle: <w0[0:7]> fixed value, <w0[8:31] w1[0:31]> incrementable unique value 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 // Initialization as permanent handle Initialize(void * pObject)207 void Initialize(void* pObject) 208 { 209 NN_TASSERT_(!IsValid()); 210 m_Data[0] = reinterpret_cast<bit32>(pObject); 211 } 212 213 // Initialization as non-permanent handle Initialize(bit8 fixedValue)214 void Initialize(bit8 fixedValue) 215 { 216 NN_TASSERT_(!IsValid()); 217 m_Data[0] = fixedValue; 218 m_Data[1] = 1; // Distinguish from permanent handle 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 // invalid handle 241 typedef const SafeHandle InvalidSafeHandle; 242 243 244 /*---------------------------------------------------------------------------* 245 * Archive entry 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; // Own index value == no dependency 282 NN_PADDING3; 283 }; 284 285 /*---------------------------------------------------------------------------* 286 * Archive handle table 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 //--- Template 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]; // May end up allocating separately 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