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;
memory_info * my_descriptor;
DFWindow * my_window;
uint32_t my_pid;
pid_t my_pid;
char *my_shm;
int my_shmid;
@ -56,6 +56,8 @@ class SHMProcess::Private
bool identified;
bool validate(char * exe_file, uint32_t pid, vector <memory_info> & known_versions);
bool waitWhile (DF_PINGPONG state);
bool DF_TestBridgeVersion(bool & ret);
bool DF_GetPID(pid_t & ret);
};
bool SHMProcess::Private::waitWhile (DF_PINGPONG state)
@ -91,33 +93,98 @@ bool SHMProcess::Private::waitWhile (DF_PINGPONG state)
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())
{
char exe_link_name [256];
char target_name[1024];
int target_result;
sprintf(exe_link_name,"/proc/%d/exe", pid);
// resolve /proc/PID/exe link
target_result = readlink(exe_link_name, target_name, sizeof(target_name)-1);
if (target_result == -1)
/*
* Locate the segment.
*/
if ((d->my_shmid = shmget(SHM_KEY, SHM_SIZE, 0666)) < 0)
{
perror("readlink");
return;
perror("shmget");
}
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()

@ -146,7 +146,7 @@ namespace DFHack
class Private;
private:
Private * const d;
SHMProcess(uint32_t pid, int shmid, char * shm, vector <memory_info> & known_versions);
SHMProcess(vector <memory_info> & known_versions);
~SHMProcess();
public:
// 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.)
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
{
public:
@ -96,70 +50,16 @@ bool ProcessEnumerator::findProcessess()
int errorcount;
int result;
char *shm = 0;
int shmid;
Process *p = 0;
/*
* Locate the segment.
*/
if ((shmid = shmget(SHM_KEY, SHM_SIZE, 0666)) < 0)
p = new SHMProcess(d->meminfo->meminfo);
if(p->isIdentified())
{
perror("shmget");
d->processes.push_back(p);
}
else
{
if ((shm = (char *) shmat(shmid, NULL, 0)) == (char *) -1)
{
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;
}
}
delete p;
p = 0;
}
// Open /proc/ directory