1 /*---------------------------------------------------------------------------*
2   Project:  Horizon
3   File:     fslow_SafeHandle.h
4 
5   Copyright (C)2009-2012 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: 47340 $
14  *---------------------------------------------------------------------------*/
15 
16 #ifndef NN_FSLOW_FSLOW_SAFE_HANDLE_H_
17 #define NN_FSLOW_FSLOW_SAFE_HANDLE_H_
18 
19 #include <nn/types.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