shared memory manipulation is now entirely contained in the SHMProcess class

develop
Petr Mrázek 2009-12-25 02:49:35 +00:00
parent efce0ab21b
commit de7c2185eb
3 changed files with 93 additions and 126 deletions

@ -47,7 +47,7 @@ class SHMProcess::Private
DataModel* my_datamodel; DataModel* my_datamodel;
memory_info * my_descriptor; memory_info * my_descriptor;
DFWindow * my_window; DFWindow * my_window;
uint32_t my_pid; pid_t my_pid;
char *my_shm; char *my_shm;
int my_shmid; int my_shmid;
@ -56,6 +56,8 @@ class SHMProcess::Private
bool identified; bool identified;
bool validate(char * exe_file, uint32_t pid, vector <memory_info> & known_versions); bool validate(char * exe_file, uint32_t pid, vector <memory_info> & known_versions);
bool waitWhile (DF_PINGPONG state); bool waitWhile (DF_PINGPONG state);
bool DF_TestBridgeVersion(bool & ret);
bool DF_GetPID(pid_t & ret);
}; };
bool SHMProcess::Private::waitWhile (DF_PINGPONG state) bool SHMProcess::Private::waitWhile (DF_PINGPONG state)
@ -91,33 +93,98 @@ bool SHMProcess::Private::waitWhile (DF_PINGPONG state)
return true; return true;
} }
SHMProcess::SHMProcess(uint32_t pid, int shmid, char * shm, vector <memory_info> & known_versions) bool SHMProcess::Private::DF_TestBridgeVersion(bool & ret)
{
((shm_cmd *)my_shm)->pingpong = DFPP_VERSION;
if(!waitWhile(DFPP_VERSION))
return false;
((shm_cmd *)my_shm)->pingpong = DFPP_SUSPENDED;
ret =( ((shm_retval *)my_shm)->value == PINGPONG_VERSION );
return true;
}
bool SHMProcess::Private::DF_GetPID(pid_t & ret)
{
((shm_cmd *)my_shm)->pingpong = DFPP_PID;
if(!waitWhile(DFPP_PID))
return false;
((shm_cmd *)my_shm)->pingpong = DFPP_SUSPENDED;
ret = ((shm_retval *)my_shm)->value;
return true;
}
SHMProcess::SHMProcess(vector <memory_info> & known_versions)
: d(new Private()) : d(new Private())
{ {
char exe_link_name [256]; char exe_link_name [256];
char target_name[1024]; char target_name[1024];
int target_result; int target_result;
sprintf(exe_link_name,"/proc/%d/exe", pid); /*
* Locate the segment.
// resolve /proc/PID/exe link */
target_result = readlink(exe_link_name, target_name, sizeof(target_name)-1); if ((d->my_shmid = shmget(SHM_KEY, SHM_SIZE, 0666)) < 0)
if (target_result == -1)
{ {
perror("readlink"); perror("shmget");
return; }
else
{
if ((d->my_shm = (char *) shmat(d->my_shmid, NULL, 0)) == (char *) -1)
{
perror("shmat");
}
else
{
struct shmid_ds descriptor;
shmctl(d->my_shmid, IPC_STAT, &descriptor);
/*
* Now we attach the segment to our data space.
*/
if(descriptor.shm_nattch != 2)// badness
{
fprintf(stderr,"dfhack: no DF or different client already connected\n");
}
else
{
bool bridgeOK;
if(!d->DF_TestBridgeVersion(bridgeOK))
{
fprintf(stderr,"DF terminated during reading\n");
}
else
{
if(!bridgeOK)
{
fprintf(stderr,"SHM bridge version mismatch\n");
}
else
{
if(d->DF_GetPID(d->my_pid))
{
sprintf(exe_link_name,"/proc/%d/exe", d->my_pid);
// resolve /proc/PID/exe link
target_result = readlink(exe_link_name, target_name, sizeof(target_name)-1);
if (target_result == -1)
{
perror("readlink");
return;
}
// make sure we have a null terminated string...
target_name[target_result] = 0;
// is this the regular linux DF?
// create linux process, add it to the vector
d->validate(target_name,d->my_pid,known_versions );
d->my_window = new DFWindow(this);
}
}
}
// make sure we restart the process
((shm_cmd *)d->my_shm)->pingpong = DFPP_RUNNING;
}
}
} }
// make sure we have a null terminated string...
target_name[target_result] = 0;
// is this the regular linux DF?
// create linux process, add it to the vector
d->validate(target_name,pid,known_versions );
d->my_shmid = shmid;
d->my_shm = shm;
d->my_window = new DFWindow(this);
// make sure we restart the process
((shm_cmd *)d->my_shm)->pingpong = DFPP_RUNNING;
} }
bool SHMProcess::isSuspended() bool SHMProcess::isSuspended()

