ContextManager and ProcessEnumerator have the basic functionality done.

Created a test program to validate them and show how to use them.
develop
Petr Mrázek 2010-05-29 21:34:36 +02:00
parent ab40868b29
commit 7300e61f8a
5 changed files with 348 additions and 71 deletions

@ -41,23 +41,90 @@ distribution.
using namespace DFHack;
namespace DFHack
{
class DFContextMgrPrivate
class ContextManager::Private
{
public:
DFContextMgrPrivate(){};
~DFContextMgrPrivate(){};
Private(){};
~Private(){};
string xml; // path to xml
vector <Context *> contexts;
ProcessEnumerator * pEnum;
};
}
class DFHack::BadContexts::Private
{
public:
Private(){};
vector <Context *> bad;
};
BadContexts::BadContexts():d(new Private()){}
BadContexts::~BadContexts()
{
clear();
delete d;
}
bool BadContexts::Contains(Process* p)
{
for(int i = 0; i < d->bad.size(); i++)
{
if((d->bad[i])->getProcess() == p)
return true;
}
return false;
}
bool BadContexts::Contains(Context* c)
{
for(int i = 0; i < d->bad.size(); i++)
{
if(d->bad[i] == c)
return true;
}
return false;
}
uint32_t BadContexts::size()
{
return d->bad.size();
}
void BadContexts::clear()
{
for(int i = 0; i < d->bad.size(); i++)
{
// delete both Process and Context!
// process has to be deleted after context, because Context does some
// cleanup on delete (detach, etc.)
Process * to_kill = d->bad[i]->getProcess();
delete d->bad[i];
delete to_kill;
}
d->bad.clear();
}
void BadContexts::push_back(Context* c)
{
if(c)
d->bad.push_back(c);
}
Context * BadContexts::operator[](uint32_t index)
{
if(index < d->bad.size())
return d->bad[index];
return 0;
}
ContextManager::ContextManager (const string path_to_xml) : d (new DFContextMgrPrivate())
ContextManager::ContextManager (const string path_to_xml) : d (new Private())
{
d->pEnum = 0;
d->xml = QUOT (MEMXML_DATA_PATH);
d->xml += "/";
d->xml += path_to_xml;
d->pEnum = new ProcessEnumerator(d->xml);
}
ContextManager::~ContextManager()
@ -66,26 +133,76 @@ ContextManager::~ContextManager()
delete d;
}
uint32_t ContextManager::Refresh()
uint32_t ContextManager::Refresh( BadContexts* bad_contexts )
{
purge();
if(d->pEnum != 0)
d->pEnum = new ProcessEnumerator(d->xml);
else
// handle expired processes, remove stale Contexts
{
delete d->pEnum;
d->pEnum = new ProcessEnumerator(d->xml);
BadProcesses expired;
// get new list od living and expired Process objects
d->pEnum->Refresh(&expired);
// scan expired, kill contexts if necessary
vector <Context*>::iterator it = d->contexts.begin();;
while(it != d->contexts.end())
{
Process * test = (*it)->getProcess();
if(expired.Contains(test))
{
// ok. we have an expired context here.
if(!bad_contexts)
{
// with nowhere to put the context, we have to destroy it
delete *it;
// stop tracking it and advance the iterator
it = d->contexts.erase(it);
continue;
}
else
{
// we stuff the context into bad_contexts
bad_contexts->push_back(*it);
// stop tracking it and advance the iterator
it = d->contexts.erase(it);
// remove process from the 'expired' container, it is tracked by bad_contexts now
// (which is responsible for freeing it).
expired.excise(test);
continue;
}
}
else it++; // not expired, just advance to next one
}
// no expired contexts are in the d->contexts vector now
// all processes remaining in 'expired' are now destroyed along with it
}
d->pEnum->purge();
d->pEnum->findProcessess();
int numProcesses = d->pEnum->size();
int numContexts = d->contexts.size();
vector <Context *> newContexts;
// enumerate valid processes
for(int i = 0; i < numProcesses; i++)
{
Context * c = new Context(d->pEnum->operator[](i));
d->contexts.push_back(c);
Process * test = d->pEnum->operator[](i);
bool exists = false;
// scan context vector for this process
for(int j = 0; j < numContexts; j++)
{
if((d->contexts[j])->getProcess() == test)
{
// already have that one, skip
exists = true;
}
}
if(!exists)
{
// new process needs a new context
Context * c = new Context(d->pEnum->operator[](i));
newContexts.push_back(c);
}
}
d->contexts.insert(d->contexts.end(), newContexts.begin(), newContexts.end());
return d->contexts.size();
}
uint32_t ContextManager::size()
{
return d->contexts.size();

@ -44,7 +44,76 @@ class DFHack::ProcessEnumerator::Private
void EnumPIDs (vector <ProcessID> &PIDs);
};
#ifdef LINUX_BUILD
class DFHack::BadProcesses::Private
{
public:
Private(){};
PROC_V bad;
};
BadProcesses::BadProcesses():d(new Private()){}
BadProcesses::~BadProcesses()
{
clear();
delete d;
}
bool BadProcesses::Contains(Process* p)
{
for(int i = 0; i < d->bad.size(); i++)
{
if(d->bad[i] == p)
return true;
}
return false;
}
bool BadProcesses::excise(Process* p)
{
vector<Process*>::iterator it = d->bad.begin();
while(it != d->bad.end())
{
if((*it) == p)
{
d->bad.erase(it);
return true;
}
else
{
it++;
}
}
return false;
}
uint32_t BadProcesses::size()
{
return d->bad.size();
}
void BadProcesses::clear()
{
for(int i = 0; i < d->bad.size(); i++)
{
delete d->bad[i];
}
d->bad.clear();
}
void BadProcesses::push_back(Process* p)
{
if(p)
d->bad.push_back(p);
}
Process * BadProcesses::operator[](uint32_t index)
{
if(index < d->bad.size())
return d->bad[index];
return 0;
}
//FIXME: wasteful
Process *ProcessEnumerator::Private::GetProcessObject(ProcessID ID)
{
@ -54,21 +123,23 @@ Process *ProcessEnumerator::Private::GetProcessObject(ProcessID ID)
return p1;
else
delete p1;
Process *p2 = new NormalProcess(ID.pid,meminfo->meminfo);
if(p2->isIdentified())
return p2;
else
delete p2;
#ifdef LINUX_BUILD
Process *p3 = new WineProcess(ID.pid,meminfo->meminfo);
if(p3->isIdentified())
return p3;
else
delete p3;
return 0;
#endif
}
#ifdef LINUX_BUILD
void ProcessEnumerator::Private::EnumPIDs (vector <ProcessID> &PIDs)
{
DIR *dir_p;
@ -104,22 +175,6 @@ void ProcessEnumerator::Private::EnumPIDs (vector <ProcessID> &PIDs)
#endif
#ifndef LINUX_BUILD
Process *ProcessEnumerator::Private::GetProcessObject(ProcessID ID)
{
Process *p1 = new SHMProcess(ID.pid,meminfo->meminfo);
if(p1->isIdentified())
return p1;
else
delete p1;
Process *p2 = new NormalProcess(ID.pid,meminfo->meminfo);
if(p2->isIdentified())
return p2;
else
delete p2;
return 0;
}
// some magic - will come in handy when we start doing debugger stuff on Windows
bool EnableDebugPriv()
{
@ -199,19 +254,19 @@ void ProcessEnumerator::Private::EnumPIDs (vector <ProcessID> &PIDs)
}
#endif
bool ProcessEnumerator::Refresh( PROC_V * invalidated_processes)
bool ProcessEnumerator::Refresh( BadProcesses* invalidated_processes)
{
// PIDs to process
vector <ProcessID> PIDs;
// this will be the new process map
PID2PROC temporary;
// clear the vector other access
// clear the vector
d->Processes.clear();
if(invalidated_processes)
invalidated_processes->clear();
d->EnumPIDs(PIDs);
for(uint64_t i = 0; i < PIDs.size();i++)
{
ProcessID & PID = PIDs[i];

@ -35,18 +35,36 @@ distribution.
namespace DFHack
{
class Context;
class DFContextMgrPrivate;
class BadContexts;
class Process;
class DFHACK_EXPORT ContextManager
{
DFContextMgrPrivate * const d;
class Private;
Private * const d;
public:
ContextManager(const std::string path_to_xml);
~ContextManager();
uint32_t Refresh();
uint32_t Refresh(BadContexts* bad_contexts = 0);
uint32_t size();
Context * operator[](uint32_t index);
Context * getSingleContext();
void purge(void);
};
class DFHACK_EXPORT BadContexts
{
class Private;
Private * const d;
void push_back(Context * c);
friend class ContextManager;
public:
BadContexts();
~BadContexts();
bool Contains(Context* c);
bool Contains(Process* p);
uint32_t size();
void clear();
Context * operator[](uint32_t index);
};
} // namespace DFHack
#endif // CONTEXTMANAGER_H_INCLUDED

@ -32,6 +32,7 @@ namespace DFHack
{
class memory_info;
class Process;
class BadProcesses;
/*
* Process manager
*/
@ -42,11 +43,26 @@ namespace DFHack
public:
ProcessEnumerator( string path_to_xml );
~ProcessEnumerator();
bool Refresh(vector <Process *> * invalidated_processes = 0);
bool Refresh(BadProcesses * invalidated_processes = 0);
bool findProcessess();
uint32_t size();
Process * operator[](uint32_t index);
void purge(void);
};
class DFHACK_EXPORT BadProcesses
{
class Private;
Private * const d;
void push_back(Process * p);
friend class ProcessEnumerator;
public:
BadProcesses();
~BadProcesses();
bool Contains(Process* p);
bool excise (Process* p);
uint32_t size();
void clear();
Process * operator[](uint32_t index);
};
}
#endif // PROCESSMANAGER_H_INCLUDED

@ -13,42 +13,113 @@ using namespace std;
using namespace DFHack;
#ifndef LINUX_BUILD
#endif
void printhelp ()
{
cout << "enter empty line for next try." << endl;
cout << "enter 'next' or 'n' for next test." << endl;
cout << "enter 'help' to show this text again." << endl;
}
int inputwait (const char * prompt)
{
inputwait_reset:
string command = "";
cout <<"[" << prompt << "]# ";
getline(cin, command);
if(command == "help")
{
printhelp();
goto inputwait_reset;
}
else if(command == "")
{
return 1;
}
else if(command == "next")
{
return 0;
}
else
{
cout << "Command not recognized. Try 'help' for a list of valid commands." << endl;
goto inputwait_reset;
}
return 0;
}
int main (void)
{
vector<Process*> inval;
ProcessEnumerator Penum("Memory.xml");
memory_info * mem;
for(int cnt = 0; cnt < 100; cnt++)
printhelp();
cout << endl;
// first test ProcessEnumerator and BadProcesses
{
// make the ProcessEnumerator update its list of Processes
// by passing the pointer to 'inval', we make it export expired
// processes instead of destroying them outright
// (processes expire when the OS kills them for whatever reason)
Penum.Refresh(&inval);
int nProc = Penum.size();
int nInval = inval.size();
cout << "Processes:" << endl;
for(int i = 0; i < nProc; i++)
cout << "Testing ProcessEnumerator" << endl;
ProcessEnumerator Penum("Memory.xml");
memory_info * mem;
do
{
mem = Penum[i]->getDescriptor();
cout << "DF instance: " << Penum[i]->getPID()
<< ", " << mem->getVersion() << endl;
}
// make the ProcessEnumerator update its list of Processes
// by passing the pointer to 'inval', we make it export expired
// processes instead of destroying them outright
// (processes expire when the OS kills them for whatever reason)
BadProcesses inval;
Penum.Refresh(&inval);
int nProc = Penum.size();
int nInval = inval.size();
cout << "Processes:" << endl;
for(int i = 0; i < nProc; i++)
{
mem = Penum[i]->getDescriptor();
cout << "DF instance: " << Penum[i]->getPID()
<< ", " << mem->getVersion() << endl;
}
cout << "Invalidated:" << endl;
for(int i = 0; i < nInval; i++)
cout << "Invalidated:" << endl;
for(int i = 0; i < nInval; i++)
{
mem = inval[i]->getDescriptor();
cout << "DF instance: " << inval[i]->getPID()
<< ", " << mem->getVersion() << endl;
}
}
while(inputwait("ProcessEnumerator"));
}
// next test ContextManager and BadContexts
{
cout << "Testing ProcessEnumerator" << endl;
ContextManager Cman("Memory.xml");
memory_info * mem;
do
{
mem = inval[i]->getDescriptor();
cout << "DF instance: " << inval[i]->getPID()
<< ", " << mem->getVersion() << endl;
// we own the expired process, we must take care of freeing its resources
delete inval[i];
// make the ProcessEnumerator update its list of Processes
// by passing the pointer to 'inval', we make it export expired
// processes instead of destroying them outright
// (processes expire when the OS kills them for whatever reason)
BadContexts inval;
Cman.Refresh(&inval);
int nCont = Cman.size();
int nInval = inval.size();
cout << "Contexts:" << endl;
for(int i = 0; i < nCont; i++)
{
mem = Cman[i]->getMemoryInfo();
cout << "DF instance: " << Cman[i]->getProcess()->getPID()
<< ", " << mem->getVersion() << endl;
}
cout << "Invalidated:" << endl;
for(int i = 0; i < nInval; i++)
{
mem = inval[i]->getMemoryInfo();
cout << "DF instance: " << inval[i]->getProcess()->getPID()
<< ", " << mem->getVersion() << endl;
}
}
cout << "<-* Press Enter to refresh *->" << endl << endl;
cin.ignore();
while(inputwait("ContextManager"));
}
#ifndef LINUX_BUILD
cout << "Done. Press any key to continue" << endl;
cin.ignore();