www.pudn.com > pueblo.zip > ChModMgr.cpp
/*----------------------------------------------------------------------------
_ _ _
/\ | | | (_)
/ \ _ __ __| |_ __ ___ _ __ ___ ___ __| |_ __ _
/ /\ \ | '_ \ / _` | '__/ _ \| '_ ` _ \ / _ \/ _` | |/ _` |
/ ____ \| | | | (_| | | | (_) | | | | | | __/ (_| | | (_| |
/_/ \_\_| |_|\__,_|_| \___/|_| |_| |_|\___|\__,_|_|\__,_|
The contents of this file are subject to the Andromedia Public
License Version 1.0 (the "License"); you may not use this file
except in compliance with the License. You may obtain a copy of
the License at http://www.andromedia.com/APL/
Software distributed under the License is distributed on an
"AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
implied. See the License for the specific language governing
rights and limitations under the License.
The Original Code is Pueblo client code, released November 4, 1998.
The Initial Developer of the Original Code is Andromedia Incorporated.
Portions created by Andromedia are Copyright (C) 1998 Andromedia
Incorporated. All Rights Reserved.
Andromedia Incorporated 415.365.6700
818 Mission Street - 2nd Floor 415.365.6701 fax
San Francisco, CA 94103
Contributor(s):
--------------------------------------------------------------------------
Chaco team: Dan Greening, Glenn Crocker, Jim Doubek,
Coyote Lussier, Pritham Shetty.
Wrote and designed original codebase.
------------------------------------------------------------------------------
This file contains the implementation of the ChModuleMgr class, which
manages module information as well as loading and unloading modules.
----------------------------------------------------------------------------*/
// $Header: /home/cvs/chaco/api/ChModMgr.cpp,v 2.11 1995/11/07 18:19:12 coyote Exp $
#include "headers.h"
#include
#include
#include
#include
#include
#include
#ifdef CH_UNIX
#include
#include
#include
#endif
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/*----------------------------------------------------------------------------
Static Unload list
----------------------------------------------------------------------------*/
#if !defined( NO_TEMPLATES )
static ChList unloadedList;
#else
static ChParamList unloadedList;
#endif
ChModuleID ChModuleMgr::m_idLocalModule = CH_LOCAL_MODULE_ID_START;
/*----------------------------------------------------------------------------
ChModuleInfo class
----------------------------------------------------------------------------*/
ChModuleInfo::ChModuleInfo( const string& strName, const string& strFilename,
bool boolStatic, ChMainHandler mainHandler,
ChMainInfo *pMainInfo ) :
m_strName( strName ),
m_strFilename( strFilename ),
m_boolStatic( boolStatic ),
m_pMainInfo( pMainInfo ),
m_mainHandler( mainHandler ),
m_sUsageCount( 1 )
{
#if defined( CH_MSW )
{ /* Must be set later with
SetLibraryHandle() */
m_hLibrary = 0;
}
#endif // defined( CH_MSW )
}
ChModuleInfo::ChModuleInfo( ChDispatcher* pDispatcher ) :
m_boolStatic( true ), m_pMainInfo( 0 ), m_mainHandler( 0 ),
m_pDispatcher( pDispatcher ), m_sUsageCount( 1 )
{
#if defined( CH_MSW )
{ /* Must be set later with
SetLibraryHandle() */
m_hLibrary = 0;
}
#endif // defined( CH_MSW )
}
bool ChModuleInfo::Unload( const ChModuleID idModule )
{
bool boolUnloaded;
if ( 0 >= DecrementModuleUsage())
{
ChMainInfo *pMainInfo = GetMainInfo();
ChMainHandler handler = GetMainHandler();
ChTermMsg msg;
// Send the TERM message
handler( msg, pMainInfo, idModule, &GetName() );
// Unload the library
#if defined( CH_MSW )
{
HINSTANCE hLibrary;
if (hLibrary = GetLibraryHandle())
{
FreeLibrary( hLibrary );
}
}
#endif // defined( CH_MSW )
boolUnloaded = true;
}
else
{
boolUnloaded = false;
}
return boolUnloaded;
}
/*----------------------------------------------------------------------------
ChVisitEnumAll class
----------------------------------------------------------------------------*/
class ChVisitEnumAll : public
#if !defined( NO_TEMPLATES )
ChPtrSplayVisitor2
#else
ChModuleSplayTreePtrVisitor2
#endif
{
public:
ChVisitEnumAll( ChModEnumFunc enumFunc )
{
m_enumFunc = enumFunc;
}
bool Visit( ChModuleID idModule, const ChModuleInfo* pModuleInfo );
protected:
ChModEnumFunc m_enumFunc;
};
bool ChVisitEnumAll::Visit( ChModuleID idModule,
const ChModuleInfo* pModuleInfo )
{
bool boolContinue;
boolContinue = m_enumFunc( *pModuleInfo );
return boolContinue;
}
/*----------------------------------------------------------------------------
ChVisitCountAll class
----------------------------------------------------------------------------*/
class ChVisitCountAll : public
#if !defined( NO_TEMPLATES )
ChPtrSplayVisitor2
#else
ChModuleSplayTreePtrVisitor2
#endif
{
public:
ChVisitCountAll() : m_iCount( 0 ) {}
virtual void Start() { m_iCount = 0; }
virtual bool Visit( ChModuleID idModule,
const ChModuleInfo* pModuleInfo );
inline int GetCount() { return m_iCount; }
protected:
int m_iCount;
};
bool ChVisitCountAll::Visit( ChModuleID idModule,
const ChModuleInfo* pModuleInfo )
{
m_iCount++;
return true;
}
/*----------------------------------------------------------------------------
ChVisitGetModuleIDs class
----------------------------------------------------------------------------*/
class ChVisitGetModuleIDs : public
#if !defined( NO_TEMPLATES )
ChPtrSplayVisitor2
#else
ChModuleSplayTreePtrVisitor2
#endif
{
public:
ChVisitGetModuleIDs( int iMax, ChModuleID* pModules ) :
m_iMax( iMax ),
m_pModules( pModules ),
m_iIndex( 0 )
{
}
virtual void Start()
{
ASSERT( m_pModules );
m_iIndex = 0;
}
virtual bool Visit( ChModuleID idModule,
const ChModuleInfo* pModuleInfo );
inline int GetCount() { return m_iIndex; }
protected:
int m_iMax;
ChModuleID* m_pModules;
int m_iIndex;
};
bool ChVisitGetModuleIDs::Visit( ChModuleID idModule,
const ChModuleInfo* pModuleInfo )
{
if (m_iIndex >= m_iMax)
{
return false;
}
m_pModules[m_iIndex] = idModule;
m_iIndex++;
return true;
}
/*----------------------------------------------------------------------------
ChVisitHideAll class
----------------------------------------------------------------------------*/
class ChVisitHideAll : public
#if !defined( NO_TEMPLATES )
ChPtrSplayVisitor2
#else
ChModuleSplayTreePtrVisitor2
#endif
{
public:
ChVisitHideAll() {}
bool Visit( ChModuleID idModule, const ChModuleInfo* pModuleInfo );
};
bool ChVisitHideAll::Visit( ChModuleID idModule, const ChModuleInfo* pModuleInfo )
{
if (idModule != CH_CORE_MODULE_ID)
{ /* Hide all modules except
the core */
ChShowModuleMsg msg( false );
pModuleInfo->GetDispatcher()->Dispatch( msg );
}
return true;
}
/*----------------------------------------------------------------------------
ChVisitUnloadAll class
----------------------------------------------------------------------------*/
class ChVisitUnloadAll : public
#if !defined( NO_TEMPLATES )
ChPtrSplayVisitor2
#else
ChModuleSplayTreePtrVisitor2
#endif
{
public:
ChVisitUnloadAll() {}
bool Visit( ChModuleID idModule, const ChModuleInfo* pModuleInfo );
};
bool ChVisitUnloadAll::Visit( ChModuleID idModule,
const ChModuleInfo* pModuleInfo )
{
if (idModule != CH_CORE_MODULE_ID && idModule < CH_LOCAL_MODULE_ID_START )
{ /* Unload all modules except
the core */
if (((ChModuleInfo*&)pModuleInfo)->Unload( idModule ))
{
unloadedList.AddTail( idModule );
}
}
return true;
}
/*----------------------------------------------------------------------------
ChVisitCheckpointAll class
----------------------------------------------------------------------------*/
class ChVisitCheckpointAll : public
#if !defined( NO_TEMPLATES )
ChPtrSplayVisitor2
#else
ChModuleSplayTreePtrVisitor2
#endif
{
public:
ChVisitCheckpointAll() {}
bool Visit( ChModuleID idModule,
const ChModuleInfo* pModuleInfo );
};
bool ChVisitCheckpointAll::Visit( ChModuleID idModule,
const ChModuleInfo* pModuleInfo )
{
if (idModule != CH_CORE_MODULE_ID && idModule < CH_LOCAL_MODULE_ID_START )
{ /* Checkpoint all modules except
the core */
ChCheckpointModuleMsg msg;
pModuleInfo->GetDispatcher()->Dispatch( msg );
}
return true;
}
/*----------------------------------------------------------------------------
ChFindModuleOp class
----------------------------------------------------------------------------*/
class ChFindModuleOp : public
#if !defined( NO_TEMPLATES )
ChPtrSplayVisitor2
#else
ChModuleSplayTreePtrVisitor2
#endif
{
public:
ChFindModuleOp( const string& strName ) :
m_strName( strName ), m_idModule( 0 ) {}
inline bool GetInfo( ChModuleID& idModule, string& strFilename )
{
idModule = m_idModule;
strFilename = m_strFilename;
return 0 != m_idModule;
}
bool Visit( ChModuleID idModule,
const ChModuleInfo* pModuleInfo );
private:
string m_strName; // Module name passed in
ChModuleID m_idModule; // Two values to return
string m_strFilename;
};
bool ChFindModuleOp::Visit( ChModuleID idModule,
const ChModuleInfo* pModuleInfo )
{
bool boolContinue;
if (pModuleInfo->GetName() == m_strName)
{ // We found the module
m_idModule = idModule;
m_strFilename = pModuleInfo->GetFilename();
boolContinue = false;
}
else
{
boolContinue = true;
}
return boolContinue;
}
/*----------------------------------------------------------------------------
ChModuleMgr class
----------------------------------------------------------------------------*/
ChModuleMgr::ChModuleMgr() : m_boolInUnloadAll( false )
{
}
ChModuleMgr::~ChModuleMgr()
{
}
ChModuleID ChModuleMgr::CreateLocalModule()
{
// Module IDs are valid only on the client
// 0xFFFFF000 - 0xFFFFFFFF are reserved fo local modules
return ( m_idLocalModule++ );
}
bool ChModuleMgr::Add( const ChModuleID& idModule, const string& strModule,
ChMainHandler mainHandler )
{
bool boolSuccess;
ChInitMsg msg( idModule, CH_CORE_MODULE_ID );
ChMainInfo *pMainInfo;
pMainInfo = (ChMainInfo *)(mainHandler( msg, 0, idModule, &strModule ));
if (pMainInfo)
{
ChModuleInfo* pModuleInfo = m_moduleTree.FindValue( idModule );
ChInitMsg initMsg( idModule, "" );
if (pModuleInfo)
{ /* Change existing information in
the tree */
pModuleInfo->Set( strModule, true, mainHandler, pMainInfo );
}
else
{ // Add the information to the tree
ChModuleInfo* pInfo;
pInfo = new ChModuleInfo( strModule, "", true, mainHandler,
pMainInfo );
m_moduleTree.Insert( idModule, pInfo );
}
/* Send a ChInitMsg to the module's
handler */
pModuleInfo->GetDispatcher()->Dispatch( initMsg );
boolSuccess = true;
}
else
{
boolSuccess = false;
}
return boolSuccess;
}
bool ChModuleMgr::Load( const ChModuleID& idModule, const string& strModule,
const string& strLibrary, const string& strLoadParam,
const ChModuleID idServerModule )
{
bool boolSuccess = true;
ChMainHandler handler;
#if defined( CH_MSW )
HINSTANCE hLibrary;
#endif // defined( CH_MSW )
#if defined( CH_MSW )
{
TRACE2( "LOAD: Library %s (%s)\n", (const char *)strLibrary,
(const char *)strModule );
/* Load the library and get the ChMain
entrypoint address */
hLibrary = LoadLibrary( strLibrary );
#if defined( WIN32 )
if (0 == hLibrary)
{
boolSuccess = false;
}
#else
if ( hLibrary <= HINSTANCE_ERROR )
{
boolSuccess = false;
}
#endif
else
{
handler = (ChMainHandler)GetProcAddress( hLibrary, CH_MAIN_NAME );
if (0 == handler)
{
#if defined( WIN32 )
DWORD dwError;
dwError = GetLastError();
#endif
boolSuccess = false;
}
}
}
#else // defined( CH_MSW )
{
#if defined( linux )
CH_DECLARE_MAIN_HANDLER( ChMainEntry );
#ifdef CH_CLIENT
CH_DECLARE_MAIN_HANDLER( ChMainEntryWorld );
if (strLibrary == CH_MODULE_WORLD) {
handler = ChMainEntryWorld;
} else
#endif // CH_CLIENT
{
handler = ChMainEntry;
}
#else
void *lib = dlopen( strLibrary, RTLD_NOW );
if (lib) {
handler = (ChMainHandler)dlsym( lib, CH_MAIN_NAME );
if (handler == 0) {
cerr << dlerror() << endl;
boolSuccess = false;
}
} else {
cerr << dlerror() << endl;
boolSuccess = false;
}
#endif // !linux
}
#endif // defined( CH_MSW )
if (boolSuccess)
{
ChInitMsg initMsg( idModule, strLoadParam, idServerModule );
ChMainInfo* pMainInfo;
pMainInfo = (ChMainInfo *)(handler( initMsg, 0, idModule,
&strModule ));
if (pMainInfo)
{
ChModuleInfo* pModuleInfo = m_moduleTree.FindValue( idModule );
if (pModuleInfo)
{ /* Change existing information in
the tree */
pModuleInfo->Set( strModule, false, handler, pMainInfo );
#if defined( CH_MSW )
{
pModuleInfo->SetLibraryHandle( hLibrary );
}
#endif // defined( CH_MSW )
}
else
{ // Add the information to the tree
ChModuleInfo *pInfo;
pInfo = new ChModuleInfo( strModule, strLibrary, false,
handler, pMainInfo );
#if defined( CH_MSW )
{
pInfo->SetLibraryHandle( hLibrary );
}
#endif // defined( CH_MSW )
m_moduleTree.Insert( idModule, pInfo );
pModuleInfo = m_moduleTree.FindValue( idModule );
}
/* Send a ChInitMsg to the module's
handler */
pModuleInfo->GetDispatcher()->Dispatch( initMsg );
boolSuccess = true;
}
else
{
boolSuccess = false;
}
}
return boolSuccess;
}
void ChModuleMgr::IncrementModuleUsage( const ChModuleID& idModule )
{
ChModuleInfo* pModuleInfo = m_moduleTree.FindValue( idModule );
ASSERT( pModuleInfo );
pModuleInfo->IncrementModuleUsage();
}
void ChModuleMgr::Unload( const ChModuleID& idModule )
{
ChModuleInfo* pModuleInfo = m_moduleTree.FindValue( idModule );
if (pModuleInfo && pModuleInfo->Unload( idModule ))
{
if (InUnloadAll())
{ /* We can't delete right now, so
add to a list to unload later */
unloadedList.AddTail( idModule );
}
else
{ // Delete from the tree
m_moduleTree.Delete( idModule );
}
}
}
ChDispatcher* ChModuleMgr::GetDispatcher( const ChModuleID& idModule )
{
ChDispatcher* pDispatcher = 0;
ChModuleInfo* pModuleInfo;
if (pModuleInfo = m_moduleTree.FindValue( idModule ))
{
pDispatcher = pModuleInfo->GetDispatcher();
}
return pDispatcher;
}
void ChModuleMgr::SetDispatcher( const ChModuleID& idModule, ChDispatcher* pDispatcher )
{
ChModuleInfo* pModuleInfo;
if (pModuleInfo = m_moduleTree.FindValue( idModule ))
{
// The module is already loaded
pModuleInfo->SetDispatcher( pDispatcher );
}
else
{ // The module is not yet loaded
ChModuleInfo* pInfo;
pInfo = new ChModuleInfo( pDispatcher );
m_moduleTree.Insert( idModule, pInfo );
}
}
void ChModuleMgr::EnumerateModules( ChModEnumFunc enumFunc )
{
ChVisitEnumAll enumAll( enumFunc );
m_moduleTree.Infix( enumAll );
}
int ChModuleMgr::GetCount()
{
ChVisitCountAll countAll;
m_moduleTree.Infix( countAll );
return countAll.GetCount();
}
int ChModuleMgr::GetModuleIDs( int iMax, ChModuleID* pModules )
{
ChVisitGetModuleIDs getAll( iMax, pModules );
m_moduleTree.Infix( getAll );
return getAll.GetCount();
}
void ChModuleMgr::HideAll()
{
ChVisitHideAll hideAll;
m_moduleTree.Infix( hideAll );
}
void ChModuleMgr::UnloadAll()
{
ChVisitUnloadAll unloadAll;
bool boolPrevUnload;
boolPrevUnload = SetUnloadAll();
m_moduleTree.Infix( unloadAll );
SetUnloadAll( boolPrevUnload );
// Erase all entries unloadList
while (!unloadedList.IsEmpty())
{
ChModuleID idUnloaded;
idUnloaded = unloadedList.RemoveHead();
m_moduleTree.Delete( idUnloaded );
}
}
void ChModuleMgr::CheckpointAll()
{
ChVisitCheckpointAll checkpointAll;
m_moduleTree.Infix( checkpointAll );
}
bool ChModuleMgr::FindModule( const string& strModule,
ChModuleID& idModule, string& strFilename )
{
ChFindModuleOp moduleSearch( strModule );
bool boolLoaded;
// Scan the tree for the module
m_moduleTree.Infix( moduleSearch );
// Return what we found
if (moduleSearch.GetInfo( idModule, strFilename ))
{
boolLoaded = true;
}
else
{
boolLoaded = false;
}
return boolLoaded;
}
ChMainInfo* ChModuleMgr::GetMainInfo( const ChModuleID& idModule )
{
ChMainInfo* pInfo;
ChModuleInfo* pModuleInfo;
if (pModuleInfo = m_moduleTree.FindValue( idModule ))
{
pInfo = pModuleInfo->GetMainInfo();
}
else
{
pInfo = 0;
}
return pInfo;
}
string ChModuleMgr::GetModuleName( const ChModuleID& idModule )
{
ChModuleInfo* pModuleInfo;
string strName;
if (pModuleInfo = m_moduleTree.FindValue( idModule ))
{
strName = pModuleInfo->GetName();
}
else
{
strName = "";
}
return strName;
}
// Local Variables: ***
// tab-width:4 ***
// End: ***