From de7c2185ebeaee69e0c102142e5d0969e6878a89 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Mr=C3=A1zek?= Date: Fri, 25 Dec 2009 02:49:35 +0000 Subject: [PATCH] shared memory manipulation is now entirely contained in the SHMProcess class --- library/DFProcess-linux-SHM.cpp | 107 ++++++++++++++++++++----- library/DFProcess.h | 2 +- library/DFProcessEnumerator-linux.cpp | 110 ++------------------------ 3 files changed, 93 insertions(+), 126 deletions(-) diff --git a/library/DFProcess-linux-SHM.cpp b/library/DFProcess-linux-SHM.cpp index 3d6d4203f..7c850b9e1 100644 --- a/library/DFProcess-linux-SHM.cpp +++ b/library/DFProcess-linux-SHM.cpp @@ -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 & 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 & 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 & 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() diff --git a/library/DFProcess.h b/library/DFProcess.h index 548399af0..7ce68850b 100644 --- a/library/DFProcess.h +++ b/library/DFProcess.h @@ -146,7 +146,7 @@ namespace DFHack class Private; private: Private * const d; - SHMProcess(uint32_t pid, int shmid, char * shm, vector & known_versions); + SHMProcess(vector & known_versions); ~SHMProcess(); public: // Set up stuff so we can read memory diff --git a/library/DFProcessEnumerator-linux.cpp b/library/DFProcessEnumerator-linux.cpp index 921383e98..d477a1a7d 100644 --- a/library/DFProcessEnumerator-linux.cpp +++ b/library/DFProcessEnumerator-linux.cpp @@ -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