Merge branch 'shm-only'

develop
Petr Mrázek 2010-03-09 15:31:44 +01:00
commit 5c4ef73f4d
21 changed files with 1343 additions and 696 deletions

@ -47,9 +47,7 @@ int main (int numargs, char** args)
uint32_t x_max,y_max,z_max; uint32_t x_max,y_max,z_max;
uint32_t num_blocks = 0; uint32_t num_blocks = 0;
uint64_t bytes_read = 0; uint64_t bytes_read = 0;
uint16_t tiletypes[16][16]; DFHack::mapblock40d Block;
DFHack::t_designation designations[16][16];
DFHack::t_occupancy occupancies[16][16];
DFHack::API DF("Memory.xml"); DFHack::API DF("Memory.xml");
if(!DF.Attach()) if(!DF.Attach())
@ -76,11 +74,9 @@ int main (int numargs, char** args)
{ {
if(DF.isValidBlock(x,y,z)) if(DF.isValidBlock(x,y,z))
{ {
DF.ReadTileTypes(x,y,z, (uint16_t *) tiletypes); DF.ReadBlock40d(x, y, z, &Block);
DF.ReadDesignations(x,y,z, (uint32_t *) designations);
DF.ReadOccupancy(x,y,z, (uint32_t *) occupancies);
num_blocks ++; num_blocks ++;
bytes_read += sizeof(tiletypes) + sizeof(designations) + sizeof(occupancies); bytes_read += sizeof(DFHack::mapblock40d);
} }
} }
} }

@ -144,8 +144,6 @@ void clrscr()
GRASS2, GRASS2,
GRASS_DEAD, GRASS_DEAD,
GRASS_DRY, GRASS_DRY,
#include <DFProcess.h>
#include <DFProcess.h>
DRIFTWOOD, DRIFTWOOD,
HFS, HFS,
MAGMA, MAGMA,
@ -272,9 +270,12 @@ main(int argc, char *argv[])
int x_max,y_max,z_max; int x_max,y_max,z_max;
uint32_t x_max_a,y_max_a,z_max_a; uint32_t x_max_a,y_max_a,z_max_a;
/*
uint16_t tiletypes[16][16]; uint16_t tiletypes[16][16];
DFHack::t_designation designations[16][16]; DFHack::t_designation designations[16][16];
uint8_t regionoffsets[16]; uint8_t regionoffsets[16];
*/
mapblock40d Block;
map <int16_t, uint32_t> materials; map <int16_t, uint32_t> materials;
materials.clear(); materials.clear();
vector<DFHack::t_matgloss> stonetypes; vector<DFHack::t_matgloss> stonetypes;
@ -300,7 +301,6 @@ main(int argc, char *argv[])
error = "Can't find a map to look at."; error = "Can't find a map to look at.";
pDF = 0; pDF = 0;
finish(0); finish(0);
#include <DFMemInfo.h>
} }
DF.getSize(x_max_a,y_max_a,z_max_a); DF.getSize(x_max_a,y_max_a,z_max_a);
@ -337,6 +337,7 @@ main(int argc, char *argv[])
int filenum = 0; int filenum = 0;
bool dirtybit = false; bool dirtybit = false;
uint32_t blockaddr = 0; uint32_t blockaddr = 0;
uint32_t blockaddr2 = 0;
// walk the map! // walk the map!
for (;;) for (;;)
{ {
@ -401,30 +402,35 @@ main(int argc, char *argv[])
if(DF.isValidBlock(cursorX+i,cursorY+j,cursorZ)) if(DF.isValidBlock(cursorX+i,cursorY+j,cursorZ))
{ {
// read data // read data
DF.ReadBlock40d(cursorX+i,cursorY+j,cursorZ, &Block);
/*
DF.ReadTileTypes(cursorX+i,cursorY+j,cursorZ, (uint16_t *) tiletypes); DF.ReadTileTypes(cursorX+i,cursorY+j,cursorZ, (uint16_t *) tiletypes);
DF.ReadDesignations(cursorX+i,cursorY+j,cursorZ, (uint32_t *) designations); DF.ReadDesignations(cursorX+i,cursorY+j,cursorZ, (uint32_t *) designations);
*/
for(int x = 0; x < 16; x++) for(int x = 0; x < 16; x++)
{ {
for(int y = 0; y < 16; y++) for(int y = 0; y < 16; y++)
{ {
if(dig) if(dig)
{ {
if(tileTypeTable[tiletypes[x][y]].c == WALL && tileTypeTable[tiletypes[x][y]].m == VEIN TileClass tc = tileTypeTable[Block.tiletypes[x][y]].c;
|| tileTypeTable[tiletypes[x][y]].c == TREE_OK || tileTypeTable[tiletypes[x][y]].c == TREE_DEAD) TileMaterial tm = tileTypeTable[Block.tiletypes[x][y]].m;
if( tc == WALL && tm == VEIN || tc == TREE_OK || tc == TREE_DEAD)
{ {
designations[x][y].bits.dig = designation_default; Block.designaton[x][y].bits.dig = designation_default;
} }
} }
int color = COLOR_BLACK; int color = COLOR_BLACK;
color = pickColor(tiletypes[x][y]); color = pickColor(Block.tiletypes[x][y]);
if(designations[x][y].bits.hidden) if(Block.designaton[x][y].bits.hidden)
{ {
puttile(x+(i+1)*16,y+(j+1)*16,tiletypes[x][y], color); puttile(x+(i+1)*16,y+(j+1)*16,Block.tiletypes[x][y], color);
} }
else else
{ {
attron(A_STANDOUT); attron(A_STANDOUT);
puttile(x+(i+1)*16,y+(j+1)*16,tiletypes[x][y], color); puttile(x+(i+1)*16,y+(j+1)*16,Block.tiletypes[x][y], color);
attroff(A_STANDOUT); attroff(A_STANDOUT);
} }
} }
@ -433,13 +439,15 @@ main(int argc, char *argv[])
if(i == 0 && j == 0) if(i == 0 && j == 0)
{ {
blockaddr = DF.getBlockPtr(cursorX+i,cursorY+j,cursorZ); blockaddr = DF.getBlockPtr(cursorX+i,cursorY+j,cursorZ);
blockaddr2 = Block.origin;
if(dump) if(dump)
{ {
hexdump(DF,blockaddr,0x1E00/*0x1DB8*/,filenum); hexdump(DF,blockaddr,0x1E00,filenum);
filenum++; filenum++;
} }
if(dig) if(dig)
DF.WriteDesignations(cursorX+i,cursorY+j,cursorZ, (uint32_t *) designations); DF.WriteDesignations(cursorX+i,cursorY+j,cursorZ, (uint32_t *) Block.designaton);
DF.ReadDirtyBit(cursorX+i,cursorY+j,cursorZ,dirtybit); DF.ReadDirtyBit(cursorX+i,cursorY+j,cursorZ,dirtybit);
if(digbit) if(digbit)
{ {
@ -449,6 +457,7 @@ main(int argc, char *argv[])
veinVector.clear(); veinVector.clear();
IceVeinVector.clear(); IceVeinVector.clear();
DF.ReadVeins(cursorX+i,cursorY+j,cursorZ,veinVector,IceVeinVector); DF.ReadVeins(cursorX+i,cursorY+j,cursorZ,veinVector,IceVeinVector);
} }
} }
} }
@ -512,7 +521,7 @@ main(int argc, char *argv[])
} }
} }
gotoxy (0,52); gotoxy (0,52);
cprintf("block address 0x%x",blockaddr); cprintf("block address 0x%x 0x%x",blockaddr, blockaddr2);
gotoxy (0,53); gotoxy (0,53);
cprintf("dirty bit: %d",dirtybit); cprintf("dirty bit: %d",dirtybit);
gotoxy (0,54); gotoxy (0,54);

@ -210,6 +210,17 @@ namespace DFHack
return s.str().c_str(); return s.str().c_str();
} }
}; };
class DFHACK_EXPORT SHMServerDisappeared : public std::exception
{
public:
SHMServerDisappeared(){}
virtual ~SHMServerDisappeared() throw(){};
virtual const char* what() const throw()
{
return "The server process has disappeared";
}
};
} }
} }

@ -23,6 +23,9 @@ distribution.
*/ */
#include "DFCommonInternal.h" #include "DFCommonInternal.h"
#include "../shmserver/shms.h"
#include "../shmserver/mod-core.h"
#include "../shmserver/mod-maps.h"
using namespace DFHack; using namespace DFHack;
/* /*
@ -114,6 +117,7 @@ public:
ProcessEnumerator* pm; ProcessEnumerator* pm;
Process* p; Process* p;
char * shm_start;
memory_info* offset_descriptor; memory_info* offset_descriptor;
vector<uint16_t> v_geology[eBiomeCount]; vector<uint16_t> v_geology[eBiomeCount];
string xml; string xml;
@ -130,6 +134,8 @@ public:
bool hotkeyInited; bool hotkeyInited;
bool settlementsInited; bool settlementsInited;
bool nameTablesInited; bool nameTablesInited;
uint32_t maps_module;
uint32_t tree_offset; uint32_t tree_offset;
DfVector *p_cre; DfVector *p_cre;
@ -175,6 +181,8 @@ API::API (const string path_to_xml)
d->notesInited = false; d->notesInited = false;
d->hotkeyInited = false; d->hotkeyInited = false;
d->pm = NULL; d->pm = NULL;
d->shm_start = 0;
d->maps_module = 0;
} }
API::~API() API::~API()
@ -182,6 +190,11 @@ API::~API()
delete d; delete d;
} }
#define SHMCMD ((shm_cmd *)d->shm_start)->pingpong
#define SHMHDR ((shm_core_hdr *)d->shm_start)
#define SHMMAPSHDR ((Maps::shm_maps_hdr *)d->shm_start)
#define SHMDATA(type) ((type *)(d->shm_start + SHM_HEADER))
/*-----------------------------------* /*-----------------------------------*
* Init the mapblock pointer array * * Init the mapblock pointer array *
*-----------------------------------*/ *-----------------------------------*/
@ -207,19 +220,43 @@ bool API::InitMap()
d->offset_descriptor->resolveClassnameToVPtr("block_square_event_frozen_liquid", d->vein_ice_vptr); d->offset_descriptor->resolveClassnameToVPtr("block_square_event_frozen_liquid", d->vein_ice_vptr);
d->vein_mineral_vptr = 0; d->vein_mineral_vptr = 0;
d->offset_descriptor->resolveClassnameToVPtr("block_square_event_mineral",d->vein_mineral_vptr); d->offset_descriptor->resolveClassnameToVPtr("block_square_event_mineral",d->vein_mineral_vptr);
/*
* --> SHM initialization (if possible) <--
*/
g_pProcess->getModuleIndex("Maps",2,d->maps_module);
if(d->maps_module)
{
// supply the module with offsets so it can work with them
Maps::maps_offsets *off = SHMDATA(Maps::maps_offsets);
off->biome_stuffs = d->biome_stuffs;
off->designation_offset = d->designation_offset;
off->map_offset = map_offset;
off->occupancy_offset = d->occupancy_offset;
off->tile_type_offset = d->tile_type_offset;
off->vein_ice_vptr = d->vein_ice_vptr; // FIXME: not necessarily true, the shm server side needs a class lookup >_<
off->vein_mineral_vptr = d->vein_mineral_vptr; // FIXME: not necessarily true, the shm server side needs a class lookup >_<
off->veinvector = d->veinvector;
off->x_count_offset = x_count_offset;
off->y_count_offset = y_count_offset;
off->z_count_offset = z_count_offset;
full_barrier
const uint32_t cmd = Maps::MAP_INIT + d->maps_module << 16;
SHMCMD = cmd;
g_pProcess->waitWhile(cmd);
//cerr << "Map acceleration enabled!" << endl;
}
// get the map pointer // get the map pointer
uint32_t x_array_loc = g_pProcess->readDWord (map_offset); uint32_t x_array_loc = g_pProcess->readDWord (map_offset);
//FIXME: very inadequate
if (!x_array_loc) if (!x_array_loc)
{ {
throw Error::NoMapLoaded(); throw Error::NoMapLoaded();
// bad stuffz happend
//return false;
} }
uint32_t mx, my, mz;
// get the size // get the size
uint32_t mx, my, mz;
mx = d->x_block_count = g_pProcess->readDWord (x_count_offset); mx = d->x_block_count = g_pProcess->readDWord (x_count_offset);
my = d->y_block_count = g_pProcess->readDWord (y_count_offset); my = d->y_block_count = g_pProcess->readDWord (y_count_offset);
mz = d->z_block_count = g_pProcess->readDWord (z_count_offset); mz = d->z_block_count = g_pProcess->readDWord (z_count_offset);
@ -279,6 +316,43 @@ uint32_t API::getBlockPtr (uint32_t x, uint32_t y, uint32_t z)
return d->block[x*d->y_block_count*d->z_block_count + y*d->z_block_count + z]; return d->block[x*d->y_block_count*d->z_block_count + y*d->z_block_count + z];
} }
bool API::ReadBlock40d(uint32_t x, uint32_t y, uint32_t z, mapblock40d * buffer)
{
if(d->shm_start && d->maps_module) // ACCELERATE!
{
SHMMAPSHDR->x = x;
SHMMAPSHDR->y = y;
SHMMAPSHDR->z = z;
volatile uint32_t cmd = Maps::MAP_READ_BLOCK_BY_COORDS + (d->maps_module << 16);
full_barrier
SHMCMD = cmd;
full_barrier
if(!g_pProcess->waitWhile(cmd))
{
return false;
}
memcpy(buffer,SHMDATA(mapblock40d),sizeof(mapblock40d));
return true;
}
else // plain old block read
{
uint32_t addr = d->block[x*d->y_block_count*d->z_block_count + y*d->z_block_count + z];
if (addr)
{
g_pProcess->read (addr + d->tile_type_offset, sizeof (buffer->tiletypes), (uint8_t *) buffer->tiletypes);
g_pProcess->read (addr + d->occupancy_offset, sizeof (buffer->occupancy), (uint8_t *) buffer->occupancy);
g_pProcess->read (addr + d->designation_offset, sizeof (buffer->designaton), (uint8_t *) buffer->designaton);
g_pProcess->read (addr + d->biome_stuffs, sizeof (buffer->biome_indices), (uint8_t *) buffer->biome_indices);
buffer->origin = addr;
uint32_t addr_of_struct = g_pProcess->readDWord(addr);
buffer->dirty_dword = g_pProcess->readDWord(addr_of_struct);
return true;
}
return false;
}
}
// 256 * sizeof(uint16_t) // 256 * sizeof(uint16_t)
bool API::ReadTileTypes (uint32_t x, uint32_t y, uint32_t z, uint16_t *buffer) bool API::ReadTileTypes (uint32_t x, uint32_t y, uint32_t z, uint16_t *buffer)
{ {
@ -734,7 +808,7 @@ bool API::ReadGeology (vector < vector <uint16_t> >& assign)
} }
assign.clear(); assign.clear();
assign.reserve (eBiomeCount); assign.reserve (eBiomeCount);
// TODO: clean this up // // TODO: clean this up
for (int i = 0; i < eBiomeCount;i++) for (int i = 0; i < eBiomeCount;i++)
{ {
assign.push_back (d->v_geology[i]); assign.push_back (d->v_geology[i]);
@ -1373,6 +1447,7 @@ bool API::Attach()
//cerr << "couldn't attach to process" << endl; //cerr << "couldn't attach to process" << endl;
//return false; // couldn't attach to process, no go //return false; // couldn't attach to process, no go
} }
d->shm_start = d->p->getSHMStart();
d->offset_descriptor = d->p->getDescriptor(); d->offset_descriptor = d->p->getDescriptor();
// process is attached, everything went just fine... hopefully // process is attached, everything went just fine... hopefully
return true; return true;
@ -1391,6 +1466,7 @@ bool API::Detach()
} }
d->pm = NULL; d->pm = NULL;
d->p = NULL; d->p = NULL;
d->shm_start = 0;
d->offset_descriptor = NULL; d->offset_descriptor = NULL;
return true; return true;
} }

