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