1 /*---------------------------------------------------------------------------*
2   Project:  Horizon
3   File:     fslow_SafeHandle.cpp
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: 19967 $
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  *    - w0の下位8bitは固定値のため変更しない
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 
53   Description:  初期化
54 
55   Arguments:    index   このエントリのインデックス
56 
57   Returns:      None.
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 
71   Description:  後始末
72 
73   Arguments:    None.
74 
75   Returns:      None.
76 
77   Note:         ハンドルの値もリセットされるため、ハンドルテーブル自体が削除
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 
96   Description:  このエントリを有効にする
97 
98   Arguments:    pObject         登録するアーカイブオブジェクト
99                 dependencyIndex 依存するエントリのインデックス
100 
101   Returns:      ハンドルを返す
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; // ハンドル固有値を更新する
116 
117     m_AccessLockCounter.Initialize();
118     return m_Handle;
119 }
120 
121 /*---------------------------------------------------------------------------*
122   Name:         SafeHandleTableEntry::Deactivate
123 
124   Description:  このエントリを無効にする
125 
126   Arguments:    None.
127 
128   Returns:      None.
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 
144   Description:  このエントリをロックする
145                 - ReaderLockを取る
146 
147   Arguments:    None.
148 
149   Returns:      ロックができたかどうかを返す
150  *---------------------------------------------------------------------------*/
Lock()151 bool SafeHandleTableEntry::Lock()
152 {
153     NN_TASSERT_(IsActivated());
154     return m_AccessLockCounter.Increment();
155 }
156 
157 /*---------------------------------------------------------------------------*
158   Name:         SafeHandleTableEntry::Unlock
159 
160   Description:  このエントリをアンロックする
161                 - ReaderLockを解除する
162 
163   Arguments:    None.
164 
165   Returns:      None.
166  *---------------------------------------------------------------------------*/
Unlock()167 void SafeHandleTableEntry::Unlock()
168 {
169     NN_TASSERT_(IsActivated());
170     m_AccessLockCounter.Decrement();
171 }
172 
173 /*---------------------------------------------------------------------------*
174   Name:         SafeHandleTableEntry::LockForUnregister
175 
176   Description:  登録削除用のアンロックをする
177                 - WriterLockの準備をする
178 
179   Arguments:    None.
180 
181   Returns:      None.
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 
198   Description:  初期化
199 
200   Arguments:    pEntryBiffer    エントリテーブル用のバッファ
201                 NumEntry        バッファに格納できるエントリ数
202 
203   Returns:      None.
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: void* で貰って placement new した方がよい?
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 
225   Description:  後始末
226 
227   Arguments:    None.
228 
229   Returns:      None.
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 
250   Description:  アーカイブオブジェクトの登録
251 
252   Arguments:    pObject             登録するアーカイブオブジェクト
253                 dependencyHandle    依存するアーカイブのハンドル
254 
255   Returns:      ハンドルを返す
256 
257   Note:         依存先のアーカイブをロックしてから呼び出すこと。
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         // 依存先をロック
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 
293   Description:  アーカイブオブジェクトの登録を解除する
294 
295   Arguments:    handle  登録を解除するアーカイブのハンドル
296 
297   Returns:      None.
298 
299   Note:         自分に依存しているアーカイブも再帰的に解除する。
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     // 他からこれ以上ロックされないようにする
322     pEntry->LockForUnregister();
323 
324     // 自分に依存しているエントリがある
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     // 依存先のロックを外す
336     if(pEntry->HasDependencyIndex())
337     {
338         GetEntry(pEntry->GetDependencyIndex())->Unlock();
339     }
340 
341     // 自分を無効にする
342     pEntry->Deactivate();
343 }
344 
345 /*---------------------------------------------------------------------------*
346   Name:         SafeHandleTable::LockEntry
347 
348   Description:  エントリをロックする
349 
350   Arguments:    handle  アーカイブのエントリ
351 
352   Returns:      ロックが出来たかどうかを返す。
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             // ロックできたとしても、期待するハンドルのものをロックしたとは限らない。
361             // 対応するエントリが期待するものであることを確認する。
362             if (pEntry->HasHandle(handle))
363             {
364                 return true;
365             }
366             // 対応するエントリが期待するハンドルを持たなかった場合には、
367             // この関数としてはロック失敗のため、エントリロックを解除する。
368             pEntry->Unlock();
369         }
370     }
371 
372     return false;
373 }
374 
375 /*---------------------------------------------------------------------------*
376   Name:         SafeHandleTable::UnlockEntry
377 
378   Description:  エントリのロックを解除する
379 
380   Arguments:    handle  アーカイブオブジェクトのエントリ
381 
382   Returns:      None.
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 
399   Description:  ハンドルからエントリを検索する
400 
401   Arguments:    handle  アーカイブのハンドル
402 
403   Returns:      エントリを返す
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         // ハンドル内にインデックス情報が入っているので利用する
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 
426   Description:  空いているエントリを探す
427 
428   Arguments:    None.
429 
430   Returns:      エントリを返す
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