/*---------------------------------------------------------------------------* Project: Horizon File: fslow_SafeHandle.cpp Copyright 2010 Nintendo. All rights reserved. These coded instructions, statements, and computer programs contain proprietary information of Nintendo of America Inc. and/or Nintendo Company Ltd., and are protected by Federal copyright law. They may not be disclosed to third parties or copied or duplicated in any form, in whole or in part, without the prior written consent of Nintendo. $Rev: 19967 $ *---------------------------------------------------------------------------*/ #include namespace nn { namespace fslow { /*===========================================================================* * SafeHandle *===========================================================================*/ /*---------------------------------------------------------------------------* * operator++ * - w0の下位8bitは固定値のため変更しない *---------------------------------------------------------------------------*/ SafeHandle& SafeHandle::operator++() { NN_TASSERT_(IsValid()); NN_TASSERT_(!IsPermanent()); m_Data[0] += 0x100; if (((m_Data[0] & 0xFFFFFF00) == 0) && (++m_Data[1] == 0)) { NN_TPANIC_("No more archive handle."); } return *this; } /*===========================================================================* * SafeHandleTableEntry *===========================================================================*/ /*---------------------------------------------------------------------------* Name: SafeHandleTableEntry::Initialize Description: 初期化 Arguments: index このエントリのインデックス Returns: None. *---------------------------------------------------------------------------*/ void SafeHandleTableEntry::Initialize(s32 index) { NN_TASSERT_(!IsInitialized()); NN_TASSERT_(index <= MAX_INDEX); m_DependencyIndex = static_cast(index); m_Handle.Initialize(index); } /*---------------------------------------------------------------------------* Name: SafeHandleTableEntry::Finalize Description: 後始末 Arguments: None. Returns: None. Note: ハンドルの値もリセットされるため、ハンドルテーブル自体が削除 されるときに呼び出す。 *---------------------------------------------------------------------------*/ void SafeHandleTableEntry::Finalize() { NN_TASSERT_(IsInitialized()); if(IsActivated()) { Deactivate(); } m_DependencyIndex = 0; m_Handle.Invalidate(); } /*---------------------------------------------------------------------------* Name: SafeHandleTableEntry::Activate Description: このエントリを有効にする Arguments: pObject 登録するアーカイブオブジェクト dependencyIndex 依存するエントリのインデックス Returns: ハンドルを返す *---------------------------------------------------------------------------*/ SafeHandle SafeHandleTableEntry::Activate(void* pObject, s32 dependencyIndex/*=INVALID_INDEX*/) { NN_TASSERT_(IsInitialized() && !IsActivated()); NN_TASSERT_(pObject); m_pObject = pObject; if(dependencyIndex != INVALID_INDEX) { m_DependencyIndex = static_cast(dependencyIndex); } ++m_Handle; // ハンドル固有値を更新する m_AccessLockCounter.Initialize(); return m_Handle; } /*---------------------------------------------------------------------------* Name: SafeHandleTableEntry::Deactivate Description: このエントリを無効にする Arguments: None. Returns: None. *---------------------------------------------------------------------------*/ void SafeHandleTableEntry::Deactivate() { NN_TASSERT_(IsActivated()); NN_TASSERT_(m_AccessLockCounter.IsFinalizationPrepared()); m_pObject = 0; m_DependencyIndex = m_Handle.GetFixedValue(); m_AccessLockCounter.Finalize(); } /*---------------------------------------------------------------------------* Name: SafeHandleTableEntry::Lock Description: このエントリをロックする - ReaderLockを取る Arguments: None. Returns: ロックができたかどうかを返す *---------------------------------------------------------------------------*/ bool SafeHandleTableEntry::Lock() { NN_TASSERT_(IsActivated()); return m_AccessLockCounter.Increment(); } /*---------------------------------------------------------------------------* Name: SafeHandleTableEntry::Unlock Description: このエントリをアンロックする - ReaderLockを解除する Arguments: None. Returns: None. *---------------------------------------------------------------------------*/ void SafeHandleTableEntry::Unlock() { NN_TASSERT_(IsActivated()); m_AccessLockCounter.Decrement(); } /*---------------------------------------------------------------------------* Name: SafeHandleTableEntry::LockForUnregister Description: 登録削除用のアンロックをする - WriterLockの準備をする Arguments: None. Returns: None. *---------------------------------------------------------------------------*/ void SafeHandleTableEntry::LockForUnregister() { NN_TASSERT_(IsActivated()); m_AccessLockCounter.PrepareFinalization(); } /*===========================================================================* * SafeHandleTable *===========================================================================*/ /*---------------------------------------------------------------------------* Name: SafeHandleTable::Initialize Description: 初期化 Arguments: pEntryBiffer エントリテーブル用のバッファ NumEntry バッファに格納できるエントリ数 Returns: None. *---------------------------------------------------------------------------*/ void SafeHandleTable::Initialize(SafeHandleTableEntry* pEntryBuffer, s32 NumEntry) { NN_TASSERT_(!IsInitialized()); NN_TASSERT_(pEntryBuffer); NN_TASSERT_(NumEntry <= SafeHandleTableEntry::MAX_INDEX); for(s32 i = 0; i < NumEntry; ++i) { // CHECK: void* で貰って placement new した方がよい? pEntryBuffer[i].Initialize(i); } m_NumEntry = NumEntry; m_pEntryBuffer = pEntryBuffer; m_CriticalSection.Initialize(); } /*---------------------------------------------------------------------------* Name: SafeHandleTable::Finalize Description: 後始末 Arguments: None. Returns: None. *---------------------------------------------------------------------------*/ void SafeHandleTable::Finalize() { if(!IsInitialized()) { return; } for(s32 i = 0; i < m_NumEntry; ++i) { m_pEntryBuffer[i].Finalize(); } m_NumEntry = 0; m_pEntryBuffer = 0; } /*---------------------------------------------------------------------------* Name: SafeHandleTable::Register Description: アーカイブオブジェクトの登録 Arguments: pObject 登録するアーカイブオブジェクト dependencyHandle 依存するアーカイブのハンドル Returns: ハンドルを返す Note: 依存先のアーカイブをロックしてから呼び出すこと。 *---------------------------------------------------------------------------*/ SafeHandle SafeHandleTable::Register(void* pObject, SafeHandle dependencyHandle/*=InvalidSafeHandle()*/) { NN_TASSERT_(IsInitialized()); nn::os::CriticalSection::ScopedLock lk(m_CriticalSection); s32 dependencyIndex; if(dependencyHandle.IsValid()) { // 依存先をロック dependencyIndex = dependencyHandle.GetFixedValue(); if(!GetEntry(dependencyIndex)->Lock()) { return InvalidSafeHandle(); } } else { dependencyIndex = SafeHandleTableEntry::INVALID_INDEX; } SafeHandleTableEntry* pEntry = FindFreeEntry(); if(pEntry) { return pEntry->Activate(pObject, dependencyIndex); } return InvalidSafeHandle(); } /*---------------------------------------------------------------------------* Name: SafeHandleTable::Unregister Description: アーカイブオブジェクトの登録を解除する Arguments: handle 登録を解除するアーカイブのハンドル Returns: None. Note: 自分に依存しているアーカイブも再帰的に解除する。 *---------------------------------------------------------------------------*/ void SafeHandleTable::Unregister(SafeHandle handle) { NN_TASSERT_(IsInitialized()); nn::os::CriticalSection::ScopedLock lk(m_CriticalSection); if(handle.IsValid()) { UnregisterRecursive(handle.GetFixedValue()); } } void SafeHandleTable::UnregisterRecursive(s32 index) { SafeHandleTableEntry* pEntry = GetEntry(index); if(!pEntry || !pEntry->IsActivated()) { return; } // 他からこれ以上ロックされないようにする pEntry->LockForUnregister(); // 自分に依存しているエントリがある SafeHandleTableEntry* pEntryDependOn; for(s32 i = 0; i < m_NumEntry; ++i) { pEntryDependOn = GetEntry(i); if(pEntryDependOn->IsActivated() && (pEntryDependOn->GetDependencyIndex() == index)) { UnregisterRecursive(i); } } // 依存先のロックを外す if(pEntry->HasDependencyIndex()) { GetEntry(pEntry->GetDependencyIndex())->Unlock(); } // 自分を無効にする pEntry->Deactivate(); } /*---------------------------------------------------------------------------* Name: SafeHandleTable::LockEntry Description: エントリをロックする Arguments: handle アーカイブのエントリ Returns: ロックが出来たかどうかを返す。 *---------------------------------------------------------------------------*/ bool SafeHandleTable::LockEntry(SafeHandleTableEntry* pEntry, SafeHandle handle) { if(pEntry && pEntry->IsActivated()) { if (pEntry->Lock()) { // ロックできたとしても、期待するハンドルのものをロックしたとは限らない。 // 対応するエントリが期待するものであることを確認する。 if (pEntry->HasHandle(handle)) { return true; } // 対応するエントリが期待するハンドルを持たなかった場合には、 // この関数としてはロック失敗のため、エントリロックを解除する。 pEntry->Unlock(); } } return false; } /*---------------------------------------------------------------------------* Name: SafeHandleTable::UnlockEntry Description: エントリのロックを解除する Arguments: handle アーカイブオブジェクトのエントリ Returns: None. *---------------------------------------------------------------------------*/ void SafeHandleTable::UnlockEntry(SafeHandleTableEntry* pEntry) { if(pEntry && pEntry->IsActivated()) { pEntry->Unlock(); } else { NN_TPANIC_("unknown handle"); } } /*---------------------------------------------------------------------------* Name: SafeHandleTable::FindEntry Description: ハンドルからエントリを検索する Arguments: handle アーカイブのハンドル Returns: エントリを返す *---------------------------------------------------------------------------*/ SafeHandleTableEntry* SafeHandleTable::FindEntry(SafeHandle handle) const { NN_TASSERT_(IsInitialized()); nn::os::CriticalSection::ScopedLock lk(m_CriticalSection); if(handle.IsValid()) { // ハンドル内にインデックス情報が入っているので利用する SafeHandleTableEntry* pEntry = GetEntry(handle.GetFixedValue()); if(pEntry && pEntry->HasHandle(handle)) { return pEntry; } } return 0; } /*---------------------------------------------------------------------------* Name: SafeHandleTable::FindFreeEntry Description: 空いているエントリを探す Arguments: None. Returns: エントリを返す *---------------------------------------------------------------------------*/ SafeHandleTableEntry* SafeHandleTable::FindFreeEntry() const { for (s32 i = 0; i < m_NumEntry; ++i) { if (!m_pEntryBuffer[i].IsActivated()) { return m_pEntryBuffer + i; } } return 0; } }}