@ -135,6 +135,8 @@ namespace DFHack
*/ */
uint32_t getBlockPtr (uint32_t blockx, uint32_t blocky, uint32_t blockz); uint32_t getBlockPtr (uint32_t blockx, uint32_t blocky, uint32_t blockz);
bool ReadBlock40d(uint32_t blockx, uint32_t blocky, uint32_t blockz, mapblock40d * buffer);
bool ReadTileTypes(uint32_t blockx, uint32_t blocky, uint32_t blockz, uint16_t *buffer); // 256 * sizeof(uint16_t) bool ReadTileTypes(uint32_t blockx, uint32_t blocky, uint32_t blockz, uint16_t *buffer); // 256 * sizeof(uint16_t)
bool WriteTileTypes(uint32_t blockx, uint32_t blocky, uint32_t blockz, uint16_t *buffer); // 256 * sizeof(uint16_t) bool WriteTileTypes(uint32_t blockx, uint32_t blocky, uint32_t blockz, uint16_t *buffer); // 256 * sizeof(uint16_t)

@ -28,6 +28,7 @@ distribution.
#include <sys/ipc.h> #include <sys/ipc.h>
#include <time.h> #include <time.h>
#include "../shmserver/shms.h" #include "../shmserver/shms.h"
#include "../shmserver/mod-core.h"
#include <sys/time.h> #include <sys/time.h>
#include <time.h> #include <time.h>
#include <sched.h> #include <sched.h>
@ -50,6 +51,7 @@ class SHMProcess::Private
attached = false; attached = false;
suspended = false; suspended = false;
identified = false; identified = false;
useYield = false;
}; };
~Private(){}; ~Private(){};
memory_info * my_descriptor; memory_info * my_descriptor;
@ -57,32 +59,53 @@ class SHMProcess::Private
pid_t my_pid; pid_t my_pid;
char *my_shm; char *my_shm;
int my_shmid; int my_shmid;
Process* q;
bool attached; bool attached;
bool suspended; bool suspended;
bool identified; bool identified;
bool useYield;
bool validate(char* exe_file, uint32_t pid, std::vector< memory_info* >& known_versions); bool validate(char* exe_file, uint32_t pid, std::vector< memory_info* >& known_versions);
bool waitWhile (DF_PINGPONG state);
bool DF_TestBridgeVersion(bool & ret); bool Aux_Core_Attach(bool & versionOK, pid_t & PID);
bool DF_GetPID(pid_t & ret); bool waitWhile (uint32_t state);
}; };
bool SHMProcess::Private::waitWhile (DF_PINGPONG state) // some helpful macros to keep the code bloat in check
#define SHMCMD ((shm_cmd *)my_shm)->pingpong
#define D_SHMCMD ((shm_cmd *)d->my_shm)->pingpong
#define SHMHDR ((shm_core_hdr *)my_shm)
#define D_SHMHDR ((shm_core_hdr *)d->my_shm)
#define SHMDATA(type) ((type *)(my_shm + SHM_HEADER))
#define D_SHMDATA(type) ((type *)(d->my_shm + SHM_HEADER))
/*
Yeah. with no way to synchronize things (locks are slow, the OS doesn't give us enough control over scheduling)
we end up with this silly thing
*/
bool SHMProcess::Private::waitWhile (uint32_t state)
{ {
uint32_t cnt = 0; uint32_t cnt = 0;
struct shmid_ds descriptor; struct shmid_ds descriptor;
while (((shm_cmd *)my_shm)->pingpong == state) while (SHMCMD == state)
{ {
if(cnt == 10000) if(cnt == 10000)// check if the other process is still there
{ {
shmctl(my_shmid, IPC_STAT, &descriptor); shmctl(my_shmid, IPC_STAT, &descriptor);
if(descriptor.shm_nattch == 1)// DF crashed? if(descriptor.shm_nattch == 1)// DF crashed or exited - no way to tell?
{ {
gcc_barrier //detach the shared memory
((shm_cmd *)my_shm)->pingpong = DFPP_RUNNING; shmdt(my_shm);
attached = suspended = false; attached = suspended = false;
// we aren't the current process anymore
g_pProcess = NULL;
throw Error::SHMServerDisappeared();
return false; return false;
} }
else else
@ -90,12 +113,15 @@ bool SHMProcess::Private::waitWhile (DF_PINGPONG state)
cnt = 0; cnt = 0;
} }
} }
SCHED_YIELD if(useYield)
{
SCHED_YIELD
}
cnt++; cnt++;
} }
if(((shm_cmd *)my_shm)->pingpong == DFPP_SV_ERROR) if(SHMCMD == CORE_ERROR)
{ {
((shm_cmd *)my_shm)->pingpong = DFPP_RUNNING; SHMCMD = CORE_RUNNING;
attached = suspended = false; attached = suspended = false;
cerr << "shm server error!" << endl; cerr << "shm server error!" << endl;
assert (false); assert (false);
@ -104,31 +130,43 @@ bool SHMProcess::Private::waitWhile (DF_PINGPONG state)
return true; return true;
} }
bool SHMProcess::Private::DF_TestBridgeVersion(bool & ret) /*
Yeah. with no way to synchronize things (locks are slow, the OS doesn't give us enough control over scheduling)
we end up with this silly thing
*/
bool SHMProcess::waitWhile (uint32_t state)
{ {
((shm_cmd *)my_shm)->pingpong = DFPP_VERSION; return d->waitWhile(state);
gcc_barrier
if(!waitWhile(DFPP_VERSION))
return false;
gcc_barrier
((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) uint32_t OS_getAffinity()
{ {
((shm_cmd *)my_shm)->pingpong = DFPP_PID; cpu_set_t mask;
sched_getaffinity(0,sizeof(cpu_set_t),&mask);
// FIXME: truncation
uint32_t affinity = *(uint32_t *) &mask;
return affinity;
}
bool SHMProcess::Private::Aux_Core_Attach(bool & versionOK, pid_t & PID)
{
SHMDATA(coreattach)->cl_affinity = OS_getAffinity();
gcc_barrier gcc_barrier
if(!waitWhile(DFPP_PID)) SHMCMD = CORE_ATTACH;
if(!waitWhile(CORE_ATTACH))
return false; return false;
gcc_barrier gcc_barrier
((shm_cmd *)my_shm)->pingpong = DFPP_SUSPENDED; versionOK =( SHMDATA(coreattach)->sv_version == CORE_VERSION );
ret = ((shm_retval *)my_shm)->value; PID = SHMDATA(coreattach)->sv_PID;
useYield = SHMDATA(coreattach)->sv_useYield;
#ifdef DEBUG
if(useYield) cerr << "Using Yield!" << endl;
#endif
return true; return true;
} }
SHMProcess::SHMProcess(vector <memory_info *> & known_versions) SHMProcess::SHMProcess(uint32_t PID, vector< memory_info* >& known_versions)
: d(new Private()) : d(new Private())
{ {
char exe_link_name [256]; char exe_link_name [256];
@ -138,7 +176,7 @@ SHMProcess::SHMProcess(vector <memory_info *> & known_versions)
/* /*
* Locate the segment. * Locate the segment.
*/ */
if ((d->my_shmid = shmget(SHM_KEY, SHM_SIZE, 0666)) < 0) if ((d->my_shmid = shmget(SHM_KEY + PID, SHM_SIZE, 0666)) < 0)
{ {
return; return;
} }
@ -164,43 +202,43 @@ SHMProcess::SHMProcess(vector <memory_info *> & known_versions)
} }
/* /*
* Test bridge version, will also detect when we connect to something that doesn't respond * Test bridge version, get PID, sync Yield
*/ */
bool bridgeOK; bool bridgeOK;
if(!d->DF_TestBridgeVersion(bridgeOK)) if(!d->Aux_Core_Attach(bridgeOK,d->my_pid))
{ {
fprintf(stderr,"DF terminated during reading\n"); fprintf(stderr,"DF terminated during reading\n");
shmdt(d->my_shm);
return; return;
} }
if(!bridgeOK) if(!bridgeOK)
{ {
fprintf(stderr,"SHM bridge version mismatch\n"); fprintf(stderr,"SHM bridge version mismatch\n");
shmdt(d->my_shm);
return; return;
} }
/*
* get the PID from DF // find the binary
*/ sprintf(exe_link_name,"/proc/%d/exe", d->my_pid);
if(d->DF_GetPID(d->my_pid)) target_result = readlink(exe_link_name, target_name, sizeof(target_name)-1);
if (target_result == -1)
{ {
// find its binary perror("readlink");
sprintf(exe_link_name,"/proc/%d/exe", d->my_pid); shmdt(d->my_shm);
target_result = readlink(exe_link_name, target_name, sizeof(target_name)-1); return;
if (target_result == -1)
{
perror("readlink");
return;
}
// make sure we have a null terminated string...
// see http://www.opengroup.org/onlinepubs/000095399/functions/readlink.html
target_name[target_result] = 0;
// try to identify the DF version
d->validate(target_name, d->my_pid, known_versions);
d->my_window = new DFWindow(this);
} }
// make sure we have a null terminated string...
// see http://www.opengroup.org/onlinepubs/000095399/functions/readlink.html
target_name[target_result] = 0;
// try to identify the DF version
d->validate(target_name, d->my_pid, known_versions);
d->my_window = new DFWindow(this);
gcc_barrier gcc_barrier
// at this point, DF is stopped and waiting for commands. make it run again // at this point, DF is stopped and waiting for commands. make it run again
((shm_cmd *)d->my_shm)->pingpong = DFPP_RUNNING; D_SHMCMD = CORE_RUNNING;
shmdt(d->my_shm); // detach so we don't attach twice when attach() is called shmdt(d->my_shm); // detach so we don't attach twice when attach() is called
} }
@ -319,8 +357,8 @@ bool SHMProcess::suspend()
{ {
return true; return true;
} }
((shm_cmd *)d->my_shm)->pingpong = DFPP_SUSPEND; D_SHMCMD = CORE_SUSPEND;
if(!d->waitWhile(DFPP_SUSPEND)) if(!waitWhile(CORE_SUSPEND))
{ {
return false; return false;
} }
@ -338,14 +376,14 @@ bool SHMProcess::asyncSuspend()
{ {
return true; return true;
} }
if(((shm_cmd *)d->my_shm)->pingpong == DFPP_SUSPENDED) if(D_SHMCMD == CORE_SUSPENDED)
{ {
d->suspended = true; d->suspended = true;
return true; return true;
} }
else else
{ {
((shm_cmd *)d->my_shm)->pingpong = DFPP_SUSPEND; D_SHMCMD = CORE_SUSPEND;
return false; return false;
} }
} }
@ -361,7 +399,7 @@ bool SHMProcess::resume()
return false; return false;
if(!d->suspended) if(!d->suspended)
return true; return true;
((shm_cmd *)d->my_shm)->pingpong = DFPP_RUNNING; D_SHMCMD = CORE_RUNNING;
d->suspended = false; d->suspended = false;
return true; return true;
} }
@ -425,11 +463,11 @@ void SHMProcess::read (uint32_t src_address, uint32_t size, uint8_t *target_buff
// normal read under 1MB // normal read under 1MB
if(size <= SHM_BODY) if(size <= SHM_BODY)
{ {
((shm_read *)d->my_shm)->address = src_address; D_SHMHDR->address = src_address;
((shm_read *)d->my_shm)->length = size; D_SHMHDR->length = size;
gcc_barrier gcc_barrier
((shm_read *)d->my_shm)->pingpong = DFPP_READ; D_SHMCMD = CORE_DFPP_READ;
d->waitWhile(DFPP_READ); waitWhile(CORE_DFPP_READ);
memcpy (target_buffer, d->my_shm + SHM_HEADER,size); memcpy (target_buffer, d->my_shm + SHM_HEADER,size);
} }
// a big read, we pull data over the shm in iterations // a big read, we pull data over the shm in iterations
@ -440,11 +478,11 @@ void SHMProcess::read (uint32_t src_address, uint32_t size, uint8_t *target_buff
while (size) while (size)
{ {
// read to_read bytes from src_cursor // read to_read bytes from src_cursor
((shm_read *)d->my_shm)->address = src_address; D_SHMHDR->address = src_address;
((shm_read *)d->my_shm)->length = to_read; D_SHMHDR->length = to_read;
gcc_barrier gcc_barrier
((shm_read *)d->my_shm)->pingpong = DFPP_READ; D_SHMCMD = CORE_DFPP_READ;
d->waitWhile(DFPP_READ); waitWhile(CORE_DFPP_READ);
memcpy (target_buffer, d->my_shm + SHM_HEADER,size); memcpy (target_buffer, d->my_shm + SHM_HEADER,size);
// decrease size by bytes read // decrease size by bytes read
size -= to_read; size -= to_read;
@ -459,55 +497,55 @@ void SHMProcess::read (uint32_t src_address, uint32_t size, uint8_t *target_buff
uint8_t SHMProcess::readByte (const uint32_t offset) uint8_t SHMProcess::readByte (const uint32_t offset)
{ {
((shm_read_small *)d->my_shm)->address = offset; D_SHMHDR->address = offset;
gcc_barrier gcc_barrier
((shm_read_small *)d->my_shm)->pingpong = DFPP_READ_BYTE; D_SHMCMD = CORE_READ_BYTE;
d->waitWhile(DFPP_READ_BYTE); waitWhile(CORE_READ_BYTE);
return ((shm_retval *)d->my_shm)->value; return D_SHMHDR->value;
} }
void SHMProcess::readByte (const uint32_t offset, uint8_t &val ) void SHMProcess::readByte (const uint32_t offset, uint8_t &val )
{ {
((shm_read_small *)d->my_shm)->address = offset; D_SHMHDR->address = offset;
gcc_barrier gcc_barrier
((shm_read_small *)d->my_shm)->pingpong = DFPP_READ_BYTE; D_SHMCMD = CORE_READ_BYTE;
d->waitWhile(DFPP_READ_BYTE); waitWhile(CORE_READ_BYTE);
val = ((shm_retval *)d->my_shm)->value; val = D_SHMHDR->value;
} }
uint16_t SHMProcess::readWord (const uint32_t offset) uint16_t SHMProcess::readWord (const uint32_t offset)
{ {
((shm_read_small *)d->my_shm)->address = offset; D_SHMHDR->address = offset;
gcc_barrier gcc_barrier
((shm_read_small *)d->my_shm)->pingpong = DFPP_READ_WORD; D_SHMCMD = CORE_READ_WORD;
d->waitWhile(DFPP_READ_WORD); waitWhile(CORE_READ_WORD);
return ((shm_retval *)d->my_shm)->value; return D_SHMHDR->value;
} }
void SHMProcess::readWord (const uint32_t offset, uint16_t &val) void SHMProcess::readWord (const uint32_t offset, uint16_t &val)
{ {
((shm_read_small *)d->my_shm)->address = offset; D_SHMHDR->address = offset;
gcc_barrier gcc_barrier
((shm_read_small *)d->my_shm)->pingpong = DFPP_READ_WORD; D_SHMCMD = CORE_READ_WORD;
d->waitWhile(DFPP_READ_WORD); waitWhile(CORE_READ_WORD);
val = ((shm_retval *)d->my_shm)->value; val = D_SHMHDR->value;
} }
uint32_t SHMProcess::readDWord (const uint32_t offset) uint32_t SHMProcess::readDWord (const uint32_t offset)
{ {
((shm_read_small *)d->my_shm)->address = offset; D_SHMHDR->address = offset;
gcc_barrier gcc_barrier
((shm_read_small *)d->my_shm)->pingpong = DFPP_READ_DWORD; D_SHMCMD = CORE_READ_DWORD;
d->waitWhile(DFPP_READ_DWORD); waitWhile(CORE_READ_DWORD);
return ((shm_retval *)d->my_shm)->value; return D_SHMHDR->value;
} }
void SHMProcess::readDWord (const uint32_t offset, uint32_t &val) void SHMProcess::readDWord (const uint32_t offset, uint32_t &val)
{ {
((shm_read_small *)d->my_shm)->address = offset; D_SHMHDR->address = offset;
gcc_barrier gcc_barrier
((shm_read_small *)d->my_shm)->pingpong = DFPP_READ_DWORD; D_SHMCMD = CORE_READ_DWORD;
d->waitWhile(DFPP_READ_DWORD); waitWhile(CORE_READ_DWORD);
val = ((shm_retval *)d->my_shm)->value; val = D_SHMHDR->value;
} }
/* /*
@ -516,30 +554,30 @@ void SHMProcess::readDWord (const uint32_t offset, uint32_t &val)
void SHMProcess::writeDWord (uint32_t offset, uint32_t data) void SHMProcess::writeDWord (uint32_t offset, uint32_t data)
{ {
((shm_write_small *)d->my_shm)->address = offset; D_SHMHDR->address = offset;
((shm_write_small *)d->my_shm)->value = data; D_SHMHDR->value = data;
gcc_barrier gcc_barrier
((shm_write_small *)d->my_shm)->pingpong = DFPP_WRITE_DWORD; D_SHMCMD = CORE_WRITE_DWORD;
d->waitWhile(DFPP_WRITE_DWORD); waitWhile(CORE_WRITE_DWORD);
} }
// using these is expensive. // using these is expensive.
void SHMProcess::writeWord (uint32_t offset, uint16_t data) void SHMProcess::writeWord (uint32_t offset, uint16_t data)
{ {
((shm_write_small *)d->my_shm)->address = offset; D_SHMHDR->address = offset;
((shm_write_small *)d->my_shm)->value = data; D_SHMHDR->value = data;
gcc_barrier gcc_barrier
((shm_write_small *)d->my_shm)->pingpong = DFPP_WRITE_WORD; D_SHMCMD = CORE_WRITE_WORD;
d->waitWhile(DFPP_WRITE_WORD); waitWhile(CORE_WRITE_WORD);
} }
void SHMProcess::writeByte (uint32_t offset, uint8_t data) void SHMProcess::writeByte (uint32_t offset, uint8_t data)
{ {
((shm_write_small *)d->my_shm)->address = offset; D_SHMHDR->address = offset;
((shm_write_small *)d->my_shm)->value = data; D_SHMHDR->value = data;
gcc_barrier gcc_barrier
((shm_write_small *)d->my_shm)->pingpong = DFPP_WRITE_BYTE; D_SHMCMD = CORE_WRITE_BYTE;
d->waitWhile(DFPP_WRITE_BYTE); waitWhile(CORE_WRITE_BYTE);
} }
void SHMProcess::write (uint32_t dst_address, uint32_t size, uint8_t *source_buffer) void SHMProcess::write (uint32_t dst_address, uint32_t size, uint8_t *source_buffer)
@ -547,12 +585,12 @@ void SHMProcess::write (uint32_t dst_address, uint32_t size, uint8_t *source_buf
// normal write under 1MB // normal write under 1MB
if(size <= SHM_BODY) if(size <= SHM_BODY)
{ {
((shm_write *)d->my_shm)->address = dst_address; D_SHMHDR->address = dst_address;
((shm_write *)d->my_shm)->length = size; D_SHMHDR->length = size;
memcpy(d->my_shm+SHM_HEADER,source_buffer, size); memcpy(d->my_shm+SHM_HEADER,source_buffer, size);
gcc_barrier gcc_barrier
((shm_write *)d->my_shm)->pingpong = DFPP_WRITE; D_SHMCMD = CORE_WRITE;
d->waitWhile(DFPP_WRITE); waitWhile(CORE_WRITE);
} }
// a big write, we push this over the shm in iterations // a big write, we push this over the shm in iterations
else else
@ -562,12 +600,12 @@ void SHMProcess::write (uint32_t dst_address, uint32_t size, uint8_t *source_buf
while (size) while (size)
{ {
// write to_write bytes to dst_cursor // write to_write bytes to dst_cursor
((shm_write *)d->my_shm)->address = dst_address; D_SHMHDR->address = dst_address;
((shm_write *)d->my_shm)->length = to_write; D_SHMHDR->length = to_write;
memcpy(d->my_shm+SHM_HEADER,source_buffer, to_write); memcpy(d->my_shm+SHM_HEADER,source_buffer, to_write);
gcc_barrier gcc_barrier
((shm_write *)d->my_shm)->pingpong = DFPP_WRITE; D_SHMCMD = CORE_WRITE;
d->waitWhile(DFPP_WRITE); waitWhile(CORE_WRITE);
// decrease size by bytes written // decrease size by bytes written
size -= to_write; size -= to_write;
// move the cursors // move the cursors
@ -615,21 +653,21 @@ DfVector SHMProcess::readVector (uint32_t offset, uint32_t item_size)
const std::string SHMProcess::readSTLString(uint32_t offset) const std::string SHMProcess::readSTLString(uint32_t offset)
{ {
((shm_read_small *)d->my_shm)->address = offset; D_SHMHDR->address = offset;
full_barrier full_barrier
((shm_read_small *)d->my_shm)->pingpong = DFPP_READ_STL_STRING; D_SHMCMD = CORE_READ_STL_STRING;
d->waitWhile(DFPP_READ_STL_STRING); waitWhile(CORE_READ_STL_STRING);
//int length = ((shm_retval *)d->my_shm)->value; //int length = ((shm_retval *)d->my_shm)->value;
return(string( (char *)d->my_shm+SHM_HEADER)); return(string( (char *)d->my_shm+SHM_HEADER));
} }
size_t SHMProcess::readSTLString (uint32_t offset, char * buffer, size_t bufcapacity) size_t SHMProcess::readSTLString (uint32_t offset, char * buffer, size_t bufcapacity)
{ {
((shm_read_small *)d->my_shm)->address = offset; D_SHMHDR->address = offset;
full_barrier full_barrier
((shm_read_small *)d->my_shm)->pingpong = DFPP_READ_STL_STRING; D_SHMCMD = CORE_READ_STL_STRING;
d->waitWhile(DFPP_READ_STL_STRING); waitWhile(CORE_READ_STL_STRING);
size_t length = ((shm_retval *)d->my_shm)->value; size_t length = D_SHMHDR->value;
size_t fit = min(bufcapacity - 1, length); size_t fit = min(bufcapacity - 1, length);
strncpy(buffer,(char *)d->my_shm+SHM_HEADER,fit); strncpy(buffer,(char *)d->my_shm+SHM_HEADER,fit);
buffer[fit] = 0; buffer[fit] = 0;
@ -638,11 +676,11 @@ size_t SHMProcess::readSTLString (uint32_t offset, char * buffer, size_t bufcapa
void SHMProcess::writeSTLString(const uint32_t address, const std::string writeString) void SHMProcess::writeSTLString(const uint32_t address, const std::string writeString)
{ {
((shm_write_small *)d->my_shm)->address = address; D_SHMHDR->address = address;
strncpy(d->my_shm+SHM_HEADER,writeString.c_str(),writeString.length()+1); // length + 1 for the null terminator strncpy(d->my_shm+SHM_HEADER,writeString.c_str(),writeString.length()+1); // length + 1 for the null terminator
full_barrier full_barrier
((shm_write_small *)d->my_shm)->pingpong = DFPP_WRITE_STL_STRING; D_SHMCMD = CORE_WRITE_STL_STRING;
d->waitWhile(DFPP_WRITE_STL_STRING); waitWhile(CORE_WRITE_STL_STRING);
} }
string SHMProcess::readClassName (uint32_t vptr) string SHMProcess::readClassName (uint32_t vptr)
@ -653,4 +691,37 @@ string SHMProcess::readClassName (uint32_t vptr)
size_t start = raw.find_first_of("abcdefghijklmnopqrstuvwxyz");// trim numbers size_t start = raw.find_first_of("abcdefghijklmnopqrstuvwxyz");// trim numbers
size_t end = raw.length(); size_t end = raw.length();
return raw.substr(start,end-start - 2); // trim the 'st' from the end return raw.substr(start,end-start - 2); // trim the 'st' from the end
}
// FIXME: having this around could lead to bad things in the hands of unsuspecting fools
// *!!DON'T BE AN UNSUSPECTING FOOL!!*
// the whole SHM thing works only because copying DWORDS is an atomic operation on i386 and x86_64 archs
// get module index by name and version. bool 1 = error
bool SHMProcess::getModuleIndex (const char * name, const uint32_t version, uint32_t & OUTPUT)
{
modulelookup * payload = (modulelookup *) (d->my_shm + SHM_HEADER);
payload->version = version;
strncpy(payload->name,name,255);
payload->name[255] = 0;
full_barrier
D_SHMCMD = CORE_ACQUIRE_MODULE;
if(!waitWhile(CORE_ACQUIRE_MODULE))
{
return false; // FIXME: throw a fatal exception instead
}
if(D_SHMHDR->error)
{
return false;
}
//fprintf(stderr,"%s v%d : %d\n", name, version, D_SHMHDR->value);
OUTPUT = D_SHMHDR->value;
return true;
}
char * SHMProcess::getSHMStart (void)
{
return d->my_shm;
} }

@ -23,6 +23,7 @@ distribution.
*/ */
#include "DFCommonInternal.h" #include "DFCommonInternal.h"
#include "../shmserver/shms.h" #include "../shmserver/shms.h"
#include "../shmserver/mod-core.h"
using namespace DFHack; using namespace DFHack;
// a full memory barrier! better be safe than sorry. // a full memory barrier! better be safe than sorry.
@ -38,6 +39,7 @@ class SHMProcess::Private
attached = false; attached = false;
suspended = false; suspended = false;
identified = false; identified = false;
useYield = 0;
DFSVMutex = 0; DFSVMutex = 0;
DFCLMutex = 0; DFCLMutex = 0;
}; };
@ -52,13 +54,23 @@ class SHMProcess::Private
bool attached; bool attached;
bool suspended; bool suspended;
bool identified; bool identified;
bool useYield;
bool waitWhile (DF_PINGPONG state); bool waitWhile (uint32_t state);
bool isValidSV(); bool isValidSV();
bool DF_TestBridgeVersion(bool & ret); bool Aux_Core_Attach(bool & versionOK, uint32_t & PID);
bool DF_GetPID(uint32_t & ret);
}; };
// some helpful macros to keep the code bloat in check
#define SHMCMD ((shm_cmd *)my_shm)->pingpong
#define D_SHMCMD ((shm_cmd *)d->my_shm)->pingpong
#define SHMHDR ((shm_core_hdr *)my_shm)
#define D_SHMHDR ((shm_core_hdr *)d->my_shm)
#define SHMDATA(type) ((type *)(my_shm + SHM_HEADER))
#define D_SHMDATA(type) ((type *)(d->my_shm + SHM_HEADER))
// is the other side still there? // is the other side still there?
bool SHMProcess::Private::isValidSV() bool SHMProcess::Private::isValidSV()
{ {
@ -87,20 +99,29 @@ bool SHMProcess::Private::isValidSV()
} }
} }
bool SHMProcess::Private::waitWhile (DF_PINGPONG state) bool SHMProcess::waitWhile (uint32_t state)
{
return d->waitWhile(state);
}
bool SHMProcess::Private::waitWhile (uint32_t state)
{ {
uint32_t cnt = 0; uint32_t cnt = 0;
SCHED_YIELD // yield the CPU, valid only on single-core CPUs while (SHMCMD == state)
while (((shm_cmd *)my_shm)->pingpong == state)
{ {
// yield the CPU, only on single-core CPUs
if(useYield)
{
SCHED_YIELD
}
if(cnt == 10000) if(cnt == 10000)
{ {
if(!isValidSV())// DF not there anymore? if(!isValidSV())// DF not there anymore?
{ {
full_barrier
((shm_cmd *)my_shm)->pingpong = DFPP_RUNNING;
attached = suspended = false; attached = suspended = false;
ReleaseMutex(DFCLMutex); ReleaseMutex(DFCLMutex);
UnmapViewOfFile(my_shm);
throw Error::SHMServerDisappeared();
return false; return false;
} }
else else
@ -110,79 +131,84 @@ bool SHMProcess::Private::waitWhile (DF_PINGPONG state)
} }
cnt++; cnt++;
} }
if(((shm_cmd *)my_shm)->pingpong == DFPP_SV_ERROR) if(SHMCMD == CORE_ERROR)
{ {
((shm_cmd *)my_shm)->pingpong = DFPP_RUNNING; SHMCMD = CORE_RUNNING;
attached = suspended = false; attached = suspended = false;
cerr << "shm server error!" << endl; cerr << "shm server error!" << endl;
assert (false);
return false; return false;
} }
return true; return true;
} }
bool SHMProcess::Private::DF_TestBridgeVersion(bool & ret) uint32_t OS_getAffinity()
{ {
((shm_cmd *)my_shm)->pingpong = DFPP_VERSION; HANDLE hProcess = GetCurrentProcess();
full_barrier DWORD dwProcessAffinityMask, dwSystemAffinityMask;
if(!waitWhile(DFPP_VERSION)) GetProcessAffinityMask( hProcess, &dwProcessAffinityMask, &dwSystemAffinityMask );
return false; return dwProcessAffinityMask;
full_barrier
((shm_cmd *)my_shm)->pingpong = DFPP_SUSPENDED;
ret =( ((shm_retval *)my_shm)->value == PINGPONG_VERSION );
return true;
} }
bool SHMProcess::Private::DF_GetPID(uint32_t & ret) bool SHMProcess::Private::Aux_Core_Attach(bool & versionOK, uint32_t & PID)
{ {
((shm_cmd *)my_shm)->pingpong = DFPP_PID; SHMDATA(coreattach)->cl_affinity = OS_getAffinity();
full_barrier full_barrier
if(!waitWhile(DFPP_PID)) SHMCMD = CORE_ATTACH;
if(!waitWhile(CORE_ATTACH))
return false; return false;
full_barrier full_barrier
((shm_cmd *)my_shm)->pingpong = DFPP_SUSPENDED; versionOK =( SHMDATA(coreattach)->sv_version == CORE_VERSION );
ret = ((shm_retval *)my_shm)->value; PID = SHMDATA(coreattach)->sv_PID;
useYield = SHMDATA(coreattach)->sv_useYield;
#ifdef DEBUG
if(useYield) cerr << "Using Yield!" << endl;
#endif
return true; return true;
} }
SHMProcess::SHMProcess(vector <memory_info *> & known_versions) SHMProcess::SHMProcess(uint32_t PID, vector <memory_info *> & known_versions)
: d(new Private()) : d(new Private())
{ {
char svmutexname [256];
sprintf(svmutexname,"DFSVMutex-%d",PID);
char clmutexname [256];
sprintf(clmutexname,"DFCLMutex-%d",PID);
// get server and client mutex // get server and client mutex
d->DFSVMutex = OpenMutex(SYNCHRONIZE,false, "DFSVMutex"); d->DFSVMutex = OpenMutex(SYNCHRONIZE,false, svmutexname);
if(d->DFSVMutex == 0) if(d->DFSVMutex == 0)
{ {
return; return;
} }
d->DFCLMutex = OpenMutex(SYNCHRONIZE,false, "DFCLMutex"); d->DFCLMutex = OpenMutex(SYNCHRONIZE,false, clmutexname);
if(d->DFCLMutex == 0) if(d->DFCLMutex == 0)
{ {
return; return;
} }
d->my_pid = PID;
// attach the SHM
if(!attach()) if(!attach())
{ {
return; return;
} }
// All seems to be OK so far. Attached and connected to something that looks like DF // Test bridge version, get PID, sync Yield
// Test bridge version, will also detect when we connect to something that doesn't respond
bool bridgeOK; bool bridgeOK;
if(!d->DF_TestBridgeVersion(bridgeOK)) bool error = 0;
if(!d->Aux_Core_Attach(bridgeOK,d->my_pid))
{ {
fprintf(stderr,"DF terminated during reading\n"); fprintf(stderr,"DF terminated during reading\n");
UnmapViewOfFile(d->my_shm); error = 1;
ReleaseMutex(d->DFCLMutex);
CloseHandle(d->DFSVMutex);
d->DFSVMutex = 0;
CloseHandle(d->DFCLMutex);
d->DFCLMutex = 0;
return;
} }
if(!bridgeOK) else if(!bridgeOK)
{ {
fprintf(stderr,"SHM bridge version mismatch\n"); fprintf(stderr,"SHM bridge version mismatch\n");
((shm_cmd *)d->my_shm)->pingpong = DFPP_RUNNING; error = 1;
}
if(error)
{
D_SHMCMD = CORE_RUNNING;
UnmapViewOfFile(d->my_shm); UnmapViewOfFile(d->my_shm);
ReleaseMutex(d->DFCLMutex); ReleaseMutex(d->DFCLMutex);
CloseHandle(d->DFSVMutex); CloseHandle(d->DFSVMutex);
@ -191,83 +217,78 @@ SHMProcess::SHMProcess(vector <memory_info *> & known_versions)
d->DFCLMutex = 0; d->DFCLMutex = 0;
return; return;
} }
/*
* get the PID from DF // try to identify the DF version
*/ do // glorified goto
if(d->DF_GetPID(d->my_pid)) {
{ IMAGE_NT_HEADERS32 pe_header;
// try to identify the DF version IMAGE_SECTION_HEADER sections[16];
do // glorified goto HMODULE hmod = NULL;
{ DWORD junk;
IMAGE_NT_HEADERS32 pe_header; HANDLE hProcess;
IMAGE_SECTION_HEADER sections[16]; bool found = false;
HMODULE hmod = NULL; d->identified = false;
DWORD junk; // open process, we only need the process open
HANDLE hProcess; hProcess = OpenProcess( PROCESS_ALL_ACCESS, FALSE, d->my_pid );
bool found = false; if (NULL == hProcess)
d->identified = false; break;
// open process, we only need the process open
hProcess = OpenProcess( PROCESS_ALL_ACCESS, FALSE, d->my_pid );
if (NULL == hProcess)
break;
// try getting the first module of the process
if(EnumProcessModules(hProcess, &hmod, 1 * sizeof(HMODULE), &junk) == 0)
{
CloseHandle(hProcess);
cout << "EnumProcessModules fail'd" << endl;
break;
}
// got base ;)
uint32_t base = (uint32_t)hmod;
// read from this process
uint32_t pe_offset = readDWord(base+0x3C);
read(base + pe_offset , sizeof(pe_header), (uint8_t *)&pe_header);
read(base + pe_offset+ sizeof(pe_header), sizeof(sections) , (uint8_t *)&sections );
// iterate over the list of memory locations
vector<memory_info *>::iterator it;
for ( it=known_versions.begin() ; it < known_versions.end(); it++ )
{
uint32_t pe_timestamp;
try
{
pe_timestamp = (*it)->getHexValue("pe_timestamp");
}
catch(Error::MissingMemoryDefinition& e)
{
continue;
}
if (pe_timestamp == pe_header.FileHeader.TimeDateStamp)
{
memory_info *m = new memory_info(**it);
m->RebaseAll(base);
d->my_descriptor = m;
d->identified = true;
cerr << "identified " << m->getVersion() << endl;
break;
}
}
CloseHandle(hProcess);
} while (0); // glorified goto end
if(d->identified) // try getting the first module of the process
if(EnumProcessModules(hProcess, &hmod, 1 * sizeof(HMODULE), &junk) == 0)
{ {
d->my_window = new DFWindow(this); CloseHandle(hProcess);
// cout << "EnumProcessModules fail'd" << endl;
break;
} }
else // got base ;)
uint32_t base = (uint32_t)hmod;
// read from this process
uint32_t pe_offset = readDWord(base+0x3C);
read(base + pe_offset , sizeof(pe_header), (uint8_t *)&pe_header);
read(base + pe_offset+ sizeof(pe_header), sizeof(sections) , (uint8_t *)&sections );
// iterate over the list of memory locations
vector<memory_info *>::iterator it;
for ( it=known_versions.begin() ; it < known_versions.end(); it++ )
{ {
((shm_cmd *)d->my_shm)->pingpong = DFPP_RUNNING; uint32_t pe_timestamp;
UnmapViewOfFile(d->my_shm); try
d->my_shm = 0; {
ReleaseMutex(d->DFCLMutex); pe_timestamp = (*it)->getHexValue("pe_timestamp");
CloseHandle(d->DFSVMutex); }
d->DFSVMutex = 0; catch(Error::MissingMemoryDefinition& e)
CloseHandle(d->DFCLMutex); {
d->DFCLMutex = 0; continue;
return; }
if (pe_timestamp == pe_header.FileHeader.TimeDateStamp)
{
memory_info *m = new memory_info(**it);
m->RebaseAll(base);
d->my_descriptor = m;
d->identified = true;
cerr << "identified " << m->getVersion() << endl;
break;
}
} }
CloseHandle(hProcess);
} while (0); // glorified goto end
if(d->identified)
{
d->my_window = new DFWindow(this);
}
else
{
D_SHMCMD = CORE_RUNNING;
UnmapViewOfFile(d->my_shm);
d->my_shm = 0;
ReleaseMutex(d->DFCLMutex);
CloseHandle(d->DFSVMutex);
d->DFSVMutex = 0;
CloseHandle(d->DFCLMutex);
d->DFCLMutex = 0;
return;
} }
full_barrier full_barrier
// at this point, DF is attached and suspended, make it run // at this point, DF is attached and suspended, make it run
@ -375,8 +396,8 @@ bool SHMProcess::suspend()
cerr << "couldn't suspend, already suspended" << endl; cerr << "couldn't suspend, already suspended" << endl;
return true; return true;
} }
((shm_cmd *)d->my_shm)->pingpong = DFPP_SUSPEND; D_SHMCMD = CORE_SUSPEND;
if(!d->waitWhile(DFPP_SUSPEND)) if(!d->waitWhile(CORE_SUSPEND))
{ {
cerr << "couldn't suspend, DF not responding to commands" << endl; cerr << "couldn't suspend, DF not responding to commands" << endl;
return false; return false;
@ -395,14 +416,14 @@ bool SHMProcess::asyncSuspend()
{ {
return true; return true;
} }
if(((shm_cmd *)d->my_shm)->pingpong == DFPP_SUSPENDED) if(D_SHMCMD == CORE_SUSPENDED)
{ {
d->suspended = true; d->suspended = true;
return true; return true;
} }
else else
{ {
((shm_cmd *)d->my_shm)->pingpong = DFPP_SUSPEND; D_SHMCMD = CORE_SUSPEND;
return false; return false;
} }
} }
@ -424,7 +445,7 @@ bool SHMProcess::resume()
cerr << "couldn't resume because of not being suspended" << endl; cerr << "couldn't resume because of not being suspended" << endl;
return true; return true;
} }
((shm_cmd *)d->my_shm)->pingpong = DFPP_RUNNING; D_SHMCMD = CORE_RUNNING;
d->suspended = false; d->suspended = false;
return true; return true;
} }
@ -454,8 +475,11 @@ bool SHMProcess::attach()
return false; // we couldn't lock it return false; // we couldn't lock it
} }
char shmname [256];
sprintf(shmname,"DFShm-%d",d->my_pid);
// now try getting and attaching the shared memory // now try getting and attaching the shared memory
HANDLE shmHandle = OpenFileMapping(FILE_MAP_ALL_ACCESS,false,"DFShm"); HANDLE shmHandle = OpenFileMapping(FILE_MAP_ALL_ACCESS,false,shmname);
if(!shmHandle) if(!shmHandle)
{ {
ReleaseMutex(d->DFCLMutex); ReleaseMutex(d->DFCLMutex);
@ -499,11 +523,11 @@ void SHMProcess::read (uint32_t src_address, uint32_t size, uint8_t *target_buff
// normal read under 1MB // normal read under 1MB
if(size <= SHM_BODY) if(size <= SHM_BODY)
{ {
((shm_read *)d->my_shm)->address = src_address; D_SHMHDR->address = src_address;
((shm_read *)d->my_shm)->length = size; D_SHMHDR->length = size;
full_barrier full_barrier
((shm_read *)d->my_shm)->pingpong = DFPP_READ; D_SHMCMD = CORE_DFPP_READ;
d->waitWhile(DFPP_READ); d->waitWhile(CORE_DFPP_READ);
memcpy (target_buffer, d->my_shm + SHM_HEADER,size); memcpy (target_buffer, d->my_shm + SHM_HEADER,size);
} }
// a big read, we pull data over the shm in iterations // a big read, we pull data over the shm in iterations
@ -514,11 +538,11 @@ void SHMProcess::read (uint32_t src_address, uint32_t size, uint8_t *target_buff
while (size) while (size)
{ {
// read to_read bytes from src_cursor // read to_read bytes from src_cursor
((shm_read *)d->my_shm)->address = src_address; D_SHMHDR->address = src_address;
((shm_read *)d->my_shm)->length = to_read; D_SHMHDR->length = to_read;
full_barrier full_barrier
((shm_read *)d->my_shm)->pingpong = DFPP_READ; D_SHMCMD = CORE_DFPP_READ;
d->waitWhile(DFPP_READ); d->waitWhile(CORE_DFPP_READ);
memcpy (target_buffer, d->my_shm + SHM_HEADER,size); memcpy (target_buffer, d->my_shm + SHM_HEADER,size);
// decrease size by bytes read // decrease size by bytes read
size -= to_read; size -= to_read;
@ -533,55 +557,55 @@ void SHMProcess::read (uint32_t src_address, uint32_t size, uint8_t *target_buff
uint8_t SHMProcess::readByte (const uint32_t offset) uint8_t SHMProcess::readByte (const uint32_t offset)
{ {
((shm_read_small *)d->my_shm)->address = offset; D_SHMHDR->address = offset;
full_barrier full_barrier
((shm_read_small *)d->my_shm)->pingpong = DFPP_READ_BYTE; D_SHMCMD = CORE_READ_BYTE;
d->waitWhile(DFPP_READ_BYTE); d->waitWhile(CORE_READ_BYTE);
return ((shm_retval *)d->my_shm)->value; return D_SHMHDR->value;
} }
void SHMProcess::readByte (const uint32_t offset, uint8_t &val ) void SHMProcess::readByte (const uint32_t offset, uint8_t &val )
{ {
((shm_read_small *)d->my_shm)->address = offset; D_SHMHDR->address = offset;
full_barrier full_barrier
((shm_read_small *)d->my_shm)->pingpong = DFPP_READ_BYTE; D_SHMCMD = CORE_READ_BYTE;
d->waitWhile(DFPP_READ_BYTE); d->waitWhile(CORE_READ_BYTE);
val = ((shm_retval *)d->my_shm)->value; val = D_SHMHDR->value;
} }
uint16_t SHMProcess::readWord (const uint32_t offset) uint16_t SHMProcess::readWord (const uint32_t offset)
{ {
((shm_read_small *)d->my_shm)->address = offset; D_SHMHDR->address = offset;
full_barrier full_barrier
((shm_read_small *)d->my_shm)->pingpong = DFPP_READ_WORD; D_SHMCMD = CORE_READ_WORD;
d->waitWhile(DFPP_READ_WORD); d->waitWhile(CORE_READ_WORD);
return ((shm_retval *)d->my_shm)->value; return D_SHMHDR->value;
} }
void SHMProcess::readWord (const uint32_t offset, uint16_t &val) void SHMProcess::readWord (const uint32_t offset, uint16_t &val)
{ {
((shm_read_small *)d->my_shm)->address = offset; D_SHMHDR->address = offset;
full_barrier full_barrier
((shm_read_small *)d->my_shm)->pingpong = DFPP_READ_WORD; D_SHMCMD = CORE_READ_WORD;
d->waitWhile(DFPP_READ_WORD); d->waitWhile(CORE_READ_WORD);
val = ((shm_retval *)d->my_shm)->value; val = D_SHMHDR->value;
} }
uint32_t SHMProcess::readDWord (const uint32_t offset) uint32_t SHMProcess::readDWord (const uint32_t offset)
{ {
((shm_read_small *)d->my_shm)->address = offset; D_SHMHDR->address = offset;
full_barrier full_barrier
((shm_read_small *)d->my_shm)->pingpong = DFPP_READ_DWORD; D_SHMCMD = CORE_READ_DWORD;
d->waitWhile(DFPP_READ_DWORD); d->waitWhile(CORE_READ_DWORD);
return ((shm_retval *)d->my_shm)->value; return D_SHMHDR->value;
} }
void SHMProcess::readDWord (const uint32_t offset, uint32_t &val) void SHMProcess::readDWord (const uint32_t offset, uint32_t &val)
{ {
((shm_read_small *)d->my_shm)->address = offset; D_SHMHDR->address = offset;
full_barrier full_barrier
((shm_read_small *)d->my_shm)->pingpong = DFPP_READ_DWORD; D_SHMCMD = CORE_READ_DWORD;
d->waitWhile(DFPP_READ_DWORD); d->waitWhile(CORE_READ_DWORD);
val = ((shm_retval *)d->my_shm)->value; val = D_SHMHDR->value;
} }
/* /*
@ -590,30 +614,30 @@ void SHMProcess::readDWord (const uint32_t offset, uint32_t &val)
void SHMProcess::writeDWord (uint32_t offset, uint32_t data) void SHMProcess::writeDWord (uint32_t offset, uint32_t data)
{ {
((shm_write_small *)d->my_shm)->address = offset; D_SHMHDR->address = offset;
((shm_write_small *)d->my_shm)->value = data; D_SHMHDR->value = data;
full_barrier full_barrier
((shm_write_small *)d->my_shm)->pingpong = DFPP_WRITE_DWORD; D_SHMCMD = CORE_WRITE_DWORD;
d->waitWhile(DFPP_WRITE_DWORD); d->waitWhile(CORE_WRITE_DWORD);
} }
// using these is expensive. // using these is expensive.
void SHMProcess::writeWord (uint32_t offset, uint16_t data) void SHMProcess::writeWord (uint32_t offset, uint16_t data)
{ {
((shm_write_small *)d->my_shm)->address = offset; D_SHMHDR->address = offset;
((shm_write_small *)d->my_shm)->value = data; D_SHMHDR->value = data;
full_barrier full_barrier
((shm_write_small *)d->my_shm)->pingpong = DFPP_WRITE_WORD; D_SHMCMD = CORE_WRITE_WORD;
d->waitWhile(DFPP_WRITE_WORD); d->waitWhile(CORE_WRITE_WORD);
} }
void SHMProcess::writeByte (uint32_t offset, uint8_t data) void SHMProcess::writeByte (uint32_t offset, uint8_t data)
{ {
((shm_write_small *)d->my_shm)->address = offset; D_SHMHDR->address = offset;
((shm_write_small *)d->my_shm)->value = data; D_SHMHDR->value = data;
full_barrier full_barrier
((shm_write_small *)d->my_shm)->pingpong = DFPP_WRITE_BYTE; D_SHMCMD = CORE_WRITE_BYTE;
d->waitWhile(DFPP_WRITE_BYTE); d->waitWhile(CORE_WRITE_BYTE);
} }
void SHMProcess::write (uint32_t dst_address, uint32_t size, uint8_t *source_buffer) void SHMProcess::write (uint32_t dst_address, uint32_t size, uint8_t *source_buffer)
@ -621,12 +645,12 @@ void SHMProcess::write (uint32_t dst_address, uint32_t size, uint8_t *source_buf
// normal write under 1MB // normal write under 1MB
if(size <= SHM_BODY) if(size <= SHM_BODY)
{ {
((shm_write *)d->my_shm)->address = dst_address; D_SHMHDR->address = dst_address;
((shm_write *)d->my_shm)->length = size; D_SHMHDR->length = size;
memcpy(d->my_shm+SHM_HEADER,source_buffer, size); memcpy(d->my_shm+SHM_HEADER,source_buffer, size);
full_barrier full_barrier
((shm_write *)d->my_shm)->pingpong = DFPP_WRITE; D_SHMCMD = CORE_WRITE;
d->waitWhile(DFPP_WRITE); d->waitWhile(CORE_WRITE);
} }
// a big write, we push this over the shm in iterations // a big write, we push this over the shm in iterations
else else
@ -636,12 +660,12 @@ void SHMProcess::write (uint32_t dst_address, uint32_t size, uint8_t *source_buf
while (size) while (size)
{ {
// write to_write bytes to dst_cursor // write to_write bytes to dst_cursor
((shm_write *)d->my_shm)->address = dst_address; D_SHMHDR->address = dst_address;
((shm_write *)d->my_shm)->length = to_write; D_SHMHDR->length = to_write;
memcpy(d->my_shm+SHM_HEADER,source_buffer, to_write); memcpy(d->my_shm+SHM_HEADER,source_buffer, to_write);
full_barrier full_barrier
((shm_write *)d->my_shm)->pingpong = DFPP_WRITE; D_SHMCMD = CORE_WRITE;
d->waitWhile(DFPP_WRITE); d->waitWhile(CORE_WRITE);
// decrease size by bytes written // decrease size by bytes written
size -= to_write; size -= to_write;
// move the cursors // move the cursors
@ -692,11 +716,11 @@ DfVector SHMProcess::readVector (uint32_t offset, uint32_t item_size)
const std::string SHMProcess::readSTLString(uint32_t offset) const std::string SHMProcess::readSTLString(uint32_t offset)
{ {
//offset -= 4; //msvc std::string pointers are 8 bytes ahead of their data, not 4 //offset -= 4; //msvc std::string pointers are 8 bytes ahead of their data, not 4
((shm_read_small *)d->my_shm)->address = offset; D_SHMHDR->address = offset;
full_barrier full_barrier
((shm_read_small *)d->my_shm)->pingpong = DFPP_READ_STL_STRING; D_SHMCMD = CORE_READ_STL_STRING;
d->waitWhile(DFPP_READ_STL_STRING); d->waitWhile(CORE_READ_STL_STRING);
int length = ((shm_retval *)d->my_shm)->value; int length = D_SHMHDR->value;
// char temp_c[256]; // char temp_c[256];
// strncpy(temp_c, d->my_shm+SHM_HEADER,length+1); // length + 1 for the null terminator // strncpy(temp_c, d->my_shm+SHM_HEADER,length+1); // length + 1 for the null terminator
return(string(d->my_shm+SHM_HEADER)); return(string(d->my_shm+SHM_HEADER));
@ -705,11 +729,11 @@ const std::string SHMProcess::readSTLString(uint32_t offset)
size_t SHMProcess::readSTLString (uint32_t offset, char * buffer, size_t bufcapacity) size_t SHMProcess::readSTLString (uint32_t offset, char * buffer, size_t bufcapacity)
{ {
//offset -= 4; //msvc std::string pointers are 8 bytes ahead of their data, not 4 //offset -= 4; //msvc std::string pointers are 8 bytes ahead of their data, not 4
((shm_read_small *)d->my_shm)->address = offset; D_SHMHDR->address = offset;
full_barrier full_barrier
((shm_read_small *)d->my_shm)->pingpong = DFPP_READ_STL_STRING; D_SHMCMD = CORE_READ_STL_STRING;
d->waitWhile(DFPP_READ_STL_STRING); d->waitWhile(CORE_READ_STL_STRING);
size_t length = ((shm_retval *)d->my_shm)->value; size_t length = D_SHMHDR->value;
size_t real = min(length, bufcapacity - 1); size_t real = min(length, bufcapacity - 1);
strncpy(buffer, d->my_shm+SHM_HEADER,real); // length + 1 for the null terminator strncpy(buffer, d->my_shm+SHM_HEADER,real); // length + 1 for the null terminator
buffer[real] = 0; buffer[real] = 0;
@ -718,11 +742,11 @@ size_t SHMProcess::readSTLString (uint32_t offset, char * buffer, size_t bufcapa
void SHMProcess::writeSTLString(const uint32_t address, const std::string writeString) void SHMProcess::writeSTLString(const uint32_t address, const std::string writeString)
{ {
((shm_write_small *)d->my_shm)->address = address/*-4*/; D_SHMHDR->address = address/*-4*/;
strncpy(d->my_shm+SHM_HEADER,writeString.c_str(),writeString.length()+1); // length + 1 for the null terminator strncpy(d->my_shm+SHM_HEADER,writeString.c_str(),writeString.length()+1); // length + 1 for the null terminator
full_barrier full_barrier
((shm_write_small *)d->my_shm)->pingpong = DFPP_WRITE_STL_STRING; D_SHMCMD = CORE_WRITE_STL_STRING;
d->waitWhile(DFPP_WRITE_STL_STRING); d->waitWhile(CORE_WRITE_STL_STRING);
} }
string SHMProcess::readClassName (uint32_t vptr) string SHMProcess::readClassName (uint32_t vptr)
@ -732,4 +756,23 @@ string SHMProcess::readClassName (uint32_t vptr)
string raw = readCString(typeinfo + 0xC); // skips the .?AV string raw = readCString(typeinfo + 0xC); // skips the .?AV
raw.resize(raw.length() - 4);// trim st@@ from end raw.resize(raw.length() - 4);// trim st@@ from end
return raw; return raw;
}
// get module index by name and version. bool 1 = error
bool SHMProcess::getModuleIndex (const char * name, const uint32_t version, uint32_t & OUTPUT)
{
modulelookup * payload = (modulelookup *) (d->my_shm + SHM_HEADER);
payload->version = version;
strcpy(payload->name,name);
full_barrier
D_SHMCMD = CORE_ACQUIRE_MODULE;
d->waitWhile(CORE_ACQUIRE_MODULE);
if(D_SHMHDR->error) return false;
OUTPUT = D_SHMHDR->value;
return true;
}
char * SHMProcess::getSHMStart (void)
{
return d->my_shm;
} }

@ -69,7 +69,7 @@ NormalProcess::NormalProcess(uint32_t pid, vector <memory_info *> & known_versio
if(EnumProcessModules(hProcess, &hmod, 1 * sizeof(HMODULE), &junk) == 0) if(EnumProcessModules(hProcess, &hmod, 1 * sizeof(HMODULE), &junk) == 0)
{ {
CloseHandle(hProcess); CloseHandle(hProcess);
cout << "EnumProcessModules fail'd" << endl; // cout << "EnumProcessModules fail'd" << endl;
return; //if enumprocessModules fails, give up return; //if enumprocessModules fails, give up
} }

@ -119,6 +119,12 @@ namespace DFHack
virtual DFWindow * getWindow() = 0; virtual DFWindow * getWindow() = 0;
// get the DF Process ID // get the DF Process ID
virtual int getPID() = 0; virtual int getPID() = 0;
// get module index by name and version. bool 1 = error
virtual bool getModuleIndex (const char * name, const uint32_t version, uint32_t & OUTPUT) = 0;
// get the SHM start if available
virtual char * getSHMStart (void) = 0;
// wait for a SHM state. returns 0 without the SHM
virtual bool waitWhile (uint32_t state) = 0;
}; };
class DFHACK_EXPORT NormalProcess : virtual public Process class DFHACK_EXPORT NormalProcess : virtual public Process
@ -171,6 +177,12 @@ namespace DFHack
memory_info *getDescriptor(); memory_info *getDescriptor();
DFWindow * getWindow(); DFWindow * getWindow();
int getPID(); int getPID();
// get module index by name and version. bool 1 = error
bool getModuleIndex (const char * name, const uint32_t version, uint32_t & OUTPUT) {return false;};
// get the SHM start if available
char * getSHMStart (void){return 0;};
// wait for a SHM state. returns 0 without the SHM
bool waitWhile (uint32_t state){return false;};
}; };
class DFHACK_EXPORT SHMProcess : virtual public Process class DFHACK_EXPORT SHMProcess : virtual public Process
@ -181,7 +193,7 @@ namespace DFHack
Private * const d; Private * const d;
public: public:
SHMProcess(vector <memory_info *> & known_versions); SHMProcess(uint32_t PID, vector <memory_info *> & known_versions);
~SHMProcess(); ~SHMProcess();
// Set up stuff so we can read memory // Set up stuff so we can read memory
bool attach(); bool attach();
@ -224,6 +236,12 @@ namespace DFHack
memory_info *getDescriptor(); memory_info *getDescriptor();
DFWindow * getWindow(); DFWindow * getWindow();
int getPID(); int getPID();
// get module index by name and version. bool 1 = error
bool getModuleIndex (const char * name, const uint32_t version, uint32_t & OUTPUT);
// get the SHM start if available
char * getSHMStart (void);
// wait for a SHM state. returns 0 without the SHM
bool waitWhile (uint32_t state);
}; };
#ifdef LINUX_BUILD #ifdef LINUX_BUILD
@ -277,6 +295,12 @@ namespace DFHack
memory_info *getDescriptor(); memory_info *getDescriptor();
DFWindow * getWindow(); DFWindow * getWindow();
int getPID(); int getPID();
// get module index by name and version. bool 1 = error
bool getModuleIndex (const char * name, const uint32_t version, uint32_t & OUTPUT) {return false;};
// get the SHM start if available
char * getSHMStart (void){return 0;};
// wait for a SHM state. returns 0 without the SHM
bool waitWhile (uint32_t state){return false;};
}; };
#endif #endif
} }

