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