@ -146,7 +146,7 @@ namespace DFHack
class Private; class Private;
private: private:
Private * const d; Private * const d;
SHMProcess(uint32_t pid, int shmid, char * shm, vector <memory_info> & known_versions); SHMProcess(vector <memory_info> & known_versions);
~SHMProcess(); ~SHMProcess();
public: public:
// Set up stuff so we can read memory // Set up stuff so we can read memory

@ -34,52 +34,6 @@ using namespace DFHack;
/// HACK: global variables (only one process can be attached at the same time.) /// HACK: global variables (only one process can be attached at the same time.)
Process * DFHack::g_pProcess; ///< current process. non-NULL when picked Process * DFHack::g_pProcess; ///< current process. non-NULL when picked
bool waitWhile (char *shm, int shmid, uint32_t state)
{
uint32_t cnt = 0;
struct shmid_ds descriptor;
while (((shm_cmd *)shm)->pingpong == state)
{
if(cnt == 10000)
{
shmctl(shmid, IPC_STAT, &descriptor);
if(descriptor.shm_nattch == 1)// DF crashed?
{
((shm_cmd *)shm)->pingpong = DFPP_RUNNING;
fprintf(stderr,"dfhack: Broke out of loop, other process disappeared.\n");
return false;
}
else
{
cnt = 0;
}
}
cnt++;
}
if(((shm_cmd *)shm)->pingpong == DFPP_SV_ERROR) return false;
return true;
}
bool DF_TestBridgeVersion(char *shm, int shmid, bool & ret)
{
((shm_cmd *)shm)->pingpong = DFPP_VERSION;
if(!waitWhile(shm, shmid, DFPP_VERSION))
return false;
((shm_cmd *)shm)->pingpong = DFPP_SUSPENDED;
ret =( ((shm_retval *)shm)->value == PINGPONG_VERSION );
return true;
}
bool DF_GetPID(char *shm, int shmid, pid_t & ret)
{
((shm_cmd *)shm)->pingpong = DFPP_PID;
if(!waitWhile(shm, shmid, DFPP_PID))
return false;
((shm_cmd *)shm)->pingpong = DFPP_SUSPENDED;
ret = ((shm_retval *)shm)->value;
return true;
}
class DFHack::ProcessEnumerator::Private class DFHack::ProcessEnumerator::Private
{ {
public: public:
@ -96,70 +50,16 @@ bool ProcessEnumerator::findProcessess()
int errorcount; int errorcount;
int result; int result;
char *shm = 0;
int shmid;
Process *p = 0; Process *p = 0;
/* p = new SHMProcess(d->meminfo->meminfo);
* Locate the segment. if(p->isIdentified())
*/
if ((shmid = shmget(SHM_KEY, SHM_SIZE, 0666)) < 0)
{ {
perror("shmget"); d->processes.push_back(p);
} }
else else
{ {
if ((shm = (char *) shmat(shmid, NULL, 0)) == (char *) -1) delete p;
{ p = 0;
perror("shmat");
}
else
{
struct shmid_ds descriptor;
shmctl(shmid, IPC_STAT, &descriptor);
/*
* Now we attach the segment to our data space.
*/
if(descriptor.shm_nattch != 2)// badness
{
fprintf(stderr,"dfhack: WTF\n");
}
else
{
bool bridgeOK;
if(!DF_TestBridgeVersion(shm, shmid, bridgeOK))
{
fprintf(stderr,"DF terminated during reading\n");
}
else
{
if(!bridgeOK)
{
fprintf(stderr,"SHM bridge version mismatch\n");
}
else
{
pid_t DFPID;
if(DF_GetPID(shm, shmid, DFPID))
{
printf("shm: DF PID: %d\n",DFPID);
p = new SHMProcess(DFPID,shmid,shm,d->meminfo->meminfo);
}
}
}
}
if(p && p->isIdentified())
{
cerr << "added process to vector" << endl;
d->processes.push_back(p);
}
else
{
// couldn't use the hooked process, make sure it's running fine
((shm_cmd *)shm)->pingpong = DFPP_RUNNING;
delete p;
}
}
} }
// Open /proc/ directory // Open /proc/ directory