@ -46,19 +46,6 @@ bool ProcessEnumerator::findProcessess()
{ {
DIR *dir_p; DIR *dir_p;
struct dirent *dir_entry_p; struct dirent *dir_entry_p;
Process *p = 0;
p = new SHMProcess(d->meminfo->meminfo);
if(p->isIdentified())
{
d->processes.push_back(p);
}
else
{
delete p;
p = 0;
}
// Open /proc/ directory // Open /proc/ directory
dir_p = opendir("/proc/"); dir_p = opendir("/proc/");
// Reading /proc/ entries // Reading /proc/ entries
@ -69,6 +56,16 @@ bool ProcessEnumerator::findProcessess()
{ {
continue; continue;
} }
Process *p1 = new SHMProcess(atoi(dir_entry_p->d_name),d->meminfo->meminfo);
if(p1->isIdentified())
{
d->processes.push_back(p1);
continue;
}
else
{
delete p1;
}
Process *p2 = new NormalProcess(atoi(dir_entry_p->d_name),d->meminfo->meminfo); Process *p2 = new NormalProcess(atoi(dir_entry_p->d_name),d->meminfo->meminfo);
if(p2->isIdentified()) if(p2->isIdentified())
{ {
@ -89,6 +86,7 @@ bool ProcessEnumerator::findProcessess()
{ {
delete p3; delete p3;
} }
} }
closedir(dir_p); closedir(dir_p);
// return value depends on if we found some DF processes // return value depends on if we found some DF processes

@ -67,21 +67,7 @@ bool ProcessEnumerator::findProcessess()
{ {
// Get the list of process identifiers. // Get the list of process identifiers.
DWORD ProcArray[2048], memoryNeeded, numProccesses; DWORD ProcArray[2048], memoryNeeded, numProccesses;
{ //EnableDebugPriv();
Process * p = new SHMProcess(d->meminfo->meminfo);
if(p->isIdentified())
{
d->processes.push_back(p);
return true;
}
else
{
delete p;
p = 0;
}
}
EnableDebugPriv();
if ( !EnumProcesses( ProcArray, sizeof(ProcArray), &memoryNeeded ) ) if ( !EnumProcesses( ProcArray, sizeof(ProcArray), &memoryNeeded ) )
{ {
cout << "EnumProcesses fail'd" << endl; cout << "EnumProcesses fail'd" << endl;
@ -90,19 +76,32 @@ bool ProcessEnumerator::findProcessess()
// Calculate how many process identifiers were returned. // Calculate how many process identifiers were returned.
numProccesses = memoryNeeded / sizeof(DWORD); numProccesses = memoryNeeded / sizeof(DWORD);
EnableDebugPriv();
// iterate through processes // iterate through processes
for ( int i = 0; i < (int)numProccesses; i++ ) for ( int i = 0; i < (int)numProccesses; i++ )
{ {
Process *q = new NormalProcess(ProcArray[i],d->meminfo->meminfo); Process *p = new SHMProcess(ProcArray[i],d->meminfo->meminfo);
if(q->isIdentified()) if(p->isIdentified())
{
d->processes.push_back(p);
continue;
}
else
{
delete p;
p = 0;
}
p = new NormalProcess(ProcArray[i],d->meminfo->meminfo);
if(p->isIdentified())
{ {
d->processes.push_back(q); d->processes.push_back(p);
continue;
} }
else else
{ {
delete q; delete p;
q = 0; p = 0;
} }
} }
if(d->processes.size()) if(d->processes.size())

@ -769,6 +769,17 @@ union t_occupancy
naked_occupancy_grouped unibits; naked_occupancy_grouped unibits;
}; };
typedef struct
{
int16_t tiletypes [16][16];
DFHack::t_designation designaton [16][16];
DFHack::t_occupancy occupancy [16][16];
// really a '7', but I use 8 to make it neater :)
uint8_t biome_indices [8];
uint32_t origin; // the address where it came from
uint32_t dirty_dword; // bit 1 set means that the block is to be included in job checks
} mapblock40d;
struct t_viewscreen struct t_viewscreen
{ {
int32_t type; int32_t type;

@ -2,10 +2,13 @@
SET(PROJECT_HDRS SET(PROJECT_HDRS
shms.h shms.h
mod-core.h
mod-maps.h
) )
SET(PROJECT_SRCS SET(PROJECT_SRCS
shms-proto.cpp mod-core.cpp
mod-maps.cpp
) )
SET(PROJECT_HDRS_LINUX SET(PROJECT_HDRS_LINUX
@ -35,15 +38,16 @@ SET_SOURCE_FILES_PROPERTIES( ${PROJECT_HDRS} PROPERTIES HEADER_FILE_ONLY TRUE )
LIST(APPEND PROJECT_SRCS ${PROJECT_HDRS}) LIST(APPEND PROJECT_SRCS ${PROJECT_HDRS})
IF(UNIX) IF(CMAKE_SIZEOF_VOID_P EQUAL 4)
add_definitions(-DLINUX_BUILD) IF(UNIX)
SET(PROJECT_LIBS rt) add_definitions(-DLINUX_BUILD)
SET(CMAKE_CXX_FLAGS "-fvisibility=hidden") SET(PROJECT_LIBS rt)
ADD_LIBRARY(dfconnect SHARED ${PROJECT_SRCS}) SET(CMAKE_CXX_FLAGS "-fvisibility=hidden")
TARGET_LINK_LIBRARIES(dfconnect ${PROJECT_LIBS}) ADD_LIBRARY(dfconnect SHARED ${PROJECT_SRCS})
ELSE(UNIX) TARGET_LINK_LIBRARIES(dfconnect ${PROJECT_LIBS})
# SET(PROJECT_LIBS psapi) ELSE(UNIX)
ADD_LIBRARY(SDL SHARED ${PROJECT_SRCS}) # SET(PROJECT_LIBS psapi)
TARGET_LINK_LIBRARIES(SDL ${PROJECT_LIBS}) ADD_LIBRARY(SDL SHARED ${PROJECT_SRCS})
ENDIF(UNIX) TARGET_LINK_LIBRARIES(SDL ${PROJECT_LIBS})
ENDIF(UNIX)
ENDIF(CMAKE_SIZEOF_VOID_P EQUAL 4)

@ -0,0 +1,292 @@
/*
www.sourceforge.net/projects/dfhack
Copyright (c) 2009 Petr Mrázek (peterix)
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any
damages arising from the use of this software.
Permission is granted to anyone to use this software for any
purpose, including commercial applications, and to alter it and
redistribute it freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must
not claim that you wrote the original software. If you use this
software in a product, an acknowledgment in the product documentation
would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and
must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source
distribution.
*/
/**
* This is the source for the DF <-> dfhack shm bridge's core module.
*/
#include <stdio.h>
#include "../library/integers.h"
#include <stdlib.h>
#include <string.h>
#include <string>
#include <vector>
#define SHM_INTERNAL // for things only visible to the SHM
#include "shms.h"
#include "mod-core.h"
#include "mod-maps.h"
std::vector <DFPP_module> module_registry;
// various crud
extern int errorstate;
extern char *shm;
extern int shmid;
bool useYield = 0;
#define SHMHDR ((shm_core_hdr *)shm)
#define SHMCMD ((shm_cmd *)shm)->pingpong
#define SHMDATA(type) ((type *)(shm + SHM_HEADER))
void ReadRaw (void * data)
{
memcpy(shm + SHM_HEADER, (void *) SHMHDR->address,SHMHDR->length);
}
void ReadDWord (void * data)
{
SHMHDR->value = *((uint32_t*) SHMHDR->address);
}
void ReadWord (void * data)
{
SHMHDR->value = *((uint16_t*) SHMHDR->address);
}
void ReadByte (void * data)
{
SHMHDR->value = *((uint8_t*) SHMHDR->address);
}
void WriteRaw (void * data)
{
memcpy((void *)SHMHDR->address, shm + SHM_HEADER,SHMHDR->length);
}
void WriteDWord (void * data)
{
(*(uint32_t*)SHMHDR->address) = SHMHDR->value;
}
void WriteWord (void * data)
{
(*(uint16_t*)SHMHDR->address) = SHMHDR->value;
}
void WriteByte (void * data)
{
(*(uint8_t*)SHMHDR->address) = SHMHDR->value;
}
void ReadSTLString (void * data)
{
std::string * myStringPtr = (std::string *) SHMHDR->address;
unsigned int l = myStringPtr->length();
SHMHDR->value = l;
// FIXME: there doesn't have to be a null terminator!
strncpy(shm+SHM_HEADER,myStringPtr->c_str(),l+1);
}
void WriteSTLString (void * data)
{
std::string * myStringPtr = (std::string *) SHMHDR->address;
// here we DO expect a 0 terminator
myStringPtr->assign((const char *) (shm + SHM_HEADER));
}
// MIT HAKMEM bitcount
int bitcount(uint32_t n)
{
register uint32_t tmp;
tmp = n - ((n >> 1) & 033333333333) - ((n >> 2) & 011111111111);
return ((tmp + (tmp >> 3)) & 030707070707) % 63;
}
// get local and remote affinity, set up yield if required (single core available)
void CoreAttach (void * data)
{
// sync affinity
uint32_t local = OS_getAffinity();
uint32_t remote = SHMDATA(coreattach)->cl_affinity;
uint32_t pool = local | remote;
SHMDATA(coreattach)->sv_useYield = useYield = (bitcount(pool) == 1);
// return our PID
SHMDATA(coreattach)->sv_PID = OS_getPID();
// return core version
SHMDATA(coreattach)->sv_version = module_registry[0].version;
}
void FindModule (void * data)
{
bool found = false;
modulelookup * payload = (modulelookup *) (shm + SHM_HEADER);
std::string test = payload->name;
uint32_t version = payload->version;
for(unsigned int i = 0; i < module_registry.size();i++)
{
if(module_registry[i].name == test && module_registry[i].version == version)
{
// gotcha
SHMHDR->value = i;
found = true;
break;
}
}
SHMHDR->error = !found;
}
void FindCommand (void * data)
{
bool found = false;
commandlookup * payload = SHMDATA(commandlookup);
std::string modname = payload->module;
std::string cmdname = payload->name;
uint32_t version = payload->version;
for(unsigned int i = 0; i < module_registry.size();i++)
{
if(module_registry[i].name == modname && module_registry[i].version == version)
{
for(unsigned int j = 0 ; j < module_registry[i].commands.size();j++)
{
if(module_registry[i].commands[j].name == cmdname)
{
// gotcha
SHMHDR->value = j + (i << 16);
SHMHDR->error = false;
return;
}
}
}
}
SHMHDR->error = true;
}
DFPP_module InitCore(void)
{
DFPP_module core;
core.name = "Core";
core.version = CORE_VERSION;
core.modulestate = 0; // this one is dumb and has no real state
core.reserve(NUM_CORE_CMDS);
// basic states
core.set_command(CORE_RUNNING, CANCELLATION, "Running");
core.set_command(CORE_SUSPEND, CLIENT_WAIT, "Suspend", 0 , CORE_SUSPENDED);
core.set_command(CORE_SUSPENDED, CLIENT_WAIT, "Suspended");
core.set_command(CORE_ERROR, CANCELLATION, "Error");
// utility commands
core.set_command(CORE_ATTACH, FUNCTION,"Core attach",CoreAttach, CORE_SUSPENDED);
core.set_command(CORE_ACQUIRE_MODULE, FUNCTION, "Module lookup", FindModule, CORE_SUSPENDED);
core.set_command(CORE_ACQUIRE_COMMAND, FUNCTION, "Command lookup", FindCommand, CORE_SUSPENDED);
// raw reads
core.set_command(CORE_DFPP_READ, FUNCTION,"Raw read",ReadRaw, CORE_SUSPENDED);
core.set_command(CORE_READ_DWORD, FUNCTION,"Read DWORD",ReadDWord, CORE_SUSPENDED);
core.set_command(CORE_READ_WORD, FUNCTION,"Read WORD",ReadWord, CORE_SUSPENDED);
core.set_command(CORE_READ_BYTE, FUNCTION,"Read BYTE",ReadByte, CORE_SUSPENDED);
// raw writes
core.set_command(CORE_WRITE, FUNCTION, "Raw write", WriteRaw, CORE_SUSPENDED);
core.set_command(CORE_WRITE_DWORD, FUNCTION, "Write DWORD", WriteDWord, CORE_SUSPENDED);
core.set_command(CORE_WRITE_WORD, FUNCTION, "Write WORD", WriteWord, CORE_SUSPENDED);
core.set_command(CORE_WRITE_BYTE, FUNCTION, "Write BYTE", WriteByte, CORE_SUSPENDED);
// stl string commands
core.set_command(CORE_READ_STL_STRING, FUNCTION, "Read STL string", ReadSTLString, CORE_SUSPENDED);
core.set_command(CORE_READ_C_STRING, CLIENT_WAIT, "RESERVED");
core.set_command(CORE_WRITE_STL_STRING, FUNCTION, "Write STL string", WriteSTLString, CORE_SUSPENDED);
return core;
}
void InitModules (void)
{
// create the core module
module_registry.push_back(InitCore());
module_registry.push_back(InitMaps());
// TODO: dynamic module init
}
void KillModules (void)
{
for(unsigned int i = 0; i < module_registry.size();i++)
{
if(module_registry[i].modulestate)
free(module_registry[i].modulestate);
}
module_registry.clear();
}
void SHM_Act (void)
{
if(errorstate)
{
return;
}
uint32_t numwaits = 0;
check_again: // goto target!!!
if(numwaits == 10000)
{
// this tests if there's a process on the other side
if(isValidSHM())
{
numwaits = 0;
}
else
{
full_barrier
SHMCMD = CORE_RUNNING;
fprintf(stderr,"dfhack: Broke out of loop, other process disappeared.\n");
}
}
// this is very important! copying two words separately from the command variable leads to inconsistency.
// Always copy the thing in one go.
// Also, this whole SHM thing probably only works on intel processors
volatile shm_cmd atomic = SHMHDR->cmd;
full_barrier
DFPP_module & mod = module_registry[atomic.parts.module];
DFPP_command & cmd = mod.commands[atomic.parts.command];
full_barrier
/*
fprintf(stderr, "Called %x\0", cmd._function);
fprintf(stderr, "Client invoked %d:%d = ",atomic.parts.module,atomic.parts.command);
fprintf(stderr, "%s\n",cmd.name.c_str());
*/
full_barrier
if(cmd._function)
{
cmd._function(mod.modulestate);
}
full_barrier
if(cmd.nextState != -1)
{
SHMCMD = cmd.nextState;
}
full_barrier
if(cmd.type != CANCELLATION)
{
if(useYield)
{
SCHED_YIELD
}
numwaits ++; // watchdog timeout
goto check_again;
}
}

@ -0,0 +1,94 @@
/*
www.sourceforge.net/projects/dfhack
Copyright (c) 2009 Petr Mrázek (peterix)
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any
damages arising from the use of this software.
Permission is granted to anyone to use this software for any
purpose, including commercial applications, and to alter it and
redistribute it freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must
not claim that you wrote the original software. If you use this
software in a product, an acknowledgment in the product documentation
would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and
must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source
distribution.
*/
#ifndef SHMS_CORE_H
#define SHMS_CORE_H
// increment on every core change
#define CORE_VERSION 7
typedef struct
{
shm_cmd cmd;
uint32_t address;
uint32_t value;
uint32_t length;
uint32_t error;
} shm_core_hdr;
typedef struct
{
uint32_t version;
char name[256];
} modulelookup;
typedef struct
{
uint32_t version;
char module[256];
char name[256];
} commandlookup;
typedef struct
{
uint32_t sv_version; // output
uint32_t cl_affinity; // input
uint32_t sv_PID; // output
uint32_t sv_useYield; // output
} coreattach;
enum CORE_COMMAND
{
// basic states
CORE_RUNNING = 0, // no command, normal server execution
CORE_SUSPEND, // client notifies server to wait for commands (server is stalled in busy wait)
CORE_SUSPENDED, // response to WAIT, server is stalled in busy wait
CORE_ERROR, // there was a server error
// utility commands
CORE_ATTACH, // compare affinity, get core version and process ID
CORE_ACQUIRE_MODULE, // get index of a loaded module by name and version
CORE_ACQUIRE_COMMAND, // get module::command callsign by module name, command name and module version
// raw reads
CORE_DFPP_READ, // cl -> sv, read some data
CORE_READ_DWORD, // cl -> sv, read a dword
CORE_READ_WORD, // cl -> sv, read a word
CORE_READ_BYTE, // cl -> sv, read a byte
// raw writes
CORE_WRITE,// client writes to server
CORE_WRITE_DWORD,// client writes a DWORD to server
CORE_WRITE_WORD,// client writes a WORD to server
CORE_WRITE_BYTE,// client writes a BYTE to server
// string functions
CORE_READ_STL_STRING,// client requests contents of STL string at address
CORE_READ_C_STRING,// client requests contents of a C string at address, max length (0 means zero terminated)
CORE_WRITE_STL_STRING,// client wants to set STL string at address to something
// total commands
NUM_CORE_CMDS
};
#endif

@ -0,0 +1,121 @@
#include <string>
#include <vector>
#include <integers.h>
#include "shms.h"
#include "mod-core.h"
#include "mod-maps.h"
#include <DFTypes.h>
using namespace DFHack;
using namespace DFHack::Maps;
#include <string.h>
#include <malloc.h>
extern char *shm;
//TODO: circular buffer streaming primitives required
//TODO: commands can fail without the proper offsets. Hot to handle that?
#define SHMHDR ((shm_maps_hdr *)shm)
#define SHMCMD ((shm_cmd *)shm)->pingpong
#define SHMDATA ((char *)(shm + SHM_HEADER))
void NullCommand (void* data)
{
};
void InitOffsets (void* data)
{
maps_modulestate * state = (maps_modulestate *) data;
memcpy((void *) &(state->offsets), SHMDATA, sizeof(maps_offsets));
((maps_modulestate *) data)->inited = true;
}
void GetMapSize (void *data)
{
maps_modulestate * state = (maps_modulestate *) data;
if(state->inited)
{
SHMHDR->x = *(uint32_t *) (state->offsets.x_count_offset);
SHMHDR->y = *(uint32_t *) (state->offsets.y_count_offset);
SHMHDR->z = *(uint32_t *) (state->offsets.z_count_offset);
SHMHDR->error = false;
}
else
{
SHMHDR->error = true;
}
}
struct mblock
{
uint32_t * ptr_to_dirty;
};
#define SHMBLOCK ((mapblock40d *)(shm + SHM_HEADER))
inline void ReadBlockByAddress (void * data)
{
maps_modulestate * state = (maps_modulestate *) data;
maps_offsets & offsets = state->offsets;
mblock * block = (mblock *) SHMHDR->address;
if(block)
{
memcpy(&(SHMBLOCK->tiletypes), ((char *) block) + offsets.tile_type_offset, sizeof(SHMBLOCK->tiletypes));
memcpy(&(SHMBLOCK->designaton), ((char *) block) + offsets.designation_offset, sizeof(SHMBLOCK->designaton));
memcpy(&(SHMBLOCK->occupancy), ((char *) block) + offsets.occupancy_offset, sizeof(SHMBLOCK->occupancy));
memcpy(&(SHMBLOCK->biome_indices), ((char *) block) + offsets.biome_stuffs, sizeof(SHMBLOCK->biome_indices));
SHMBLOCK->dirty_dword = *block->ptr_to_dirty;
SHMBLOCK->origin = (uint32_t)block;
SHMHDR->error = false;
}
else
{
SHMHDR->error = true;
}
}
void ReadBlockByCoords (void * data)
{
maps_modulestate * state = (maps_modulestate *) data;
maps_offsets & offsets = state->offsets;
/* map_offset is a pointer to
a pointer to
an X block of pointers to
an Y blocks of pointers to
a Z blocks of pointers to
map blocks
only Z blocks can have NULL pointers? TODO: verify
*/
mblock * *** mapArray = *(mblock * ****)offsets.map_offset;
SHMHDR->address = (uint32_t) mapArray[SHMHDR->x][SHMHDR->y][SHMHDR->z];
ReadBlockByAddress(data); // I wonder... will this inline properly?
}
DFPP_module InitMaps( void )
{
DFPP_module maps;
maps.name = "Maps";
maps.version = MAPS_VERSION;
// freed by the core
maps.modulestate = malloc(sizeof(maps_modulestate)); // we store a flag
memset(maps.modulestate,0,sizeof(maps_modulestate));
maps.reserve(NUM_MAPS_CMDS);
// client sends a maps_offsets struct -> inited = true;
maps.set_command(MAP_INIT, FUNCTION, "Supply the module with offsets",InitOffsets,CORE_SUSPENDED);
maps.set_command(MAP_GET_SIZE, FUNCTION, "Get map size in 16x16x1 tile blocks", GetMapSize, CORE_SUSPENDED);
maps.set_command(MAP_READ_BLOCK_BY_COORDS, FUNCTION, "Read the whole block with specified coords", ReadBlockByCoords, CORE_SUSPENDED);
maps.set_command(MAP_READ_BLOCK_BY_ADDRESS, FUNCTION, "Read the whole block from an address", ReadBlockByAddress, CORE_SUSPENDED);
// will it fit into 1MB? We shouldn't assume this is the case
maps.set_command(MAP_READ_BLOCKTREE, FUNCTION,"Get the tree of block pointers as a single structure", NullCommand, CORE_SUSPENDED);
// really doesn't fit into 1MB, there should be a streaming variant to better utilize context switches
maps.set_command(MAP_READ_BLOCKS_3D, FUNCTION, "Read a range of blocks between two sets of coords", NullCommand, CORE_SUSPENDED);
return maps;
}

@ -0,0 +1,102 @@
/*
www.sourceforge.net/projects/dfhack
Copyright (c) 2009 Petr Mrázek (peterix)
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any
damages arising from the use of this software.
Permission is granted to anyone to use this software for any
purpose, including commercial applications, and to alter it and
redistribute it freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must
not claim that you wrote the original software. If you use this
software in a product, an acknowledgment in the product documentation
would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and
must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source
distribution.
*/
#ifndef MOD_MAPS_H
#define MOD_MAPS_H
// increment on every change
#include <DFTypes.h>
namespace DFHack
{
namespace Maps
{
#define MAPS_VERSION 2
typedef struct
{
uint32_t map_offset;// = d->offset_descriptor->getAddress ("map_data");
uint32_t x_count_offset;// = d->offset_descriptor->getAddress ("x_count");
uint32_t y_count_offset;// = d->offset_descriptor->getAddress ("y_count");
uint32_t z_count_offset;// = d->offset_descriptor->getAddress ("z_count");
uint32_t tile_type_offset;// = d->offset_descriptor->getOffset ("type");
uint32_t designation_offset;// = d->offset_descriptor->getOffset ("designation");
uint32_t occupancy_offset;// = d->offset_descriptor->getOffset ("occupancy");
uint32_t biome_stuffs;// = d->offset_descriptor->getOffset ("biome_stuffs");
uint32_t veinvector;// = d->offset_descriptor->getOffset ("v_vein");
uint32_t vein_mineral_vptr;
uint32_t vein_ice_vptr;
/*
GEOLOGY
uint32_t region_x_offset;// = minfo->getAddress ("region_x");
uint32_t region_y_offset;// = minfo->getAddress ("region_y");
uint32_t region_z_offset;// = minfo->getAddress ("region_z");
uint32_t world_offset;// = minfo->getAddress ("world");
uint32_t world_regions_offset;// = minfo->getOffset ("w_regions_arr");
uint32_t region_size;// = minfo->getHexValue ("region_size");
uint32_t region_geo_index_offset;// = minfo->getOffset ("region_geo_index_off");
uint32_t world_geoblocks_offset;// = minfo->getOffset ("w_geoblocks");
uint32_t world_size_x;// = minfo->getOffset ("world_size_x");
uint32_t world_size_y;// = minfo->getOffset ("world_size_y");
uint32_t geolayer_geoblock_offset;// = minfo->getOffset ("geolayer_geoblock_offset");
*/
} maps_offsets;
typedef struct
{
bool inited;
maps_offsets offsets;
} maps_modulestate;
typedef struct
{
shm_cmd cmd;
uint32_t x;
uint32_t y;
uint32_t z;
uint32_t x2;
uint32_t y2;
uint32_t z2;
uint32_t address;
uint32_t error;
} shm_maps_hdr;
enum MAPS_COMMAND
{
MAP_INIT = 0, // initialization
MAP_PROBE, // check if the map is still there
MAP_GET_SIZE, // get the map size in 16x16x1 blocks
MAP_READ_BLOCKTREE, // read the structure of pointers to blocks
MAP_READ_BLOCK_BY_COORDS, // read block by cords
MAP_READ_BLOCK_BY_ADDRESS, // read block by address
MAP_WRITE_BLOCK,
MAP_READ_BLOCKS_3D, // read blocks between two coords (volumetric)
MAP_READ_ALL_BLOCKS, // read the entire map
MAP_REVEAL, // reveal the whole map
NUM_MAPS_CMDS,
};
}
}
#endif

@ -34,12 +34,11 @@ distribution.
#include <sys/types.h> #include <sys/types.h>
#include <sys/ipc.h> #include <sys/ipc.h>
#include <unistd.h> #include <unistd.h>
#include <vector>
#include <string>
#include "shms.h" #include "shms.h"
#include <sys/time.h> #include "mod-core.h"
#include <time.h> #include <sched.h>
#include <linux/futex.h>
#include <sys/syscall.h>
#include <signal.h>
#define DFhackCExport extern "C" __attribute__ ((visibility("default"))) #define DFhackCExport extern "C" __attribute__ ((visibility("default")))
@ -62,11 +61,20 @@ bool isValidSHM()
//fprintf(stderr,"ID %d, attached: %d\n",shmid, descriptor.shm_nattch); //fprintf(stderr,"ID %d, attached: %d\n",shmid, descriptor.shm_nattch);
return (descriptor.shm_nattch == 2); return (descriptor.shm_nattch == 2);
} }
uint32_t getPID() uint32_t OS_getPID()
{ {
return getpid(); return getpid();
} }
uint32_t OS_getAffinity()
{
cpu_set_t mask;
sched_getaffinity(0,sizeof(cpu_set_t),&mask);
// FIXME: truncation
uint32_t affinity = *(uint32_t *) &mask;
return affinity;
}
void SHM_Init ( void ) void SHM_Init ( void )
{ {
// check that we do this only once per process // check that we do this only once per process
@ -77,8 +85,8 @@ void SHM_Init ( void )
} }
inited = true; inited = true;
// name for the segment // name for the segment, an accident waiting to happen
key_t key = 123466; key_t key = SHM_KEY + OS_getPID();
// find previous segment, check if it's used by some processes. // find previous segment, check if it's used by some processes.
// if it isn't, kill it with fire // if it isn't, kill it with fire
@ -109,13 +117,15 @@ void SHM_Init ( void )
} }
full_barrier full_barrier
// make sure we don't stall or do crazy stuff // make sure we don't stall or do crazy stuff
((shm_cmd *)shm)->pingpong = DFPP_RUNNING; ((shm_cmd *)shm)->pingpong = CORE_RUNNING;
InitModules();
} }
void SHM_Destroy ( void ) void SHM_Destroy ( void )
{ {
if(inited && !errorstate) if(inited && !errorstate)
{ {
KillModules();
shmid_ds descriptor; shmid_ds descriptor;
shmctl(shmid, IPC_STAT, &descriptor); shmctl(shmid, IPC_STAT, &descriptor);
shmdt(shm); shmdt(shm);
@ -144,7 +154,7 @@ DFhackCExport void SDL_GL_SwapBuffers(void)
{ {
if(_SDL_GL_SwapBuffers) if(_SDL_GL_SwapBuffers)
{ {
if(!errorstate && ((shm_cmd *)shm)->pingpong != DFPP_RUNNING) if(!errorstate && ((shm_cmd *)shm)->pingpong != CORE_RUNNING)
{ {
SHM_Act(); SHM_Act();
} }
@ -158,7 +168,7 @@ DFhackCExport int SDL_Flip(void * some_ptr)
{ {
if(_SDL_Flip) if(_SDL_Flip)
{ {
if(!errorstate && ((shm_cmd *)shm)->pingpong != DFPP_RUNNING) if(!errorstate && ((shm_cmd *)shm)->pingpong != CORE_RUNNING)
{ {
SHM_Act(); SHM_Act();
} }
@ -216,7 +226,7 @@ DFhackCExport int refresh (void)
{ {
if(_refresh) if(_refresh)
{ {
if(!errorstate && ((shm_cmd *)shm)->pingpong != DFPP_RUNNING) if(!errorstate && ((shm_cmd *)shm)->pingpong != CORE_RUNNING)
{ {
SHM_Act(); SHM_Act();
} }

@ -1,187 +0,0 @@
/*
www.sourceforge.net/projects/dfhack
Copyright (c) 2009 Petr Mrázek (peterix)
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any
damages arising from the use of this software.
Permission is granted to anyone to use this software for any
purpose, including commercial applications, and to alter it and
redistribute it freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must
not claim that you wrote the original software. If you use this
software in a product, an acknowledgment in the product documentation
would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and
must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source
distribution.
*/
/**
* This is the source for the DF <-> dfhack shm bridge, server protocol part
*/
#include <stdio.h>
#include "../library/integers.h"
#include <stdlib.h>
#include <string.h>
#include <string>
//#include <unistd.h>
#include "shms.h"
// various crud
extern int errorstate;
extern char *shm;
extern int shmid;
void SHM_Act (void)
{
if(errorstate)
{
return;
}
uint32_t numwaits = 0;
uint32_t length;
uint32_t address;
std::string * myStringPtr;
check_again: // goto target!!!
SCHED_YIELD // yield the CPU, valid only on single-core CPUs
if(numwaits == 10000)
{
// this tests if there's a process on the other side
if(isValidSHM())
{
numwaits = 0;
}
else
{
full_barrier
((shm_cmd *)shm)->pingpong = DFPP_RUNNING;
fprintf(stderr,"dfhack: Broke out of loop, other process disappeared.\n");
//MessageBox(0,"Broke out of loop, other process disappeared.","FUN", MB_OK);
}
}
switch (((shm_cmd *)shm)->pingpong)
{
case DFPP_RET_VERSION:
case DFPP_RET_DATA:
case DFPP_RET_DWORD:
case DFPP_RET_WORD:
case DFPP_RET_BYTE:
case DFPP_RET_STRING:
case DFPP_SUSPENDED:
case DFPP_RET_PID:
case DFPP_SV_ERROR:
numwaits++;
goto check_again;
case DFPP_SUSPEND:
full_barrier
((shm_cmd *)shm)->pingpong = DFPP_SUSPENDED;
goto check_again;
/*
case DFPP_BOUNCE:
length = ((shm_bounce *)shm)->length;
memcpy(BigFat,shm + SHM_HEADER,length);
memcpy(shm + SHM_HEADER,BigFat,length);
((shm_cmd *)shm)->pingpong = DFPP_RET_DATA;
goto check_again;
*/
case DFPP_PID:
((shm_retval *)shm)->value = getPID();
full_barrier
((shm_retval *)shm)->pingpong = DFPP_RET_PID;
goto check_again;
case DFPP_VERSION:
((shm_retval *)shm)->value = PINGPONG_VERSION;
full_barrier
((shm_retval *)shm)->pingpong = DFPP_RET_VERSION;
goto check_again;
case DFPP_READ:
length = ((shm_read *)shm)->length;
address = ((shm_read *)shm)->address;
memcpy(shm + SHM_HEADER, (void *) address,length);
full_barrier
((shm_cmd *)shm)->pingpong = DFPP_RET_DATA;
goto check_again;
case DFPP_READ_DWORD:
address = ((shm_read_small *)shm)->address;
((shm_retval *)shm)->value = *((uint32_t*) address);
full_barrier
((shm_retval *)shm)->pingpong = DFPP_RET_DWORD;
goto check_again;
case DFPP_READ_WORD:
address = ((shm_read_small *)shm)->address;
((shm_retval *)shm)->value = *((uint16_t*) address);
full_barrier
((shm_retval *)shm)->pingpong = DFPP_RET_WORD;
goto check_again;
case DFPP_READ_BYTE:
address = ((shm_read_small *)shm)->address;
((shm_retval *)shm)->value = *((uint8_t*) address);
full_barrier
((shm_retval *)shm)->pingpong = DFPP_RET_BYTE;
goto check_again;
case DFPP_WRITE:
address = ((shm_write *)shm)->address;
length = ((shm_write *)shm)->length;
memcpy((void *)address, shm + SHM_HEADER,length);
full_barrier
((shm_cmd *)shm)->pingpong = DFPP_SUSPENDED;
goto check_again;
case DFPP_WRITE_DWORD:
(*(uint32_t*)((shm_write_small *)shm)->address) = ((shm_write_small *)shm)->value;
full_barrier
((shm_cmd *)shm)->pingpong = DFPP_SUSPENDED;
goto check_again;
case DFPP_WRITE_WORD:
(*(uint16_t*)((shm_write_small *)shm)->address) = ((shm_write_small *)shm)->value;
full_barrier
((shm_cmd *)shm)->pingpong = DFPP_SUSPENDED;
goto check_again;
case DFPP_WRITE_BYTE:
(*(uint8_t*)((shm_write_small *)shm)->address) = ((shm_write_small *)shm)->value;
full_barrier
((shm_cmd *)shm)->pingpong = DFPP_SUSPENDED;
goto check_again;
case DFPP_CL_ERROR:
case DFPP_RUNNING:
//fprintf(stderr, "no. of waits: %d\n", numwaits);
//MessageBox(0,"Broke out of loop properly","FUN", MB_OK);
break;
case DFPP_READ_STL_STRING:
myStringPtr = (std::string *) ((shm_read_small *)shm)->address;
((shm_retval *)shm)->value = myStringPtr->length();
strncpy(shm+SHM_HEADER,myStringPtr->c_str(),myStringPtr->length()+1);// length + 1 for the null terminator
full_barrier
((shm_retval *)shm)->pingpong = DFPP_RET_STRING;
goto check_again;
case DFPP_WRITE_STL_STRING:
myStringPtr = (std::string *) ((shm_write *)shm)->address;
myStringPtr->assign((const char *) (shm + SHM_HEADER));
full_barrier
((shm_cmd *)shm)->pingpong = DFPP_SUSPENDED;
goto check_again;
default:
((shm_retval *)shm)->value = DFEE_INVALID_COMMAND;
full_barrier
((shm_retval *)shm)->pingpong = DFPP_SV_ERROR;
break;
}
}

@ -34,7 +34,10 @@ distribution.
#define DFhackCExport extern "C" __declspec(dllexport) #define DFhackCExport extern "C" __declspec(dllexport)
#include "../library/integers.h" #include "../library/integers.h"
#include <vector>
#include <string>
#include "shms.h" #include "shms.h"
#include "mod-core.h"
#include <stdio.h> #include <stdio.h>
int errorstate = 0; int errorstate = 0;
char *shm = 0; char *shm = 0;
@ -53,21 +56,28 @@ void SHM_Init ( void )
} }
inited = true; inited = true;
char svmutexname [256];
sprintf(svmutexname,"DFSVMutex-%d",OS_getPID());
char clmutexname [256];
sprintf(clmutexname,"DFCLMutex-%d",OS_getPID());
char shmname [256];
sprintf(shmname,"DFShm-%d",OS_getPID());
// create or open mutexes // create or open mutexes
DFSVMutex = CreateMutex( 0, 1, "DFSVMutex"); DFSVMutex = CreateMutex( 0, 1, svmutexname);
if(DFSVMutex == 0) if(DFSVMutex == 0)
{ {
DFSVMutex = OpenMutex(SYNCHRONIZE,false, "DFSVMutex"); DFSVMutex = OpenMutex(SYNCHRONIZE,false, svmutexname);
if(DFSVMutex == 0) if(DFSVMutex == 0)
{ {
errorstate = 1; errorstate = 1;
return; return;
} }
} }
DFCLMutex = CreateMutex( 0, 0, "DFCLMutex"); DFCLMutex = CreateMutex( 0, 0, clmutexname);
if(DFCLMutex == 0) if(DFCLMutex == 0)
{ {
DFCLMutex = OpenMutex(SYNCHRONIZE,false, "DFCLMutex"); DFCLMutex = OpenMutex(SYNCHRONIZE,false, clmutexname);
if(DFCLMutex == 0) if(DFCLMutex == 0)
{ {
CloseHandle(DFSVMutex); CloseHandle(DFSVMutex);
@ -107,7 +117,7 @@ void SHM_Init ( void )
} }
// create virtual memory mapping // create virtual memory mapping
shmHandle = CreateFileMapping(INVALID_HANDLE_VALUE,NULL,PAGE_READWRITE,0,SHM_SIZE,"DFShm"); shmHandle = CreateFileMapping(INVALID_HANDLE_VALUE,NULL,PAGE_READWRITE,0,SHM_SIZE,shmname);
// if can't create or already exists -> nothing happens // if can't create or already exists -> nothing happens
if(GetLastError() == ERROR_ALREADY_EXISTS) if(GetLastError() == ERROR_ALREADY_EXISTS)
{ {
@ -131,8 +141,7 @@ void SHM_Init ( void )
shm = (char *) MapViewOfFile(shmHandle,FILE_MAP_ALL_ACCESS, 0,0, SHM_SIZE); shm = (char *) MapViewOfFile(shmHandle,FILE_MAP_ALL_ACCESS, 0,0, SHM_SIZE);
if(shm) if(shm)
{ {
((shm_cmd *)shm)->pingpong = DFPP_RUNNING; ((shm_cmd *)shm)->pingpong = CORE_RUNNING;
//MessageBox(0,"Sucessfully mapped SHM","FUN", MB_OK);
} }
else else
{ {
@ -142,22 +151,35 @@ void SHM_Init ( void )
CloseHandle(DFSVMutex); CloseHandle(DFSVMutex);
CloseHandle(DFCLMutex); CloseHandle(DFCLMutex);
} }
InitModules();
} }
void SHM_Destroy ( void ) void SHM_Destroy ( void )
{ {
if(errorstate) if(errorstate)
return; return;
KillModules();
ReleaseMutex(DFSVMutex); ReleaseMutex(DFSVMutex);
CloseHandle(DFSVMutex); CloseHandle(DFSVMutex);
CloseHandle(DFCLMutex); CloseHandle(DFCLMutex);
} }
uint32_t getPID() uint32_t OS_getPID()
{ {
return GetCurrentProcessId(); return GetCurrentProcessId();
} }
// TODO: move to some utils file
uint32_t OS_getAffinity()
{
HANDLE hProcess = GetCurrentProcess();
DWORD dwProcessAffinityMask, dwSystemAffinityMask;
GetProcessAffinityMask( hProcess, &dwProcessAffinityMask, &dwSystemAffinityMask );
return dwProcessAffinityMask;
}
// is the other side still there? // is the other side still there?
bool isValidSHM() bool isValidSHM()
{ {
@ -665,7 +687,7 @@ DFhackCExport void SDL_Quit(void)
static void (*_SDL_GL_SwapBuffers)(void) = 0; static void (*_SDL_GL_SwapBuffers)(void) = 0;
DFhackCExport void SDL_GL_SwapBuffers(void) DFhackCExport void SDL_GL_SwapBuffers(void)
{ {
if(!errorstate && ((shm_cmd *)shm)->pingpong != DFPP_RUNNING) if(!errorstate && ((shm_cmd *)shm)->pingpong != CORE_RUNNING)
{ {
SHM_Act(); SHM_Act();
} }
@ -678,7 +700,7 @@ DFhackCExport int SDL_Flip(void * some_ptr)
{ {
if(_SDL_Flip) if(_SDL_Flip)
{ {
if(!errorstate && ((shm_cmd *)shm)->pingpong != DFPP_RUNNING) if(!errorstate && ((shm_cmd *)shm)->pingpong != CORE_RUNNING)
{ {
SHM_Act(); SHM_Act();
} }

@ -1,10 +1,9 @@
#ifndef DFCONNECT_H #ifndef DFCONNECT_H
#define DFCONNECT_H #define DFCONNECT_H
#define PINGPONG_VERSION 2
#define SHM_KEY 123466 #define SHM_KEY 123466
#define SHM_HEADER 1024 #define SHM_HEADER 1024 // 1kB reserved for a header
#define SHM_BODY 1024*1024 #define SHM_BODY 1024*1024 // 1MB reserved for bulk data transfer
#define SHM_SIZE SHM_HEADER+SHM_BODY #define SHM_SIZE SHM_HEADER+SHM_BODY
@ -12,16 +11,14 @@
#ifdef LINUX_BUILD #ifdef LINUX_BUILD
// a full memory barrier! better be safe than sorry. // a full memory barrier! better be safe than sorry.
#define full_barrier asm volatile("" ::: "memory"); __sync_synchronize(); #define full_barrier asm volatile("" ::: "memory"); __sync_synchronize();
#define SCHED_YIELD sched_yield(); // slow but allows the SHM to work on single-core #define SCHED_YIELD sched_yield(); // a requirement for single-core
// #define SCHED_YIELD usleep(0); // extremely slow
// #define SCHED_YIELD // works only on multi-core
#else #else
// we need windows.h for Sleep() // we need windows.h for Sleep()
#define _WIN32_WINNT 0x0501 // needed for INPUT struct #define _WIN32_WINNT 0x0501 // needed for INPUT struct
#define WINVER 0x0501 // OpenThread(), PSAPI, Toolhelp32 #define WINVER 0x0501 // OpenThread(), PSAPI, Toolhelp32
#define WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN
#include <windows.h> #include <windows.h>
#define SCHED_YIELD Sleep(0); // slow on single-core, but avoids infinite lockup #define SCHED_YIELD Sleep(0); // avoids infinite lockup on single core
// FIXME: detect MSVC here and use the right barrier magic // FIXME: detect MSVC here and use the right barrier magic
#ifdef __MINGW32__ #ifdef __MINGW32__
#define full_barrier asm volatile("" ::: "memory"); #define full_barrier asm volatile("" ::: "memory");
@ -32,124 +29,76 @@
#endif #endif
#endif #endif
enum DFPP_CmdType
/*
* read - parameters are address and length
* write - parameters are address, length and the actual data to write
* wait - sent to DF so that it waits for more commands
* end - sent to DF for breaking out of the wait
*/
enum DF_SHM_ERRORSTATE
{ {
SHM_OK, // all OK CANCELLATION, // we should jump out of the Act()
SHM_CANT_GET_SHM, // getting the SHM ID failed for some reason CLIENT_WAIT, // we are waiting for the client
SHM_CANT_ATTACH, // we can't attach the shm for some reason FUNCTION, // we call a function as a result of the command
SHM_SECOND_DF // we are a second DF process, can't use SHM at all
}; };
enum DF_PINGPONG struct DFPP_command
{ {
DFPP_RUNNING = 0, // no command, normal server execution void (*_function)(void *);
DFPP_CmdType type:32; // force the enum to 32 bits for compatibility reasons
DFPP_VERSION, // protocol version query std::string name;
DFPP_RET_VERSION, // return the protocol version uint32_t nextState;
DFPP_PID, // query for the process ID
DFPP_RET_PID, // return process ID
// version 1 stuff below
DFPP_READ, // cl -> sv, read some data
DFPP_RET_DATA, // sv -> cl, returned data
DFPP_READ_DWORD, // cl -> sv, read a dword
DFPP_RET_DWORD, // sv -> cl, returned dword
DFPP_READ_WORD, // cl -> sv, read a word
DFPP_RET_WORD, // sv -> cl, returned word
DFPP_READ_BYTE, // cl -> sv, read a byte
DFPP_RET_BYTE, // sv -> cl, returned byte
DFPP_SV_ERROR, // there was a server error
DFPP_CL_ERROR, // there was a client error
DFPP_WRITE,// client writes to server
DFPP_WRITE_DWORD,// client writes a DWORD to server
DFPP_WRITE_WORD,// client writes a WORD to server
DFPP_WRITE_BYTE,// client writes a BYTE to server
DFPP_SUSPEND, // client notifies server to wait for commands (server is stalled in busy wait)
DFPP_SUSPENDED, // response to WAIT, server is stalled in busy wait
// all strings capped at 1MB
DFPP_READ_STL_STRING,// client requests contents of STL string at address
DFPP_READ_C_STRING,// client requests contents of a C string at address, max length (0 means zero terminated)
DFPP_RET_STRING, // sv -> cl length + string contents
DFPP_WRITE_STL_STRING,// client wants to set STL string at address to something
// vector elements > 1MB are not supported because they don't fit into the shared memory
DFPP_READ_ENTIRE_VECTOR, // read an entire vector (parameters are address of vector object and size of items)
DFPP_RET_VECTOR_BODY, // a part of a vector is returned - no. of elements returned, no. of elements total, elements
NUM_DFPP
}; };
struct DFPP_module
enum DF_ERROR
{ {
DFEE_INVALID_COMMAND, DFPP_module()
DFEE_BUFFER_OVERFLOW {
name = "Uninitialized module";
version = 0;
modulestate = 0;
}
// ALERT: the structures share state
DFPP_module(const DFPP_module & orig)
{
commands = orig.commands;
name = orig.name;
modulestate = orig.modulestate;
version = orig.version;
}
inline void set_command(const unsigned int index, const DFPP_CmdType type, const char * name, void (*_function)(void *) = 0,uint32_t nextState = -1)
{
commands[index].type = type;
commands[index].name = name;
commands[index]._function = _function;
commands[index].nextState = nextState;
}
inline void reserve (unsigned int numcommands)
{
commands.clear();
DFPP_command cmd = {0,CANCELLATION,"",0};
commands.resize(numcommands,cmd);
}
std::string name;
uint32_t version; // version
std::vector <DFPP_command> commands;
void * modulestate;
}; };
typedef struct typedef union
{
volatile uint32_t pingpong; // = 0
} shm_cmd;
typedef struct
{
volatile uint32_t pingpong;
uint32_t address;
uint32_t length;
} shm_read;
typedef shm_read shm_write;
typedef shm_read shm_bounce;
typedef struct
{
volatile uint32_t pingpong;
} shm_ret_data;
typedef struct
{ {
struct
{
volatile uint16_t command;
volatile uint16_t module;
} parts;
volatile uint32_t pingpong; volatile uint32_t pingpong;
uint32_t address; inline void set(uint16_t module, uint16_t command)
} shm_read_small; {
pingpong = module + command << 16;
typedef struct }
{ } shm_cmd;
volatile uint32_t pingpong;
uint32_t address;
uint32_t value;
} shm_write_small;
typedef struct
{
volatile uint32_t pingpong;
uint32_t value;
} shm_retval;
typedef struct
{
volatile uint32_t pingpong;
uint32_t length;
} shm_retstr;
void SHM_Act (void); void SHM_Act (void);
void InitModules (void);
void KillModules (void);
bool isValidSHM(); bool isValidSHM();
uint32_t getPID(); uint32_t OS_getPID();
DFPP_module InitMaps(void);
uint32_t OS_getAffinity(); // limited to 32 processors. Silly, eh?
#endif #endif