1 /*---------------------------------------------------------------------------*
2   Project:  Horizon
3   File:     fslow_SafeHandle.cpp
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: 19967 $
12  *---------------------------------------------------------------------------
13 
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