1 /*---------------------------------------------------------------------------*
2   Project:  Horizon
3   File:     fslow_SafeHandle.cpp
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: 46347 $
14  *---------------------------------------------------------------------------*/
15 
16 #include <nn/fslow/fslow_SafeHandle.h>
17 
18 
19 namespace nn { namespace fslow {
20 
21 
22 /*===========================================================================*
23  *  SafeHandle
24  *===========================================================================*/
25 
26 /*---------------------------------------------------------------------------*
27  *  operator++
28  *    Not changed because the lower 8 bits of w0 are a fixed value
29  *---------------------------------------------------------------------------*/
operator ++()30 SafeHandle& SafeHandle::operator++()
31 {
32     NN_TASSERT_(IsValid());
33     NN_TASSERT_(!IsPermanent());
34 
35     m_Data[0] += 0x100;
36 
37     if (((m_Data[0] & 0xFFFFFF00) == 0) && (++m_Data[1] == 0))
38     {
39         NN_TPANIC_("No more archive handle.");
40     }
41     return *this;
42 }
43 
44 
45 
46 /*===========================================================================*
47  *  SafeHandleTableEntry
48  *===========================================================================*/
49 
50 /*---------------------------------------------------------------------------*
51   Name:         SafeHandleTableEntry::Initialize
52   Description:  Initialization
53   Arguments:    index   Index of this entry
54   Returns:      None.
55  *---------------------------------------------------------------------------
56 
57 
58 */
Initialize(s32 index)59 void SafeHandleTableEntry::Initialize(s32 index)
60 {
61     NN_TASSERT_(!IsInitialized());
62     NN_TASSERT_(index <= MAX_INDEX);
63 
64     m_DependencyIndex = static_cast<bit8>(index);
65     m_Handle.Initialize(index);
66 }
67 
68 /*---------------------------------------------------------------------------*
69   Name:         SafeHandleTableEntry::Finalize
70   Description:  Clean up
71   Arguments:    None.
72   Returns:      None.
73   Note:         Because the handle value is also reset, called when the handle table itself is deleted.
74 
75  *---------------------------------------------------------------------------
76 
77 
78 
79 */
Finalize()80 void SafeHandleTableEntry::Finalize()
81 {
82     NN_TASSERT_(IsInitialized());
83 
84     if(IsActivated())
85     {
86         Deactivate();
87     }
88 
89     m_DependencyIndex = 0;
90     m_Handle.Invalidate();
91 }
92 
93 /*---------------------------------------------------------------------------*
94   Name:         SafeHandleTableEntry::Activate
95   Description:  Enables this entry
96   Arguments:    pObject: Archive object to register
97                 Index of the entry dependent on dependencyIndex
98   Returns:      Returns a handle
99  *---------------------------------------------------------------------------
100 
101 
102 */
Activate(void * pObject,s32 dependencyIndex)103 SafeHandle SafeHandleTableEntry::Activate(void* pObject, s32 dependencyIndex/*=INVALID_INDEX*/)
104 {
105     NN_TASSERT_(IsInitialized() && !IsActivated());
106     NN_TASSERT_(pObject);
107 
108     m_pObject = pObject;
109 
110     if(dependencyIndex != INVALID_INDEX)
111     {
112         m_DependencyIndex = static_cast<bit8>(dependencyIndex);
113     }
114 
115     ++m_Handle; // Updates the handle-specific value
116 
117     m_AccessLockCounter.Initialize();
118     return m_Handle;
119 }
120 
121 /*---------------------------------------------------------------------------*
122   Name:         SafeHandleTableEntry::Deactivate
123   Description:  Disables this entry
124   Arguments:    None.
125   Returns:      None.
126  *---------------------------------------------------------------------------
127 
128 
129 */
Deactivate()130 void SafeHandleTableEntry::Deactivate()
131 {
132     NN_TASSERT_(IsActivated());
133     NN_TASSERT_(m_AccessLockCounter.IsFinalizationPrepared());
134 
135     m_pObject           = 0;
136     m_DependencyIndex   = m_Handle.GetFixedValue();
137 
138     m_AccessLockCounter.Finalize();
139 }
140 
141 /*---------------------------------------------------------------------------*
142   Name:         SafeHandleTableEntry::Lock
143   Description:  Locks this entry
144                 - Remove ReaderLock
145   Arguments:    None.
146   Returns:      Returns whether lock was done
147  *---------------------------------------------------------------------------
148 
149 
150 */
Lock()151 bool SafeHandleTableEntry::Lock()
152 {
153     NN_TASSERT_(IsActivated());
154     return m_AccessLockCounter.Increment();
155 }
156 
157 /*---------------------------------------------------------------------------*
158   Name:         SafeHandleTableEntry::Unlock
159   Description:  Unlocks this entry
160                 - Releases ReaderLock
161   Arguments:    None.
162   Returns:      None.
163  *---------------------------------------------------------------------------
164 
165 
166 */
Unlock()167 void SafeHandleTableEntry::Unlock()
168 {
169     NN_TASSERT_(IsActivated());
170     m_AccessLockCounter.Decrement();
171 }
172 
173 /*---------------------------------------------------------------------------*
174   Name:         SafeHandleTableEntry::LockForUnregister
175   Description:  Unlocks for registration deletion
176                 - Prepares WriterLock
177   Arguments:    None.
178   Returns:      None.
179  *---------------------------------------------------------------------------
180 
181 
182 */
LockForUnregister()183 void SafeHandleTableEntry::LockForUnregister()
184 {
185     NN_TASSERT_(IsActivated());
186     m_AccessLockCounter.PrepareFinalization();
187 }
188 
189 
190 
191 /*===========================================================================*
192  *  SafeHandleTable
193  *===========================================================================*/
194 
195 /*---------------------------------------------------------------------------*
196   Name:         SafeHandleTable::Initialize
197   Description:  Initialization
198   Arguments:    pEntryBiffer: Buffer for entry table
199                 NumEntry: Number of entries that can be stored in the buffer
200   Returns:      None.
201  *---------------------------------------------------------------------------
202 
203 
204 */
Initialize(SafeHandleTableEntry * pEntryBuffer,s32 NumEntry)205 void SafeHandleTable::Initialize(SafeHandleTableEntry* pEntryBuffer, s32 NumEntry)
206 {
207     NN_TASSERT_(!IsInitialized());
208     NN_TASSERT_(pEntryBuffer);
209     NN_TASSERT_(NumEntry <= SafeHandleTableEntry::MAX_INDEX);
210 
211     for(s32 i = 0; i < NumEntry; ++i)
212     {
213         // CHECK: Is placement new received with void* better?
214         pEntryBuffer[i].Initialize(i);
215     }
216 
217     m_NumEntry      = NumEntry;
218     m_pEntryBuffer  = pEntryBuffer;
219     m_CriticalSection.Initialize();
220 }
221 
222 /*---------------------------------------------------------------------------*
223   Name:         SafeHandleTable::Finalize
224   Description:  Clean up
225   Arguments:    None.
226   Returns:      None.
227  *---------------------------------------------------------------------------
228 
229 
230 */
Finalize()231 void SafeHandleTable::Finalize()
232 {
233     if(!IsInitialized())
234     {
235         return;
236     }
237 
238     for(s32 i = 0; i < m_NumEntry; ++i)
239     {
240         m_pEntryBuffer[i].Finalize();
241     }
242 
243     m_NumEntry      = 0;
244     m_pEntryBuffer  = 0;
245 }
246 
247 /*---------------------------------------------------------------------------*
248   Name:         SafeHandleTable::Register
249   Description:  Registers archive objects
250   Arguments:    pObject: Archive object to register
251                 dependencyHandle: Handle of the dependent archive
252   Returns:      Returns a handle
253   Note:         Be sure to call after locking the dependent archive.
254  *---------------------------------------------------------------------------
255 
256 
257 
258 */
Register(void * pObject,SafeHandle dependencyHandle)259 SafeHandle SafeHandleTable::Register(void* pObject, SafeHandle dependencyHandle/*=InvalidSafeHandle()*/)
260 {
261     NN_TASSERT_(IsInitialized());
262 
263     nn::os::CriticalSection::ScopedLock lk(m_CriticalSection);
264 
265     s32 dependencyIndex;
266 
267     if(dependencyHandle.IsValid())
268     {
269         // Lock the dependent
270         dependencyIndex = dependencyHandle.GetFixedValue();
271         if(!GetEntry(dependencyIndex)->Lock())
272         {
273             return InvalidSafeHandle();
274         }
275     }
276     else
277     {
278         dependencyIndex = SafeHandleTableEntry::INVALID_INDEX;
279     }
280 
281     SafeHandleTableEntry*   pEntry = FindFreeEntry();
282     if(pEntry)
283     {
284         return pEntry->Activate(pObject, dependencyIndex);
285     }
286 
287     return InvalidSafeHandle();
288 }
289 
290 /*---------------------------------------------------------------------------*
291   Name:         SafeHandleTable::Unregister
292   Description:  Releases the registration for a archive object
293   Arguments:    handle: Handle of the archive to release registration
294   Returns:      None.
295   Note:         Also recursively removes archives dependent on oneself
296  *---------------------------------------------------------------------------
297 
298 
299 
300 */
Unregister(SafeHandle handle)301 void SafeHandleTable::Unregister(SafeHandle handle)
302 {
303     NN_TASSERT_(IsInitialized());
304 
305     nn::os::CriticalSection::ScopedLock lk(m_CriticalSection);
306 
307     if(handle.IsValid())
308     {
309         UnregisterRecursive(handle.GetFixedValue());
310     }
311 }
312 
UnregisterRecursive(s32 index)313 void SafeHandleTable::UnregisterRecursive(s32 index)
314 {
315     SafeHandleTableEntry* pEntry = GetEntry(index);
316     if(!pEntry || !pEntry->IsActivated())
317     {
318         return;
319     }
320 
321     // Do not lock more than this externally
322     pEntry->LockForUnregister();
323 
324     // There is an entry dependent on oneself
325     SafeHandleTableEntry* pEntryDependOn;
326     for(s32 i = 0; i < m_NumEntry; ++i)
327     {
328         pEntryDependOn = GetEntry(i);
329         if(pEntryDependOn->IsActivated() && (pEntryDependOn->GetDependencyIndex() == index))
330         {
331             UnregisterRecursive(i);
332         }
333     }
334 
335     // Remove lock on dependent
336     if(pEntry->HasDependencyIndex())
337     {
338         GetEntry(pEntry->GetDependencyIndex())->Unlock();
339     }
340 
341     // Disable self
342     pEntry->Deactivate();
343 }
344 
345 /*---------------------------------------------------------------------------*
346   Name:         SafeHandleTable::LockEntry
347   Description:  Lock entry
348   Arguments:    handle: Archive entry
349   Returns:      Returns whether lock was done.
350  *---------------------------------------------------------------------------
351 
352 
353 */
LockEntry(SafeHandleTableEntry * pEntry,SafeHandle handle)354 bool SafeHandleTable::LockEntry(SafeHandleTableEntry* pEntry, SafeHandle handle)
355 {
356     if(pEntry && pEntry->IsActivated())
357     {
358         if (pEntry->Lock())
359         {
360             // Even if lock was done, it does not mean that the anticipated handle was locked.
361             // Verifies that the corresponding entry was anticipated.
362             if (pEntry->HasHandle(handle))
363             {
364                 return true;
365             }
366             // When the corresponding entry does not have the expected handle, the entry lock is released because this function fails to lock.
367             //
368             pEntry->Unlock();
369         }
370     }
371 
372     return false;
373 }
374 
375 /*---------------------------------------------------------------------------*
376   Name:         SafeHandleTable::UnlockEntry
377   Description:  Release the entry lock
378   Arguments:    handle: Archive object entry
379   Returns:      None.
380  *---------------------------------------------------------------------------
381 
382 
383 */
UnlockEntry(SafeHandleTableEntry * pEntry)384 void SafeHandleTable::UnlockEntry(SafeHandleTableEntry* pEntry)
385 {
386     if(pEntry && pEntry->IsActivated())
387     {
388         pEntry->Unlock();
389     }
390     else
391     {
392         NN_TPANIC_("unknown handle");
393     }
394 }
395 
396 /*---------------------------------------------------------------------------*
397   Name:         SafeHandleTable::FindEntry
398   Description:  Searches for entries from handles
399   Arguments:    handle: Archive handle
400   Returns:      Returns the entry
401  *---------------------------------------------------------------------------
402 
403 
404 */
FindEntry(SafeHandle handle) const405 SafeHandleTableEntry* SafeHandleTable::FindEntry(SafeHandle handle) const
406 {
407     NN_TASSERT_(IsInitialized());
408 
409     nn::os::CriticalSection::ScopedLock lk(m_CriticalSection);
410 
411     if(handle.IsValid())
412     {
413         // Uses the index information since it is in the handle
414         SafeHandleTableEntry* pEntry = GetEntry(handle.GetFixedValue());
415         if(pEntry && pEntry->HasHandle(handle))
416         {
417             return pEntry;
418         }
419     }
420     return 0;
421 }
422 
423 /*---------------------------------------------------------------------------*
424   Name:         SafeHandleTable::FindFreeEntry
425   Description:  Search for empty entries
426   Arguments:    None.
427   Returns:      Returns the entry
428  *---------------------------------------------------------------------------
429 
430 
431 */
FindFreeEntry() const432 SafeHandleTableEntry* SafeHandleTable::FindFreeEntry() const
433 {
434     for (s32 i = 0; i < m_NumEntry; ++i)
435     {
436         if (!m_pEntryBuffer[i].IsActivated())
437         {
438             return m_pEntryBuffer + i;
439         }
440     }
441     return 0;
442 }
443 
444 
445 }}
446 
447