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