Merge remote branch 'remotes/peterix/master' into version_compatiblity

trying merge

Conflicts:
	examples/creaturedump.cpp
	output/Memory.xml
develop
belal 2010-03-13 08:45:30 -05:00
commit 0582354191
29 changed files with 1881 additions and 843 deletions

@ -319,8 +319,10 @@ int main (void)
cerr << "Can't get the creature types." << endl;
return 1;
}
if(!DF.InitReadNameTables(names))
vector< vector<string> > englishWords;
vector< vector<string> > foreignWords;
if(!DF.InitReadNameTables(englishWords,foreignWords))
{
cerr << "Can't get name tables" << endl;
return 1;
@ -335,8 +337,148 @@ int main (void)
for(uint32_t i = 0; i < numCreatures; i++)
{
DFHack::t_creature temp;
DF.ReadCreature(i,temp);
printCreature(DF,temp);
DF.ReadCreature(i, temp);
if(string(creaturestypes[temp.type].id) == "DWARF")
{
cout << "address: " << temp.origin << " creature type: " << creaturestypes[temp.type].id << ", position: " << temp.x << "x " << temp.y << "y "<< temp.z << "z" << endl;
bool addendl = false;
if(temp.name.first_name[0])
{
cout << "first name: " << temp.name.first_name;
addendl = true;
}
if(temp.name.nickname[0])
{
cout << ", nick name: " << temp.name.nickname;
addendl = true;
}
string transName = DF.TranslateName(temp.name,englishWords,foreignWords,false);
if(!transName.empty())
{
cout << ", trans name: " << transName;
addendl=true;
}
//cout << ", generic name: " << DF.TranslateName(temp.last_name,names,"GENERIC");
/*
if(!temp.trans_name.empty()){
cout << ", trans name: " << temp.trans_name;
addendl =true;
}
if(!temp.generic_name.empty()){
cout << ", generic name: " << temp.generic_name;
addendl=true;
}
*/
cout << ", likes: ";
for(uint32_t i = 0;i<temp.numLikes; i++)
{
if(printLike(temp.likes[i],mat,itemTypes))
{
cout << ", ";
}
}
if(addendl)
{
cout << endl;
addendl = false;
}
cout << "profession: " << mem->getProfession(temp.profession) << "(" << (int) temp.profession << ")";
if(temp.custom_profession[0])
{
cout << ", custom profession: " << temp.custom_profession;
}
if(temp.current_job.active)
{
cout << ", current job: " << mem->getJob(temp.current_job.jobId);
}
cout << endl;
cout << "happiness: " << temp.happiness << ", strength: " << temp.strength << ", agility: "
<< temp.agility << ", toughness: " << temp.toughness << ", money: " << temp.money << ", id: " << temp.id;
if(temp.squad_leader_id != -1)
{
cout << ", squad_leader_id: " << temp.squad_leader_id;
}
cout << ", sex: ";
if(temp.sex == 0)
{
cout << "Female";
}
else
{
cout <<"Male";
}
cout << endl;
/*
//skills
for(unsigned int i = 0; i < temp.skills.size();i++){
if(i > 0){
cout << ", ";
}
cout << temp.skills[i].name << ": " << temp.skills[i].rating;
}
*/
/*
* FLAGS 1
*/
cout << "flags1: ";
print_bits(temp.flags1.whole, cout);
cout << endl;
if(temp.flags1.bits.dead)
{
cout << "dead ";
}
if(temp.flags1.bits.on_ground)
{
cout << "on the ground, ";
}
if(temp.flags1.bits.skeleton)
{
cout << "skeletal ";
}
if(temp.flags1.bits.zombie)
{
cout << "zombie ";
}
if(temp.flags1.bits.tame)
{
cout << "tame ";
}
if(temp.flags1.bits.royal_guard)
{
cout << "royal_guard ";
}
if(temp.flags1.bits.fortress_guard)
{
cout << "fortress_guard ";
}
/*
* FLAGS 2
*/
cout << endl << "flags2: ";
print_bits(temp.flags2.whole, cout);
cout << endl;
if(temp.flags2.bits.killed)
{
cout << "killed by kill function, ";
}
if(temp.flags2.bits.resident)
{
cout << "resident, ";
}
if(temp.flags2.bits.gutted)
{
cout << "gutted, ";
}
if(temp.flags2.bits.slaughter)
{
cout << "marked for slaughter, ";
}
if(temp.flags2.bits.underworld)
{
cout << "from the underworld, ";
}
cout << endl << endl;
}
}
uint32_t currentIdx;
DFHack::t_creature currentCreature;

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

@ -50,8 +50,9 @@ int main (void)
cerr << "DF not found" << endl;
return 1;
}
map< string, vector<string> > names;
if(!DF.InitReadNameTables(names))
vector< vector<string> > englishWords;
vector< vector<string> > foreignWords;
if(!DF.InitReadNameTables(englishWords,foreignWords))
{
cerr << "Could not get Names" << endl;
return 1;
@ -61,7 +62,7 @@ int main (void)
cout << "\nSelect Name to search or q to Quit" << endl;
getline (cin, input);
while(input != "q"){
for( map< string, vector<string> >::iterator it = names.begin();it != names.end(); it++){
/*for( map< string, vector<string> >::iterator it = names.begin();it != names.end(); it++){
for(uint32_t i = 0; i < it->second.size(); i++){
uint32_t found = tolower(input).find(tolower(it->second[i]));
if(found != string::npos){
@ -70,7 +71,7 @@ int main (void)
cout << it->first << " " << it->second[i] << " " << groupBy2(value.str()) << endl;
}
}
}
}*/
DF.Resume();
getline(cin,input);
}

@ -7,6 +7,7 @@
#include <vector>
using namespace std;
#include <DFError.h>
#include <DFTypes.h>
#include <DFHackAPI.h>
#include <DFMemInfo.h>
@ -23,7 +24,8 @@ void print_bits ( T val, std::ostream& out )
val >>= 1;
}
}
map<string, vector<string> > names;
vector< vector<string> > englishWords;
vector< vector<string> > foreignWords;
uint32_t numCreatures;
vector<DFHack::t_matgloss> creaturestypes;
void printDwarves(DFHack::API & DF)
@ -37,15 +39,15 @@ void printDwarves(DFHack::API & DF)
if (type == "DWARF" && !temp.flags1.bits.dead && !temp.flags2.bits.killed)
{
cout << i << ":";
if (temp.nick_name[0])
if (temp.name.nickname[0])
{
cout << temp.nick_name;
cout << temp.name.nickname;
}
else
{
cout << temp.first_name;
cout << temp.name.first_name;
}
string transName = DF.TranslateName(temp.last_name,names,creaturestypes[temp.type].id);
string transName = DF.TranslateName(temp.name,englishWords,foreignWords, false);
cout << " " << temp.custom_profession; //transName;
if (dwarfCounter%3 != 2)
{
@ -109,7 +111,7 @@ bool getDwarfSelection(DFHack::API & DF, DFHack::t_creature & toChange,string &
if (input == "n")
{
commandString = "pzyn";
eraseAmount = string(toChange.nick_name).length();
eraseAmount = string(toChange.name.nickname).length();
changeType = true;
isName = true;
}
@ -153,7 +155,7 @@ bool waitTillChanged(DFHack::API &DF, int creatureToCheck, string changeValue, b
int tryCount = 0;
if (isName)
{
while (testCre.nick_name != changeValue && tryCount <50)
while (testCre.name.nickname != changeValue && tryCount <50)
{
DF.Resume();
w->TypeSpecial(DFHack::WAIT,1,100);
@ -324,7 +326,7 @@ int main (void)
return 1;
}
DF.InitReadNameTables(names);
DF.InitReadNameTables(englishWords,foreignWords);
DF.InitReadCreatures(numCreatures);
DF.InitViewAndCursor();
DFHack::Process * p = DF.getProcess();
@ -435,11 +437,28 @@ start:
// I have the writeString function do nothing for normal mode
if (commandString == "pzyn") // change nickname
{
p->writeSTLString(toChange.origin+mem->getOffset("creature_nick_name"),changeString);
try
{
uint32_t nickname = mem->getOffset("creature_name") + mem->getOffset("name_nickname");
p->writeSTLString(toChange.origin+nickname,changeString);
}
catch (DFHack::Error::MissingMemoryDefinition& e)
{
cerr << "Writing creature nicknames unsupported in this version!" << endl;
}
}
else
{
p->writeSTLString(toChange.origin+mem->getOffset("creature_custom_profession"),changeString);
try
{
uint32_t custom_prof = mem->getOffset("creature_custom_profession");
p->writeSTLString(toChange.origin+custom_prof,changeString);
}
catch (DFHack::Error::MissingMemoryDefinition& e)
{
cerr << "Writing creature custom profession unsupported in this version!" << endl;
}
}
}
DF.Suspend();

@ -8,13 +8,25 @@ using namespace std;
#include <DFTypes.h>
#include <DFHackAPI.h>
#include <stdio.h>
void printSettlement(DFHack::API & DF, const DFHack::t_settlement & settlement, const map<string, vector<string> > &names)
void printSettlement(DFHack::API & DF, const DFHack::t_settlement & settlement, const vector< vector<string> > &englishWords, const vector< vector<string> > &foreignWords)
{
string genericName = DF.TranslateName(settlement.name,2,names,"GENERIC");
string dwarfName = DF.TranslateName(settlement.name,2,names,"DWARF");
cout << dwarfName << " " << genericName << " " << "world x: " << settlement.world_x << " world y: " << settlement.world_y
<< " local_x: " << settlement.local_x1 << " local_y: " << settlement.local_y1 << " size: " << settlement.local_x2 - settlement.local_x1 << " by " << settlement.local_y2 - settlement.local_y1 << "\n";
cout << "First name: " << settlement.name.first_name << endl << "Nickname: " << settlement.name.nickname << endl;
cout << settlement.name.words[0] << " " << settlement.name.words[1] << " " << settlement.name.words[2] << " "
<< settlement.name.words[3] << " " << settlement.name.words[4] << " " << settlement.name.words[5] << " "
<< settlement.name.words[6] << " " << settlement.name.words[7] << endl;
cout << settlement.name.parts_of_speech[0] << " " << settlement.name.parts_of_speech[1] << " " << settlement.name.parts_of_speech[2] << " "
<< settlement.name.parts_of_speech[3] << " " << settlement.name.parts_of_speech[4] << " " << settlement.name.parts_of_speech[5] << " "
<< settlement.name.parts_of_speech[6] << " " << settlement.name.parts_of_speech[7] << endl;
printf("Origin: 0x%x\n",settlement.origin);
string genericName = DF.TranslateName(settlement.name,englishWords,foreignWords,true);
string dwarfName = DF.TranslateName(settlement.name,englishWords,foreignWords,false);
cout << dwarfName << " " << genericName << " " << "world x: " << settlement.world_x << " world y: " << settlement.world_y
<< " local_x: " << settlement.local_x1 << " local_y: " << settlement.local_y1 << " size: " << settlement.local_x2 - settlement.local_x1 << " by " << settlement.local_y2 - settlement.local_y1 << "\n";
}
int main (int argc,const char* argv[])
@ -32,22 +44,23 @@ int main (int argc,const char* argv[])
cerr << "Could not read Settlements" << endl;
return 1;
}
map<string, vector<string> > names;
if(!DF.InitReadNameTables(names))
vector< vector<string> > englishWords;
vector< vector<string> > foreignWords;
if(!DF.InitReadNameTables(englishWords,foreignWords))
{
cerr << "Can't get name tables" << endl;
return 1;
}
cout << "Settlements\n";
for(uint32_t i =0;i<numSettlements;i++){
/*for(uint32_t i =0;i<numSettlements;i++){
DFHack::t_settlement temp;
DF.ReadSettlement(i,temp);
printSettlement(DF,temp,names);
}
printSettlement(DF,temp,englishWords,foreignWords);
}*/
// MSVC claims this is causing the heap to be corrupted, I think it is because the currentSettlement vector only has 1 item in it
cout << "Current Settlement\n";
DF.ReadCurrentSettlement(current);
printSettlement(DF,current,names);
if(DF.ReadCurrentSettlement(current))
printSettlement(DF,current,englishWords,foreignWords);
DF.FinishReadNameTables();
DF.FinishReadSettlements();

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

@ -210,6 +210,17 @@ namespace DFHack
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 "../shmserver/shms.h"
#include "../shmserver/mod-core.h"
#include "../shmserver/mod-maps.h"
using namespace DFHack;
/*
@ -36,6 +39,11 @@ public:
, pm (NULL), p (NULL), offset_descriptor (NULL)
, p_cons (NULL), p_bld (NULL), p_veg (NULL)
{}
void readName(t_name & name, uint32_t address);
// get the name offsets
bool InitReadNames();
uint32_t * block;
uint32_t x_block_count, y_block_count, z_block_count;
uint32_t regionX, regionY, regionZ;
@ -61,14 +69,15 @@ public:
uint32_t view_screen_offset;
uint32_t current_menu_state_offset;
uint32_t name_firstname_offset;
uint32_t name_nickname_offset;
uint32_t name_words_offset;
uint32_t creature_pos_offset;
uint32_t creature_type_offset;
uint32_t creature_flags1_offset;
uint32_t creature_flags2_offset;
uint32_t creature_first_name_offset;
uint32_t creature_nick_name_offset;
uint32_t creature_last_name_offset;
uint32_t creature_name_offset;
uint32_t creature_custom_profession_offset;
uint32_t creature_profession_offset;
uint32_t creature_sex_offset;
@ -86,6 +95,8 @@ public:
uint32_t creature_happiness_offset;
uint32_t creature_traits_offset;
uint32_t creature_likes_offset;
uint32_t creature_artifact_name_offset;
uint32_t creature_mood_offset;
uint32_t item_material_offset;
@ -106,6 +117,7 @@ public:
ProcessEnumerator* pm;
Process* p;
char * shm_start;
memory_info* offset_descriptor;
vector<uint16_t> v_geology[eBiomeCount];
string xml;
@ -118,9 +130,12 @@ public:
bool viewSizeInited;
bool itemsInited;
bool notesInited;
bool namesInited;
bool hotkeyInited;
bool settlementsInited;
bool nameTablesInited;
uint32_t maps_module;
uint32_t tree_offset;
DfVector *p_cre;
@ -133,6 +148,23 @@ public:
DfVector *p_current_settlement;
};
// FIXME: flesh it out
bool API::Private::InitReadNames()
{
name_firstname_offset = offset_descriptor->getOffset("name_firstname");
name_nickname_offset = offset_descriptor->getOffset("name_nickname");
name_words_offset = offset_descriptor->getOffset("name_words");
return true;
}
void API::Private::readName(t_name & name, uint32_t address)
{
g_pProcess->readSTLString(address + name_firstname_offset , name.first_name, 128);
g_pProcess->readSTLString(address + name_nickname_offset , name.nickname, 128);
g_pProcess->read(address + name_words_offset ,48, (uint8_t *) name.words);
}
API::API (const string path_to_xml)
: d (new Private())
{
@ -149,6 +181,8 @@ API::API (const string path_to_xml)
d->notesInited = false;
d->hotkeyInited = false;
d->pm = NULL;
d->shm_start = 0;
d->maps_module = 0;
}
API::~API()
@ -156,6 +190,11 @@ API::~API()
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 *
*-----------------------------------*/
@ -181,19 +220,43 @@ bool API::InitMap()
d->offset_descriptor->resolveClassnameToVPtr("block_square_event_frozen_liquid", d->vein_ice_vptr);
d->vein_mineral_vptr = 0;
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
uint32_t x_array_loc = g_pProcess->readDWord (map_offset);
//FIXME: very inadequate
if (!x_array_loc)
{
throw Error::NoMapLoaded();
// bad stuffz happend
//return false;
}
uint32_t mx, my, mz;
// get the size
uint32_t mx, my, mz;
mx = d->x_block_count = g_pProcess->readDWord (x_count_offset);
my = d->y_block_count = g_pProcess->readDWord (y_count_offset);
mz = d->z_block_count = g_pProcess->readDWord (z_count_offset);
@ -253,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];
}
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)
bool API::ReadTileTypes (uint32_t x, uint32_t y, uint32_t z, uint16_t *buffer)
{
@ -697,7 +797,7 @@ bool API::ReadGeology (vector < vector <uint16_t> >& assign)
}
assign.clear();
assign.reserve (eBiomeCount);
// TODO: clean this up
// // TODO: clean this up
for (int i = 0; i < eBiomeCount;i++)
{
assign.push_back (d->v_geology[i]);
@ -854,14 +954,13 @@ bool API::InitReadCreatures( uint32_t &numcreatures )
try
{
memory_info * minfo = d->offset_descriptor;
d->InitReadNames();
int creatures = d->offset_descriptor->getAddress ("creatures");
d->creature_pos_offset = minfo->getOffset ("creature_position");
d->creature_type_offset = minfo->getOffset ("creature_race");
d->creature_flags1_offset = minfo->getOffset ("creature_flags1");
d->creature_flags2_offset = minfo->getOffset ("creature_flags2");
d->creature_first_name_offset = minfo->getOffset ("creature_first_name");
d->creature_nick_name_offset = minfo->getOffset ("creature_nick_name");
d->creature_last_name_offset = minfo->getOffset ("creature_last_name");
d->creature_name_offset = minfo->getOffset ("creature_name");
d->creature_custom_profession_offset = minfo->getOffset ("creature_custom_profession");
d->creature_profession_offset = minfo->getOffset ("creature_profession");
d->creature_sex_offset = minfo->getOffset ("creature_sex");
@ -879,6 +978,8 @@ bool API::InitReadCreatures( uint32_t &numcreatures )
d->creature_happiness_offset = minfo->getOffset ("creature_happiness");
d->creature_traits_offset = minfo->getOffset ("creature_traits");
d->creature_likes_offset = minfo->getOffset("creature_likes");
d->creature_artifact_name_offset = minfo->getOffset("creature_artifact_name");
d->creature_mood_offset = minfo->getOffset("creature_mood");
d->p_cre = new DfVector (d->p->readVector (creatures, 4));
//InitReadNameTables();
@ -932,6 +1033,7 @@ bool API::InitReadSettlements( uint32_t & numsettlements )
{
try
{
d->InitReadNames();
memory_info * minfo = d->offset_descriptor;
int allSettlements = minfo->getAddress ("settlements");
int currentSettlement = minfo->getAddress("settlement_current");
@ -960,7 +1062,7 @@ bool API::ReadSettlement(const int32_t index, t_settlement & settlement)
// read pointer from vector at position
uint32_t temp = * (uint32_t *) d->p_settlements->at (index);
settlement.origin = temp;
g_pProcess->read(temp + d->settlement_name_offset, 2 * sizeof(int32_t), (uint8_t *) &settlement.name);
d->readName(settlement.name, temp + d->settlement_name_offset);
g_pProcess->read(temp + d->settlement_world_xy_offset, 2 * sizeof(int16_t), (uint8_t *) &settlement.world_x);
g_pProcess->read(temp + d->settlement_local_xy_offset, 4 * sizeof(int16_t), (uint8_t *) &settlement.local_x1);
return true;
@ -973,7 +1075,7 @@ bool API::ReadCurrentSettlement(t_settlement & settlement)
uint32_t temp = * (uint32_t *) d->p_current_settlement->at(0);
settlement.origin = temp;
g_pProcess->read(temp + d->settlement_name_offset, 2 * sizeof(int32_t), (uint8_t *) &settlement.name);
d->readName(settlement.name, temp + d->settlement_name_offset);
g_pProcess->read(temp + d->settlement_world_xy_offset, 2 * sizeof(int16_t), (uint8_t *) &settlement.world_x);
g_pProcess->read(temp + d->settlement_local_xy_offset, 4 * sizeof(int16_t), (uint8_t *) &settlement.local_x1);
return true;
@ -1098,17 +1200,12 @@ bool API::ReadCreature (const int32_t index, t_creature & furball)
g_pProcess->readDWord (temp + d->creature_type_offset, furball.type);
g_pProcess->readDWord (temp + d->creature_flags1_offset, furball.flags1.whole);
g_pProcess->readDWord (temp + d->creature_flags2_offset, furball.flags2.whole);
// normal names
d->p->readSTLString (temp + d->creature_first_name_offset, furball.first_name, 128);
d->p->readSTLString (temp + d->creature_nick_name_offset, furball.nick_name, 128);
// names
d->readName(furball.name,temp + d->creature_name_offset);
d->readName(furball.squad_name, temp + d->creature_squad_name_offset);
d->readName(furball.artifact_name, temp + d->creature_artifact_name_offset);
// custom profession
d->p->readSTLString (temp + d->creature_nick_name_offset, furball.nick_name, 128);
fill_char_buf (furball.custom_profession, d->p->readSTLString (temp + d->creature_custom_profession_offset));
// crazy composited names
g_pProcess->read (temp + d->creature_last_name_offset, sizeof (t_lastname), (uint8_t *) &furball.last_name);
g_pProcess->read (temp + d->creature_squad_name_offset, sizeof (t_squadname), (uint8_t *) &furball.squad_name);
// labors
g_pProcess->read (temp + d->creature_labors_offset, NUM_CREATURE_LABORS, furball.labors);
@ -1150,6 +1247,9 @@ bool API::ReadCreature (const int32_t index, t_creature & furball)
g_pProcess->read(temp2,sizeof(t_like),(uint8_t *) &furball.likes[i]);
}
g_pProcess->readWord (temp + d->creature_mood_offset, furball.mood);
g_pProcess->readDWord (temp + d->creature_happiness_offset, furball.happiness);
g_pProcess->readDWord (temp + d->creature_id_offset, furball.id);
g_pProcess->readDWord (temp + d->creature_agility_offset, furball.agility);
@ -1167,34 +1267,40 @@ void API::WriteLabors(const uint32_t index, uint8_t labors[NUM_CREATURE_LABORS])
WriteRaw(temp + d->creature_labors_offset, NUM_CREATURE_LABORS, labors);
}
bool API::InitReadNameTables (map< string, vector<string> > & nameTable)
bool API::InitReadNameTables(vector<vector<string> > & translations , vector<vector<string> > & foreign_languages) //(map< string, vector<string> > & nameTable)
{
try
{
int genericAddress = d->offset_descriptor->getAddress ("language_vector");
int transAddress = d->offset_descriptor->getAddress ("translation_vector");
int word_table_offset = d->offset_descriptor->getOffset ("word_table");
int sizeof_string = d->offset_descriptor->getHexValue ("sizeof_string");
DfVector genericVec (d->p->readVector (genericAddress, 4));
DfVector transVec (d->p->readVector (transAddress, 4));
translations.resize(10);
for (uint32_t i = 0;i < genericVec.getSize();i++)
{
uint32_t genericNamePtr = * (uint32_t *) genericVec.at (i);
string genericName = d->p->readSTLString (genericNamePtr);
nameTable["GENERIC"].push_back (genericName);
for(int i=0; i<10;i++)
{
string word = d->p->readSTLString (genericNamePtr + i * sizeof_string);
translations[i].push_back (word);
}
}
foreign_languages.resize(transVec.getSize());
for (uint32_t i = 0; i < transVec.getSize();i++)
{
uint32_t transPtr = * (uint32_t *) transVec.at (i);
string transName = d->p->readSTLString (transPtr);
//string transName = d->p->readSTLString (transPtr);
DfVector trans_names_vec (d->p->readVector (transPtr + word_table_offset, 4));
for (uint32_t j = 0;j < trans_names_vec.getSize();j++)
{
uint32_t transNamePtr = * (uint32_t *) trans_names_vec.at (j);
string name = d->p->readSTLString (transNamePtr);
nameTable[transName].push_back (name);
foreign_languages[i].push_back (name);
}
}
d->nameTablesInited = true;
@ -1207,71 +1313,76 @@ bool API::InitReadNameTables (map< string, vector<string> > & nameTable)
}
}
string API::TranslateName (const int names[], int size, const map<string, vector<string> > & nameTable, const string & language)
string API::TranslateName(const DFHack::t_name &name,const std::vector< std::vector<std::string> > & translations ,const std::vector< std::vector<std::string> > & foreign_languages, bool inEnglish)
{
string trans;
string out;
assert (d->nameTablesInited);
map<string, vector<string> >::const_iterator it;
it = nameTable.find (language);
if (it != nameTable.end())
if(!inEnglish)
{
for (int i = 0;i < size;i++)
if(name.words[0] >=0 || name.words[1] >=0)
{
if (names[i] == -1)
{
break;
}
trans.append (it->second[names[i]]);
if(name.words[0]>=0) out.append(foreign_languages[name.language][name.words[0]]);
if(name.words[1]>=0) out.append(foreign_languages[name.language][name.words[1]]);
out[0] = toupper(out[0]);
}
}
return (trans);
}
string API::TranslateName (const t_lastname & last, const map<string, vector<string> > & nameTable, const string & language)
{
string trans_last;
assert (d->nameTablesInited);
map<string, vector<string> >::const_iterator it;
it = nameTable.find (language);
if (it != nameTable.end())
{
for (int i = 0;i < 7;i++)
if(name.words[5] >=0)
{
if (last.names[i] == -1)
{
break;
}
trans_last.append (it->second[last.names[i]]);
string word;
for(int i=2;i<=5;i++)
if(name.words[i]>=0) word.append(foreign_languages[name.language][name.words[i]]);
word[0] = toupper(word[0]);
if(out.length() > 0) out.append(" ");
out.append(word);
}
}
return (trans_last);
}
string API::TranslateName (const t_squadname & squad, const map<string, vector<string> > & nameTable, const string & language)
{
string trans_squad;
assert (d->nameTablesInited);
map<string, vector<string> >::const_iterator it;
it = nameTable.find (language);
if (it != nameTable.end())
if(name.words[6] >=0)
{
string word;
word.append(foreign_languages[name.language][name.words[6]]);
word[0] = toupper(word[0]);
if(out.length() > 0) out.append(" ");
out.append(word);
}
}
else
{
for (int i = 0;i < 7;i++)
if(name.words[0] >=0 || name.words[1] >=0)
{
if (squad.names[i] == -1)
{
continue;
}
if (squad.names[i] == 0)
{
break;
}
if (i == 4)
if(name.words[0]>=0) out.append(translations[name.parts_of_speech[0]+1][name.words[0]]);
if(name.words[1]>=0) out.append(translations[name.parts_of_speech[1]+1][name.words[1]]);
out[0] = toupper(out[0]);
}
if(name.words[5] >=0)
{
if(out.length() > 0)
out.append(" the");
else
out.append("The");
string word;
for(int i=2;i<=5;i++)
{
trans_squad.append (" ");
if(name.words[i]>=0)
{
word = translations[name.parts_of_speech[i]+1][name.words[i]];
word[0] = toupper(word[0]);
out.append(" " + word);
}
}
trans_squad.append (it->second[squad.names[i]]);
}
if(name.words[6] >=0)
{
if(out.length() > 0)
out.append(" of");
else
out.append("Of");
string word;
word.append(translations[name.parts_of_speech[6]+1][name.words[6]]);
word[0] = toupper(word[0]);
out.append(" " + word);
}
}
return (trans_squad);
return out;
}
void API::FinishReadNameTables()
@ -1325,6 +1436,7 @@ bool API::Attach()
//cerr << "couldn't attach to process" << endl;
//return false; // couldn't attach to process, no go
}
d->shm_start = d->p->getSHMStart();
d->offset_descriptor = d->p->getDescriptor();
// process is attached, everything went just fine... hopefully
return true;
@ -1343,6 +1455,7 @@ bool API::Detach()
}
d->pm = NULL;
d->p = NULL;
d->shm_start = 0;
d->offset_descriptor = NULL;
return true;
}

@ -135,6 +135,8 @@ namespace DFHack
*/
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 WriteTileTypes(uint32_t blockx, uint32_t blocky, uint32_t blockz, uint16_t *buffer); // 256 * sizeof(uint16_t)
@ -222,12 +224,10 @@ namespace DFHack
vector<t_trait> getTraits(const uint32_t &index);
vector<t_labor> getLabors(const uint32_t &index);
*/
bool InitReadNameTables (std::map< std::string, std::vector<std::string> > & nameTable);
bool InitReadNameTables (std::vector< std::vector<std::string> > & translations , std::vector< std::vector<std::string> > & foreign_languages);
void FinishReadNameTables();
std::string TranslateName(const t_lastname & last, const std::map< std::string, std::vector< std::string > > &nameTable,const std::string & language="GENERIC");
std::string TranslateName(const t_squadname & squad, const std::map< std::string, std::vector< std::string > > &nameTable,const std::string & language="GENERIC");
std::string TranslateName (const int names[], int size, const std::map<std::string, std::vector<std::string> > &nameTable, const std::string & language="GENERIC");
std::string TranslateName(const t_name & name,const std::vector< std::vector<std::string> > & translations ,const std::vector< std::vector<std::string> > & foreign_languages, bool inEnglish=true);
void WriteLabors(const uint32_t index, uint8_t labors[NUM_CREATURE_LABORS]);

@ -95,7 +95,7 @@ memory_info::memory_info(const memory_info &old)
d->strings = old.d->strings;
d->base = old.d->base;
//d->classes = old.d->classes;
for(int i = 0; i < old.d->classes.size(); i++)
for(uint32_t i = 0; i < old.d->classes.size(); i++)
{
t_class * copy = new t_class(*old.d->classes[i]);
d->classes.push_back(copy);

@ -68,7 +68,7 @@ namespace DFHack
}
~t_class()
{
for(int i = 0; i < subs.size();i++)
for(uint32_t i = 0; i < subs.size();i++)
{
delete subs[i];
}

@ -28,6 +28,7 @@ distribution.
#include <sys/ipc.h>
#include <time.h>
#include "../shmserver/shms.h"
#include "../shmserver/mod-core.h"
#include <sys/time.h>
#include <time.h>
#include <sched.h>
@ -50,6 +51,9 @@ class SHMProcess::Private
attached = false;
suspended = false;
identified = false;
useYield = false;
my_SVfileLock = -1;
my_CLfileLock = -1;
};
~Private(){};
memory_info * my_descriptor;
@ -57,32 +61,77 @@ class SHMProcess::Private
pid_t my_pid;
char *my_shm;
int my_shmid;
Process* q;
int my_SVfileLock;
int my_CLfileLock;
bool attached;
bool suspended;
bool identified;
bool useYield;
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 DF_GetPID(pid_t & ret);
bool Aux_Core_Attach(bool & versionOK, pid_t & PID);
bool waitWhile (uint32_t state);
bool GetLocks();
bool AreLocksOk();
void FreeLocks();
};
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;
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);
if(descriptor.shm_nattch == 1)// DF crashed?
/*
shmctl(my_shmid, IPC_STAT, &descriptor);
if(descriptor.shm_nattch == 1)// DF crashed or exited - no way to tell?
{
//detach the shared memory
shmdt(my_shm);
attached = suspended = false;
// we aren't the current process anymore
g_pProcess = NULL;
throw Error::SHMServerDisappeared();
return false;
}
else
{
gcc_barrier
((shm_cmd *)my_shm)->pingpong = DFPP_RUNNING;
cnt = 0;
}
*/
if(!AreLocksOk())
{
//detach the shared memory
shmdt(my_shm);
attached = suspended = false;
// we aren't the current process anymore
g_pProcess = NULL;
FreeLocks();
throw Error::SHMServerDisappeared();
return false;
}
else
@ -90,12 +139,15 @@ bool SHMProcess::Private::waitWhile (DF_PINGPONG state)
cnt = 0;
}
}
SCHED_YIELD
if(useYield)
{
SCHED_YIELD
}
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;
cerr << "shm server error!" << endl;
assert (false);
@ -104,31 +156,109 @@ bool SHMProcess::Private::waitWhile (DF_PINGPONG state)
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)
{
return d->waitWhile(state);
}
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;
}
bool SHMProcess::Private::Aux_Core_Attach(bool & versionOK, pid_t & PID)
{
((shm_cmd *)my_shm)->pingpong = DFPP_VERSION;
SHMDATA(coreattach)->cl_affinity = OS_getAffinity();
gcc_barrier
if(!waitWhile(DFPP_VERSION))
SHMCMD = CORE_ATTACH;
if(!waitWhile(CORE_ATTACH))
return false;
gcc_barrier
((shm_cmd *)my_shm)->pingpong = DFPP_SUSPENDED;
ret =( ((shm_retval *)my_shm)->value == PINGPONG_VERSION );
versionOK =( SHMDATA(coreattach)->sv_version == CORE_VERSION );
PID = SHMDATA(coreattach)->sv_PID;
useYield = SHMDATA(coreattach)->sv_useYield;
#ifdef DEBUG
if(useYield) cerr << "Using Yield!" << endl;
#endif
return true;
}
bool SHMProcess::Private::DF_GetPID(pid_t & ret)
bool SHMProcess::Private::AreLocksOk()
{
((shm_cmd *)my_shm)->pingpong = DFPP_PID;
gcc_barrier
if(!waitWhile(DFPP_PID))
// both locks are inited (we hold our lock)
if(my_CLfileLock != -1 && my_SVfileLock != -1)
{
if(lockf(my_SVfileLock,F_TEST,0) == -1) // and server holds its lock
{
return true; // OK, locks are good
}
}
// locks are bad
return false;
}
void SHMProcess::Private::FreeLocks()
{
if(my_CLfileLock != -1)
{
lockf(my_CLfileLock,F_ULOCK,0);
close(my_CLfileLock);
my_CLfileLock = -1;
}
if(my_SVfileLock != -1)
{
close(my_SVfileLock);
my_SVfileLock = -1;
}
}
bool SHMProcess::Private::GetLocks()
{
char name[256];
// try to acquire locks
// look at the server lock, if it's locked, the server is present
sprintf(name, "/tmp/DFHack/%d/SVlock",my_pid,name);
my_SVfileLock = open(name,O_WRONLY);
if(my_SVfileLock == -1)
{
return false;
gcc_barrier
((shm_cmd *)my_shm)->pingpong = DFPP_SUSPENDED;
ret = ((shm_retval *)my_shm)->value;
}
if(lockf( my_SVfileLock, F_TEST, 0 ) != -1)
{
close(my_SVfileLock);
return false;
}
// open the client lock, try to lock it
sprintf(name, "/tmp/DFHack/%d/CLlock",my_pid,name);
my_CLfileLock = open(name,O_WRONLY);
if(my_CLfileLock == -1)
{
close(my_SVfileLock);
return false;
}
if(lockf(my_CLfileLock,F_TLOCK, 0) == -1)
{
// couldn't acquire lock
close(my_SVfileLock);
close(my_CLfileLock);
return false;
}
// ok, we have all the locks!
return true;
}
SHMProcess::SHMProcess(vector <memory_info *> & known_versions)
SHMProcess::SHMProcess(uint32_t PID, vector< memory_info* >& known_versions)
: d(new Private())
{
char exe_link_name [256];
@ -138,7 +268,7 @@ SHMProcess::SHMProcess(vector <memory_info *> & known_versions)
/*
* 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;
}
@ -151,57 +281,63 @@ SHMProcess::SHMProcess(vector <memory_info *> & known_versions)
return;
}
/*
* Check if there are two processes connected to the segment
*/
shmid_ds descriptor;
shmctl(d->my_shmid, IPC_STAT, &descriptor);
if(descriptor.shm_nattch != 2)// badness
// set pid and gets lock for it
d->my_pid = PID;
if(!d->GetLocks())
{
fprintf(stderr,"dfhack: %d : invalid no. of processes connected\n", (int) descriptor.shm_nattch);
fprintf(stderr,"detach: %d",shmdt(d->my_shm));
fprintf(stderr,"Couldn't get locks for PID %d'\n", PID);
shmdt(d->my_shm);
return;
}
/*
* Test bridge version, will also detect when we connect to something that doesn't respond
* Test bridge version, get PID, sync Yield
*/
bool bridgeOK;
if(!d->DF_TestBridgeVersion(bridgeOK))
if(!d->Aux_Core_Attach(bridgeOK,d->my_pid))
{
fprintf(stderr,"DF terminated during reading\n");
shmdt(d->my_shm);
// free locks
d->FreeLocks();
return;
}
if(!bridgeOK)
{
fprintf(stderr,"SHM bridge version mismatch\n");
shmdt(d->my_shm);
// free locks
d->FreeLocks();
return;
}
/*
* get the PID from DF
*/
if(d->DF_GetPID(d->my_pid))
// find the binary
sprintf(exe_link_name,"/proc/%d/exe", d->my_pid);
target_result = readlink(exe_link_name, target_name, sizeof(target_name)-1);
if (target_result == -1)
{
// find its binary
sprintf(exe_link_name,"/proc/%d/exe", d->my_pid);
target_result = readlink(exe_link_name, target_name, sizeof(target_name)-1);
if (target_result == -1)
{
perror("readlink");
return;
}
// make sure we have a null terminated string...
// 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);
perror("readlink");
shmdt(d->my_shm);
// free locks
d->FreeLocks();
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);
gcc_barrier
// 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
// free locks
d->FreeLocks();
}
bool SHMProcess::isSuspended()
@ -319,8 +455,8 @@ bool SHMProcess::suspend()
{
return true;
}
((shm_cmd *)d->my_shm)->pingpong = DFPP_SUSPEND;
if(!d->waitWhile(DFPP_SUSPEND))
D_SHMCMD = CORE_SUSPEND;
if(!waitWhile(CORE_SUSPEND))
{
return false;
}
@ -338,14 +474,14 @@ bool SHMProcess::asyncSuspend()
{
return true;
}
if(((shm_cmd *)d->my_shm)->pingpong == DFPP_SUSPENDED)
if(D_SHMCMD == CORE_SUSPENDED)
{
d->suspended = true;
return true;
}
else
{
((shm_cmd *)d->my_shm)->pingpong = DFPP_SUSPEND;
D_SHMCMD = CORE_SUSPEND;
return false;
}
}
@ -361,7 +497,7 @@ bool SHMProcess::resume()
return false;
if(!d->suspended)
return true;
((shm_cmd *)d->my_shm)->pingpong = DFPP_RUNNING;
D_SHMCMD = CORE_RUNNING;
d->suspended = false;
return true;
}
@ -372,9 +508,16 @@ bool SHMProcess::attach()
int status;
if(g_pProcess != 0)
{
cerr << "there's already a different process attached" << endl;
// FIXME: throw exception here - programmer error
cerr << "client is already attached to a process!" << endl;
return false;
}
if(!d->GetLocks())
{
cerr << "server is full or not really there!" << endl;
return false;
}
/*
* Attach the segment
*/
@ -389,10 +532,12 @@ bool SHMProcess::attach()
}
d->attached = false;
cerr << "unable to suspend" << endl;
// FIXME: detach sehment here
shmdt(d->my_shm);
d->FreeLocks();
return false;
}
cerr << "unable to attach" << endl;
d->FreeLocks();
return false;
}
@ -413,9 +558,11 @@ bool SHMProcess::detach()
d->suspended = false;
d->my_shm = 0;
g_pProcess = 0;
d->FreeLocks();
return true;
}
// fail if we can't detach
// FIXME: throw exception here??
perror("failed to detach shared segment");
return false;
}
@ -425,11 +572,11 @@ void SHMProcess::read (uint32_t src_address, uint32_t size, uint8_t *target_buff
// normal read under 1MB
if(size <= SHM_BODY)
{
((shm_read *)d->my_shm)->address = src_address;
((shm_read *)d->my_shm)->length = size;
D_SHMHDR->address = src_address;
D_SHMHDR->length = size;
gcc_barrier
((shm_read *)d->my_shm)->pingpong = DFPP_READ;
d->waitWhile(DFPP_READ);
D_SHMCMD = CORE_DFPP_READ;
waitWhile(CORE_DFPP_READ);
memcpy (target_buffer, d->my_shm + SHM_HEADER,size);
}
// a big read, we pull data over the shm in iterations
@ -440,11 +587,11 @@ void SHMProcess::read (uint32_t src_address, uint32_t size, uint8_t *target_buff
while (size)
{
// read to_read bytes from src_cursor
((shm_read *)d->my_shm)->address = src_address;
((shm_read *)d->my_shm)->length = to_read;
D_SHMHDR->address = src_address;
D_SHMHDR->length = to_read;
gcc_barrier
((shm_read *)d->my_shm)->pingpong = DFPP_READ;
d->waitWhile(DFPP_READ);
D_SHMCMD = CORE_DFPP_READ;
waitWhile(CORE_DFPP_READ);
memcpy (target_buffer, d->my_shm + SHM_HEADER,size);
// decrease size by bytes read
size -= to_read;
@ -459,55 +606,55 @@ void SHMProcess::read (uint32_t src_address, uint32_t size, uint8_t *target_buff
uint8_t SHMProcess::readByte (const uint32_t offset)
{
((shm_read_small *)d->my_shm)->address = offset;
D_SHMHDR->address = offset;
gcc_barrier
((shm_read_small *)d->my_shm)->pingpong = DFPP_READ_BYTE;
d->waitWhile(DFPP_READ_BYTE);
return ((shm_retval *)d->my_shm)->value;
D_SHMCMD = CORE_READ_BYTE;
waitWhile(CORE_READ_BYTE);
return D_SHMHDR->value;
}
void SHMProcess::readByte (const uint32_t offset, uint8_t &val )
{
((shm_read_small *)d->my_shm)->address = offset;
D_SHMHDR->address = offset;
gcc_barrier
((shm_read_small *)d->my_shm)->pingpong = DFPP_READ_BYTE;
d->waitWhile(DFPP_READ_BYTE);
val = ((shm_retval *)d->my_shm)->value;
D_SHMCMD = CORE_READ_BYTE;
waitWhile(CORE_READ_BYTE);
val = D_SHMHDR->value;
}
uint16_t SHMProcess::readWord (const uint32_t offset)
{
((shm_read_small *)d->my_shm)->address = offset;
D_SHMHDR->address = offset;
gcc_barrier
((shm_read_small *)d->my_shm)->pingpong = DFPP_READ_WORD;
d->waitWhile(DFPP_READ_WORD);
return ((shm_retval *)d->my_shm)->value;
D_SHMCMD = CORE_READ_WORD;
waitWhile(CORE_READ_WORD);
return D_SHMHDR->value;
}
void SHMProcess::readWord (const uint32_t offset, uint16_t &val)
{
((shm_read_small *)d->my_shm)->address = offset;
D_SHMHDR->address = offset;
gcc_barrier
((shm_read_small *)d->my_shm)->pingpong = DFPP_READ_WORD;
d->waitWhile(DFPP_READ_WORD);
val = ((shm_retval *)d->my_shm)->value;
D_SHMCMD = CORE_READ_WORD;
waitWhile(CORE_READ_WORD);
val = D_SHMHDR->value;
}
uint32_t SHMProcess::readDWord (const uint32_t offset)
{
((shm_read_small *)d->my_shm)->address = offset;
D_SHMHDR->address = offset;
gcc_barrier
((shm_read_small *)d->my_shm)->pingpong = DFPP_READ_DWORD;
d->waitWhile(DFPP_READ_DWORD);
return ((shm_retval *)d->my_shm)->value;
D_SHMCMD = CORE_READ_DWORD;
waitWhile(CORE_READ_DWORD);
return D_SHMHDR->value;
}
void SHMProcess::readDWord (const uint32_t offset, uint32_t &val)
{
((shm_read_small *)d->my_shm)->address = offset;
D_SHMHDR->address = offset;
gcc_barrier
((shm_read_small *)d->my_shm)->pingpong = DFPP_READ_DWORD;
d->waitWhile(DFPP_READ_DWORD);
val = ((shm_retval *)d->my_shm)->value;
D_SHMCMD = CORE_READ_DWORD;
waitWhile(CORE_READ_DWORD);
val = D_SHMHDR->value;
}
/*
@ -516,30 +663,30 @@ void SHMProcess::readDWord (const uint32_t offset, uint32_t &val)
void SHMProcess::writeDWord (uint32_t offset, uint32_t data)
{
((shm_write_small *)d->my_shm)->address = offset;
((shm_write_small *)d->my_shm)->value = data;
D_SHMHDR->address = offset;
D_SHMHDR->value = data;
gcc_barrier
((shm_write_small *)d->my_shm)->pingpong = DFPP_WRITE_DWORD;
d->waitWhile(DFPP_WRITE_DWORD);
D_SHMCMD = CORE_WRITE_DWORD;
waitWhile(CORE_WRITE_DWORD);
}
// using these is expensive.
void SHMProcess::writeWord (uint32_t offset, uint16_t data)
{
((shm_write_small *)d->my_shm)->address = offset;
((shm_write_small *)d->my_shm)->value = data;
D_SHMHDR->address = offset;
D_SHMHDR->value = data;
gcc_barrier
((shm_write_small *)d->my_shm)->pingpong = DFPP_WRITE_WORD;
d->waitWhile(DFPP_WRITE_WORD);
D_SHMCMD = CORE_WRITE_WORD;
waitWhile(CORE_WRITE_WORD);
}
void SHMProcess::writeByte (uint32_t offset, uint8_t data)
{
((shm_write_small *)d->my_shm)->address = offset;
((shm_write_small *)d->my_shm)->value = data;
D_SHMHDR->address = offset;
D_SHMHDR->value = data;
gcc_barrier
((shm_write_small *)d->my_shm)->pingpong = DFPP_WRITE_BYTE;
d->waitWhile(DFPP_WRITE_BYTE);
D_SHMCMD = CORE_WRITE_BYTE;
waitWhile(CORE_WRITE_BYTE);
}
void SHMProcess::write (uint32_t dst_address, uint32_t size, uint8_t *source_buffer)
@ -547,12 +694,12 @@ void SHMProcess::write (uint32_t dst_address, uint32_t size, uint8_t *source_buf
// normal write under 1MB
if(size <= SHM_BODY)
{
((shm_write *)d->my_shm)->address = dst_address;
((shm_write *)d->my_shm)->length = size;
D_SHMHDR->address = dst_address;
D_SHMHDR->length = size;
memcpy(d->my_shm+SHM_HEADER,source_buffer, size);
gcc_barrier
((shm_write *)d->my_shm)->pingpong = DFPP_WRITE;
d->waitWhile(DFPP_WRITE);
D_SHMCMD = CORE_WRITE;
waitWhile(CORE_WRITE);
}
// a big write, we push this over the shm in iterations
else
@ -562,12 +709,12 @@ void SHMProcess::write (uint32_t dst_address, uint32_t size, uint8_t *source_buf
while (size)
{
// write to_write bytes to dst_cursor
((shm_write *)d->my_shm)->address = dst_address;
((shm_write *)d->my_shm)->length = to_write;
D_SHMHDR->address = dst_address;
D_SHMHDR->length = to_write;
memcpy(d->my_shm+SHM_HEADER,source_buffer, to_write);
gcc_barrier
((shm_write *)d->my_shm)->pingpong = DFPP_WRITE;
d->waitWhile(DFPP_WRITE);
D_SHMCMD = CORE_WRITE;
waitWhile(CORE_WRITE);
// decrease size by bytes written
size -= to_write;
// move the cursors
@ -615,21 +762,21 @@ DfVector SHMProcess::readVector (uint32_t offset, uint32_t item_size)
const std::string SHMProcess::readSTLString(uint32_t offset)
{
((shm_read_small *)d->my_shm)->address = offset;
D_SHMHDR->address = offset;
full_barrier
((shm_read_small *)d->my_shm)->pingpong = DFPP_READ_STL_STRING;
d->waitWhile(DFPP_READ_STL_STRING);
D_SHMCMD = CORE_READ_STL_STRING;
waitWhile(CORE_READ_STL_STRING);
//int length = ((shm_retval *)d->my_shm)->value;
return(string( (char *)d->my_shm+SHM_HEADER));
}
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
((shm_read_small *)d->my_shm)->pingpong = DFPP_READ_STL_STRING;
d->waitWhile(DFPP_READ_STL_STRING);
size_t length = ((shm_retval *)d->my_shm)->value;
D_SHMCMD = CORE_READ_STL_STRING;
waitWhile(CORE_READ_STL_STRING);
size_t length = D_SHMHDR->value;
size_t fit = min(bufcapacity - 1, length);
strncpy(buffer,(char *)d->my_shm+SHM_HEADER,fit);
buffer[fit] = 0;
@ -638,11 +785,11 @@ size_t SHMProcess::readSTLString (uint32_t offset, char * buffer, size_t bufcapa
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
full_barrier
((shm_write_small *)d->my_shm)->pingpong = DFPP_WRITE_STL_STRING;
d->waitWhile(DFPP_WRITE_STL_STRING);
D_SHMCMD = CORE_WRITE_STL_STRING;
waitWhile(CORE_WRITE_STL_STRING);
}
string SHMProcess::readClassName (uint32_t vptr)
@ -653,4 +800,37 @@ string SHMProcess::readClassName (uint32_t vptr)
size_t start = raw.find_first_of("abcdefghijklmnopqrstuvwxyz");// trim numbers
size_t end = raw.length();
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 "../shmserver/shms.h"
#include "../shmserver/mod-core.h"
using namespace DFHack;
// a full memory barrier! better be safe than sorry.
@ -38,6 +39,7 @@ class SHMProcess::Private
attached = false;
suspended = false;
identified = false;
useYield = 0;
DFSVMutex = 0;
DFCLMutex = 0;
};
@ -52,13 +54,23 @@ class SHMProcess::Private
bool attached;
bool suspended;
bool identified;
bool useYield;
bool waitWhile (DF_PINGPONG state);
bool waitWhile (uint32_t state);
bool isValidSV();
bool DF_TestBridgeVersion(bool & ret);
bool DF_GetPID(uint32_t & ret);
bool Aux_Core_Attach(bool & versionOK, uint32_t & PID);
};
// 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?
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;
SCHED_YIELD // yield the CPU, valid only on single-core CPUs
while (((shm_cmd *)my_shm)->pingpong == state)
while (SHMCMD == state)
{
// yield the CPU, only on single-core CPUs
if(useYield)
{
SCHED_YIELD
}
if(cnt == 10000)
{
if(!isValidSV())// DF not there anymore?
{
full_barrier
((shm_cmd *)my_shm)->pingpong = DFPP_RUNNING;
attached = suspended = false;
ReleaseMutex(DFCLMutex);
UnmapViewOfFile(my_shm);
throw Error::SHMServerDisappeared();
return false;
}
else
@ -110,79 +131,84 @@ bool SHMProcess::Private::waitWhile (DF_PINGPONG state)
}
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;
cerr << "shm server error!" << endl;
assert (false);
return false;
}
return true;
}
bool SHMProcess::Private::DF_TestBridgeVersion(bool & ret)
uint32_t OS_getAffinity()
{
((shm_cmd *)my_shm)->pingpong = DFPP_VERSION;
full_barrier
if(!waitWhile(DFPP_VERSION))
return false;
full_barrier
((shm_cmd *)my_shm)->pingpong = DFPP_SUSPENDED;
ret =( ((shm_retval *)my_shm)->value == PINGPONG_VERSION );
return true;
HANDLE hProcess = GetCurrentProcess();
DWORD dwProcessAffinityMask, dwSystemAffinityMask;
GetProcessAffinityMask( hProcess, &dwProcessAffinityMask, &dwSystemAffinityMask );
return dwProcessAffinityMask;
}
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
if(!waitWhile(DFPP_PID))
SHMCMD = CORE_ATTACH;
if(!waitWhile(CORE_ATTACH))
return false;
full_barrier
((shm_cmd *)my_shm)->pingpong = DFPP_SUSPENDED;
ret = ((shm_retval *)my_shm)->value;
versionOK =( SHMDATA(coreattach)->sv_version == CORE_VERSION );
PID = SHMDATA(coreattach)->sv_PID;
useYield = SHMDATA(coreattach)->sv_useYield;
#ifdef DEBUG
if(useYield) cerr << "Using Yield!" << endl;
#endif
return true;
}
SHMProcess::SHMProcess(vector <memory_info *> & known_versions)
SHMProcess::SHMProcess(uint32_t PID, vector <memory_info *> & known_versions)
: d(new Private())
{
char svmutexname [256];
sprintf(svmutexname,"DFSVMutex-%d",PID);
char clmutexname [256];
sprintf(clmutexname,"DFCLMutex-%d",PID);
// get server and client mutex
d->DFSVMutex = OpenMutex(SYNCHRONIZE,false, "DFSVMutex");
d->DFSVMutex = OpenMutex(SYNCHRONIZE,false, svmutexname);
if(d->DFSVMutex == 0)
{
return;
}
d->DFCLMutex = OpenMutex(SYNCHRONIZE,false, "DFCLMutex");
d->DFCLMutex = OpenMutex(SYNCHRONIZE,false, clmutexname);
if(d->DFCLMutex == 0)
{
return;
}
d->my_pid = PID;
// attach the SHM
if(!attach())
{
return;
}
// All seems to be OK so far. Attached and connected to something that looks like DF
// Test bridge version, will also detect when we connect to something that doesn't respond
// Test bridge version, get PID, sync Yield
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");
UnmapViewOfFile(d->my_shm);
ReleaseMutex(d->DFCLMutex);
CloseHandle(d->DFSVMutex);
d->DFSVMutex = 0;
CloseHandle(d->DFCLMutex);
d->DFCLMutex = 0;
return;
error = 1;
}
if(!bridgeOK)
else if(!bridgeOK)
{
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);
ReleaseMutex(d->DFCLMutex);
CloseHandle(d->DFSVMutex);
@ -191,83 +217,78 @@ SHMProcess::SHMProcess(vector <memory_info *> & known_versions)
d->DFCLMutex = 0;
return;
}
/*
* get the PID from DF
*/
if(d->DF_GetPID(d->my_pid))
{
// try to identify the DF version
do // glorified goto
{
IMAGE_NT_HEADERS32 pe_header;
IMAGE_SECTION_HEADER sections[16];
HMODULE hmod = NULL;
DWORD junk;
HANDLE hProcess;
bool found = false;
d->identified = false;
// 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
// try to identify the DF version
do // glorified goto
{
IMAGE_NT_HEADERS32 pe_header;
IMAGE_SECTION_HEADER sections[16];
HMODULE hmod = NULL;
DWORD junk;
HANDLE hProcess;
bool found = false;
d->identified = false;
// open process, we only need the process open
hProcess = OpenProcess( PROCESS_ALL_ACCESS, FALSE, d->my_pid );
if (NULL == hProcess)
break;
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;
UnmapViewOfFile(d->my_shm);
d->my_shm = 0;
ReleaseMutex(d->DFCLMutex);
CloseHandle(d->DFSVMutex);
d->DFSVMutex = 0;
CloseHandle(d->DFCLMutex);
d->DFCLMutex = 0;
return;
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)
{
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
// 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;
return true;
}
((shm_cmd *)d->my_shm)->pingpong = DFPP_SUSPEND;
if(!d->waitWhile(DFPP_SUSPEND))
D_SHMCMD = CORE_SUSPEND;
if(!d->waitWhile(CORE_SUSPEND))
{
cerr << "couldn't suspend, DF not responding to commands" << endl;
return false;
@ -395,14 +416,14 @@ bool SHMProcess::asyncSuspend()
{
return true;
}
if(((shm_cmd *)d->my_shm)->pingpong == DFPP_SUSPENDED)
if(D_SHMCMD == CORE_SUSPENDED)
{
d->suspended = true;
return true;
}
else
{
((shm_cmd *)d->my_shm)->pingpong = DFPP_SUSPEND;
D_SHMCMD = CORE_SUSPEND;
return false;
}
}
@ -424,7 +445,7 @@ bool SHMProcess::resume()
cerr << "couldn't resume because of not being suspended" << endl;
return true;
}
((shm_cmd *)d->my_shm)->pingpong = DFPP_RUNNING;
D_SHMCMD = CORE_RUNNING;
d->suspended = false;
return true;
}
@ -454,8 +475,11 @@ bool SHMProcess::attach()
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
HANDLE shmHandle = OpenFileMapping(FILE_MAP_ALL_ACCESS,false,"DFShm");
HANDLE shmHandle = OpenFileMapping(FILE_MAP_ALL_ACCESS,false,shmname);
if(!shmHandle)
{
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
if(size <= SHM_BODY)
{
((shm_read *)d->my_shm)->address = src_address;
((shm_read *)d->my_shm)->length = size;
D_SHMHDR->address = src_address;
D_SHMHDR->length = size;
full_barrier
((shm_read *)d->my_shm)->pingpong = DFPP_READ;
d->waitWhile(DFPP_READ);
D_SHMCMD = CORE_DFPP_READ;
d->waitWhile(CORE_DFPP_READ);
memcpy (target_buffer, d->my_shm + SHM_HEADER,size);
}
// 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)
{
// read to_read bytes from src_cursor
((shm_read *)d->my_shm)->address = src_address;
((shm_read *)d->my_shm)->length = to_read;
D_SHMHDR->address = src_address;
D_SHMHDR->length = to_read;
full_barrier
((shm_read *)d->my_shm)->pingpong = DFPP_READ;
d->waitWhile(DFPP_READ);
D_SHMCMD = CORE_DFPP_READ;
d->waitWhile(CORE_DFPP_READ);
memcpy (target_buffer, d->my_shm + SHM_HEADER,size);
// decrease size by bytes 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)
{
((shm_read_small *)d->my_shm)->address = offset;
D_SHMHDR->address = offset;
full_barrier
((shm_read_small *)d->my_shm)->pingpong = DFPP_READ_BYTE;
d->waitWhile(DFPP_READ_BYTE);
return ((shm_retval *)d->my_shm)->value;
D_SHMCMD = CORE_READ_BYTE;
d->waitWhile(CORE_READ_BYTE);
return D_SHMHDR->value;
}
void SHMProcess::readByte (const uint32_t offset, uint8_t &val )
{
((shm_read_small *)d->my_shm)->address = offset;
D_SHMHDR->address = offset;
full_barrier
((shm_read_small *)d->my_shm)->pingpong = DFPP_READ_BYTE;
d->waitWhile(DFPP_READ_BYTE);
val = ((shm_retval *)d->my_shm)->value;
D_SHMCMD = CORE_READ_BYTE;
d->waitWhile(CORE_READ_BYTE);
val = D_SHMHDR->value;
}
uint16_t SHMProcess::readWord (const uint32_t offset)
{
((shm_read_small *)d->my_shm)->address = offset;
D_SHMHDR->address = offset;
full_barrier
((shm_read_small *)d->my_shm)->pingpong = DFPP_READ_WORD;
d->waitWhile(DFPP_READ_WORD);
return ((shm_retval *)d->my_shm)->value;
D_SHMCMD = CORE_READ_WORD;
d->waitWhile(CORE_READ_WORD);
return D_SHMHDR->value;
}
void SHMProcess::readWord (const uint32_t offset, uint16_t &val)
{
((shm_read_small *)d->my_shm)->address = offset;
D_SHMHDR->address = offset;
full_barrier
((shm_read_small *)d->my_shm)->pingpong = DFPP_READ_WORD;
d->waitWhile(DFPP_READ_WORD);
val = ((shm_retval *)d->my_shm)->value;
D_SHMCMD = CORE_READ_WORD;
d->waitWhile(CORE_READ_WORD);
val = D_SHMHDR->value;
}
uint32_t SHMProcess::readDWord (const uint32_t offset)
{
((shm_read_small *)d->my_shm)->address = offset;
D_SHMHDR->address = offset;
full_barrier
((shm_read_small *)d->my_shm)->pingpong = DFPP_READ_DWORD;
d->waitWhile(DFPP_READ_DWORD);
return ((shm_retval *)d->my_shm)->value;
D_SHMCMD = CORE_READ_DWORD;
d->waitWhile(CORE_READ_DWORD);
return D_SHMHDR->value;
}
void SHMProcess::readDWord (const uint32_t offset, uint32_t &val)
{
((shm_read_small *)d->my_shm)->address = offset;
D_SHMHDR->address = offset;
full_barrier
((shm_read_small *)d->my_shm)->pingpong = DFPP_READ_DWORD;
d->waitWhile(DFPP_READ_DWORD);
val = ((shm_retval *)d->my_shm)->value;
D_SHMCMD = CORE_READ_DWORD;
d->waitWhile(CORE_READ_DWORD);
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)
{
((shm_write_small *)d->my_shm)->address = offset;
((shm_write_small *)d->my_shm)->value = data;
D_SHMHDR->address = offset;
D_SHMHDR->value = data;
full_barrier
((shm_write_small *)d->my_shm)->pingpong = DFPP_WRITE_DWORD;
d->waitWhile(DFPP_WRITE_DWORD);
D_SHMCMD = CORE_WRITE_DWORD;
d->waitWhile(CORE_WRITE_DWORD);
}
// using these is expensive.
void SHMProcess::writeWord (uint32_t offset, uint16_t data)
{
((shm_write_small *)d->my_shm)->address = offset;
((shm_write_small *)d->my_shm)->value = data;
D_SHMHDR->address = offset;
D_SHMHDR->value = data;
full_barrier
((shm_write_small *)d->my_shm)->pingpong = DFPP_WRITE_WORD;
d->waitWhile(DFPP_WRITE_WORD);
D_SHMCMD = CORE_WRITE_WORD;
d->waitWhile(CORE_WRITE_WORD);
}
void SHMProcess::writeByte (uint32_t offset, uint8_t data)
{
((shm_write_small *)d->my_shm)->address = offset;
((shm_write_small *)d->my_shm)->value = data;
D_SHMHDR->address = offset;
D_SHMHDR->value = data;
full_barrier
((shm_write_small *)d->my_shm)->pingpong = DFPP_WRITE_BYTE;
d->waitWhile(DFPP_WRITE_BYTE);
D_SHMCMD = CORE_WRITE_BYTE;
d->waitWhile(CORE_WRITE_BYTE);
}
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
if(size <= SHM_BODY)
{
((shm_write *)d->my_shm)->address = dst_address;
((shm_write *)d->my_shm)->length = size;
D_SHMHDR->address = dst_address;
D_SHMHDR->length = size;
memcpy(d->my_shm+SHM_HEADER,source_buffer, size);
full_barrier
((shm_write *)d->my_shm)->pingpong = DFPP_WRITE;
d->waitWhile(DFPP_WRITE);
D_SHMCMD = CORE_WRITE;
d->waitWhile(CORE_WRITE);
}
// a big write, we push this over the shm in iterations
else
@ -636,12 +660,12 @@ void SHMProcess::write (uint32_t dst_address, uint32_t size, uint8_t *source_buf
while (size)
{
// write to_write bytes to dst_cursor
((shm_write *)d->my_shm)->address = dst_address;
((shm_write *)d->my_shm)->length = to_write;
D_SHMHDR->address = dst_address;
D_SHMHDR->length = to_write;
memcpy(d->my_shm+SHM_HEADER,source_buffer, to_write);
full_barrier
((shm_write *)d->my_shm)->pingpong = DFPP_WRITE;
d->waitWhile(DFPP_WRITE);
D_SHMCMD = CORE_WRITE;
d->waitWhile(CORE_WRITE);
// decrease size by bytes written
size -= to_write;
// 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)
{
//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
((shm_read_small *)d->my_shm)->pingpong = DFPP_READ_STL_STRING;
d->waitWhile(DFPP_READ_STL_STRING);
int length = ((shm_retval *)d->my_shm)->value;
D_SHMCMD = CORE_READ_STL_STRING;
d->waitWhile(CORE_READ_STL_STRING);
int length = D_SHMHDR->value;
// char temp_c[256];
// strncpy(temp_c, d->my_shm+SHM_HEADER,length+1); // length + 1 for the null terminator
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)
{
//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
((shm_read_small *)d->my_shm)->pingpong = DFPP_READ_STL_STRING;
d->waitWhile(DFPP_READ_STL_STRING);
size_t length = ((shm_retval *)d->my_shm)->value;
D_SHMCMD = CORE_READ_STL_STRING;
d->waitWhile(CORE_READ_STL_STRING);
size_t length = D_SHMHDR->value;
size_t real = min(length, bufcapacity - 1);
strncpy(buffer, d->my_shm+SHM_HEADER,real); // length + 1 for the null terminator
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)
{
((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
full_barrier
((shm_write_small *)d->my_shm)->pingpong = DFPP_WRITE_STL_STRING;
d->waitWhile(DFPP_WRITE_STL_STRING);
D_SHMCMD = CORE_WRITE_STL_STRING;
d->waitWhile(CORE_WRITE_STL_STRING);
}
string SHMProcess::readClassName (uint32_t vptr)
@ -732,4 +756,23 @@ string SHMProcess::readClassName (uint32_t vptr)
string raw = readCString(typeinfo + 0xC); // skips the .?AV
raw.resize(raw.length() - 4);// trim st@@ from end
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)
{
CloseHandle(hProcess);
cout << "EnumProcessModules fail'd" << endl;
// cout << "EnumProcessModules fail'd" << endl;
return; //if enumprocessModules fails, give up
}

@ -119,6 +119,12 @@ namespace DFHack
virtual DFWindow * getWindow() = 0;
// get the DF Process ID
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
@ -171,6 +177,12 @@ namespace DFHack
memory_info *getDescriptor();
DFWindow * getWindow();
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
@ -181,7 +193,7 @@ namespace DFHack
Private * const d;
public:
SHMProcess(vector <memory_info *> & known_versions);
SHMProcess(uint32_t PID, vector <memory_info *> & known_versions);
~SHMProcess();
// Set up stuff so we can read memory
bool attach();
@ -224,6 +236,12 @@ namespace DFHack
memory_info *getDescriptor();
DFWindow * getWindow();
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
@ -277,6 +295,12 @@ namespace DFHack
memory_info *getDescriptor();
DFWindow * getWindow();
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
}

@ -46,19 +46,6 @@ bool ProcessEnumerator::findProcessess()
{
DIR *dir_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
dir_p = opendir("/proc/");
// Reading /proc/ entries
@ -69,6 +56,16 @@ bool ProcessEnumerator::findProcessess()
{
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);
if(p2->isIdentified())
{
@ -89,6 +86,7 @@ bool ProcessEnumerator::findProcessess()
{
delete p3;
}
}
closedir(dir_p);
// return value depends on if we found some DF processes

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

@ -484,14 +484,17 @@ struct t_trait
CREATURE
*/
struct t_lastname
//#pragma pack(push,4)
struct t_name
{
int names[7];
};
struct t_squadname
{
int names[6];
char first_name[128];
char nickname[128];
int32_t words[7];
uint16_t parts_of_speech[7];
uint32_t language;
bool has_name;
};
struct t_skill
{
uint16_t id;
@ -511,6 +514,8 @@ struct t_like
t_matglossPair material;
bool active;
};
//#pragma pack(pop)
#define NUM_CREATURE_TRAITS 30
#define NUM_CREATURE_LABORS 102
struct t_creature
@ -522,10 +527,9 @@ struct t_creature
uint32_t type;
t_creaturflags1 flags1;
t_creaturflags2 flags2;
char first_name [128];
char nick_name [128];
t_lastname last_name;
t_squadname squad_name;
t_name name;
t_name squad_name;
t_name artifact_name;
uint8_t profession;
char custom_profession[128];
// enabled labors
@ -541,6 +545,7 @@ struct t_creature
uint8_t numLikes;
t_like likes[32];
t_job current_job;
uint16_t mood;
uint32_t happiness;
uint32_t id;
uint32_t agility;
@ -764,6 +769,17 @@ union t_occupancy
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
{
int32_t type;
@ -795,7 +811,7 @@ struct t_hotkey
struct t_settlement
{
uint32_t origin;
int32_t name[2];
t_name name;
int16_t world_x;
int16_t world_y;
int16_t local_x1;

@ -196,12 +196,10 @@ namespace DFHack
bool getItemIndexesInBox(std::vector<uint32_t> &indexes,
const uint16_t x1, const uint16_t y1, const uint16_t z1,
const uint16_t x2, const uint16_t y2, const uint16_t z2);
bool InitReadNameTables (std::map< std::string, std::vector<std::string> > & OUTPUT);
bool InitReadNameTables (std::vector< std::vector<std::string> > & translations , std::vector< std::vector<std::string> > & foreign_languages);
void FinishReadNameTables();
std::string TranslateName(const t_lastname & last, const std::map< std::string, std::vector< std::string > > &nameTable,const std::string & language="GENERIC");
std::string TranslateName(const t_squadname & squad, const std::map< std::string, std::vector< std::string > > &nameTable,const std::string & language="GENERIC");
std::string TranslateName (const int names[], int size, const std::map<std::string, std::vector<std::string> > &nameTable, const std::string & language="GENERIC");
std::string TranslateName(const t_name & name,const std::vector< std::vector<std::string> > & translations ,const std::vector< std::vector<std::string> > & foreign_languages, bool inEnglish=true);
void WriteLabors(const uint32_t index, uint8_t labors[NUM_CREATURE_LABORS]);

@ -789,9 +789,7 @@
<Offset name="biome_stuffs">0x1D64</Offset>
<!-- creature offsets -->
<Offset name="creature_first_name">0x00</Offset>
<Offset name="creature_nick_name">0x1C</Offset>
<Offset name="creature_last_name">0x38</Offset>
<Offset name="creature_name">0x00</Offset>
<Offset name="creature_custom_profession">0x6c</Offset>
<Offset name="creature_profession">0x88</Offset>
<Offset name="creature_race">0x8C</Offset>
@ -1159,15 +1157,23 @@
<Offset name="word_table">0x54</Offset>
<!-- name struct -->
<Offset name="name_firstname">0x0</Offset>
<Offset name="name_nickname">0x1C</Offset>
<Offset name="name_words">0x38</Offset>
<HexValue name="sizeof_string">0x1C</HexValue> <!-- TEST! Missing in 40d! -->
<!-- creature offsets -->
<Offset name="creature_flags1">0xFC</Offset>
<Offset name="creature_flags2">0x100</Offset>
<Offset name="creature_sex">0x10A</Offset>
<Offset name="creature_id">0x10C</Offset>
<Offset name="creature_squad_name">0x1D8</Offset>
<Offset name="creature_squad_name">0x198</Offset>
<Offset name="creature_mood">0x238</Offset>
<Offset name="creature_squad_leader_id">0x268</Offset>
<Offset name="creature_money">0x2F8</Offset>
<Offset name="creature_current_job">0x314</Offset>
<Offset name="creature_artifact_name">0x484</Offset>
<Offset name="creature_strength">0x4F0</Offset>
<Offset name="creature_agility">0x4F4</Offset>
<Offset name="creature_toughness">0x4F8</Offset>
@ -1176,7 +1182,7 @@
<Offset name="creature_labors">0x544</Offset>
<Offset name="creature_happiness">0x610</Offset>
<Offset name="creature_traits">0x700</Offset>
<!-- tree and shrub offsets -->
<Offset name="tree_desc_offset">0x70</Offset>
@ -1210,7 +1216,7 @@
<Offset name="hotkey_mode">0x1C</Offset>
<Offset name="hotkey_xyz">0x20</Offset>
<Offset name="settlement_name">0x38</Offset>
<Offset name="settlement_name">0x0</Offset>
<Offset name="settlement_world_xy">0x7a</Offset>
<Offset name="settlement_local_xy">0x100</Offset>
@ -1551,14 +1557,18 @@
<Address name="z_count">0x0935595c</Address>
<Offset name="word_table">0x1C</Offset>
<!-- name struct -->
<Offset name="name_firstname">0x0</Offset>
<Offset name="name_nickname">0x4</Offset>
<Offset name="name_words">0x8</Offset>
<HexValue name="sizeof_string">0x4</HexValue>
<!-- job object offsets -->
<Offset name="current_job_id">0x08</Offset>
<!-- creature offsets -->
<Offset name="creature_first_name">0x00</Offset>
<Offset name="creature_nick_name">0x04</Offset>
<Offset name="creature_last_name">0x08</Offset>
<Offset name="creature_name">0x00</Offset>
<Offset name="creature_position">0x4C</Offset>
<Offset name="creature_race">0x44</Offset>
<Offset name="creature_flags1">0x90</Offset>
@ -1618,7 +1628,7 @@
<Offset name="hotkey_xyz">0x8</Offset>
<HexValue name="hotkey_size">0x14</HexValue>
<Offset name="settlement_name">0x08</Offset>
<Offset name="settlement_name">0x00</Offset>
<Offset name="settlement_world_xy">0x4a</Offset>
<Offset name="settlement_local_xy">0x94</Offset>

@ -2,10 +2,13 @@
SET(PROJECT_HDRS
shms.h
mod-core.h
mod-maps.h
)
SET(PROJECT_SRCS
shms-proto.cpp
mod-core.cpp
mod-maps.cpp
)
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})
IF(UNIX)
add_definitions(-DLINUX_BUILD)
SET(PROJECT_LIBS rt)
SET(CMAKE_CXX_FLAGS "-fvisibility=hidden")
ADD_LIBRARY(dfconnect SHARED ${PROJECT_SRCS})
TARGET_LINK_LIBRARIES(dfconnect ${PROJECT_LIBS})
ELSE(UNIX)
# SET(PROJECT_LIBS psapi)
ADD_LIBRARY(SDL SHARED ${PROJECT_SRCS})
TARGET_LINK_LIBRARIES(SDL ${PROJECT_LIBS})
ENDIF(UNIX)
IF(CMAKE_SIZEOF_VOID_P EQUAL 4)
IF(UNIX)
add_definitions(-DLINUX_BUILD)
SET(PROJECT_LIBS rt)
SET(CMAKE_CXX_FLAGS "-fvisibility=hidden")
ADD_LIBRARY(dfconnect SHARED ${PROJECT_SRCS})
TARGET_LINK_LIBRARIES(dfconnect ${PROJECT_LIBS})
ELSE(UNIX)
# SET(PROJECT_LIBS psapi)
ADD_LIBRARY(SDL SHARED ${PROJECT_SRCS})
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

@ -33,13 +33,14 @@ distribution.
#include <sys/shm.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <vector>
#include <string>
#include "shms.h"
#include <sys/time.h>
#include <time.h>
#include <linux/futex.h>
#include <sys/syscall.h>
#include <signal.h>
#include "mod-core.h"
#include <sched.h>
#define DFhackCExport extern "C" __attribute__ ((visibility("default")))
@ -50,10 +51,14 @@ char *shm = 0;
int shmid = 0;
bool inited = 0;
int fd_svlock = 0;
int fd_cllock = 0;
/*******************************************************************************
* SHM part starts here *
*******************************************************************************/
/*
// FIXME: add error checking?
bool isValidSHM()
{
@ -62,11 +67,39 @@ bool isValidSHM()
//fprintf(stderr,"ID %d, attached: %d\n",shmid, descriptor.shm_nattch);
return (descriptor.shm_nattch == 2);
}
uint32_t getPID()
*/
// is the other side still there?
bool isValidSHM()
{
// try if CL lock file is free
int result = lockf(fd_cllock,F_TEST,0);
/*
F_TEST: Test the lock:
return 0 if the specified section is unlocked or locked by this process;
return -1, set errno to EAGAIN (EACCES on some other systems), if another process holds a lock.
*/
// if nobody holds the lock, the SHM isn't valid. file locks are unlocked when the owner closes or crashes.
if(result == 0) return false;
return true;
}
uint32_t OS_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 )
{
// check that we do this only once per process
@ -76,9 +109,26 @@ void SHM_Init ( void )
return;
}
inited = true;
char name[256];
char name2[256];
// name for the segment
key_t key = 123466;
// make folder structure for our lock files
sprintf(name, "/tmp/DFHack/%d",OS_getPID());
mode_t createmode = S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH;
mkdir("/tmp/DFHack", createmode);
mkdir(name, createmode);
// create and lock the server lock file
sprintf(name2, "%s/SVlock",name);
fd_svlock = open(name2,O_WRONLY | O_CREAT, createmode);
lockf( fd_svlock, F_LOCK, 0 );
// create the client lock file
sprintf(name2, "%s/CLlock",name);
fd_cllock = open(name2,O_WRONLY | O_CREAT, createmode);
// name for the segment, an accident waiting to happen
key_t key = SHM_KEY + OS_getPID();
// find previous segment, check if it's used by some processes.
// if it isn't, kill it with fire
@ -109,13 +159,15 @@ void SHM_Init ( void )
}
full_barrier
// 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 )
{
if(inited && !errorstate)
{
KillModules();
shmid_ds descriptor;
shmctl(shmid, IPC_STAT, &descriptor);
shmdt(shm);
@ -124,6 +176,23 @@ void SHM_Destroy ( void )
shmctl(shmid, IPC_STAT, &descriptor);
}
shmctl(shmid,IPC_RMID,NULL);
// unlock and close server lock, close client lock
lockf(fd_svlock,F_ULOCK,0);
close(fd_svlock);
close(fd_cllock);
fd_svlock = 0;
fd_cllock = 0;
// destroy lock files
char name[256];
char name2[256];
sprintf(name, "/tmp/DFHack/%d",OS_getPID());
sprintf(name2, "%s/SVlock",name);
unlink(name2);
sprintf(name2, "%s/CLlock",name);
unlink(name2);
rmdir(name);
fprintf(stderr,"dfhack: destroyed shared segment.\n");
inited = false;
}
@ -144,7 +213,7 @@ DFhackCExport void SDL_GL_SwapBuffers(void)
{
if(_SDL_GL_SwapBuffers)
{
if(!errorstate && ((shm_cmd *)shm)->pingpong != DFPP_RUNNING)
if(!errorstate && ((shm_cmd *)shm)->pingpong != CORE_RUNNING)
{
SHM_Act();
}
@ -158,7 +227,7 @@ DFhackCExport int SDL_Flip(void * some_ptr)
{
if(_SDL_Flip)
{
if(!errorstate && ((shm_cmd *)shm)->pingpong != DFPP_RUNNING)
if(!errorstate && ((shm_cmd *)shm)->pingpong != CORE_RUNNING)
{
SHM_Act();
}
@ -216,7 +285,7 @@ DFhackCExport int refresh (void)
{
if(_refresh)
{
if(!errorstate && ((shm_cmd *)shm)->pingpong != DFPP_RUNNING)
if(!errorstate && ((shm_cmd *)shm)->pingpong != CORE_RUNNING)
{
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)
#include "../library/integers.h"
#include <vector>
#include <string>
#include "shms.h"
#include "mod-core.h"
#include <stdio.h>
int errorstate = 0;
char *shm = 0;
@ -53,21 +56,28 @@ void SHM_Init ( void )
}
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
DFSVMutex = CreateMutex( 0, 1, "DFSVMutex");
DFSVMutex = CreateMutex( 0, 1, svmutexname);
if(DFSVMutex == 0)
{
DFSVMutex = OpenMutex(SYNCHRONIZE,false, "DFSVMutex");
DFSVMutex = OpenMutex(SYNCHRONIZE,false, svmutexname);
if(DFSVMutex == 0)
{
errorstate = 1;
return;
}
}
DFCLMutex = CreateMutex( 0, 0, "DFCLMutex");
DFCLMutex = CreateMutex( 0, 0, clmutexname);
if(DFCLMutex == 0)
{
DFCLMutex = OpenMutex(SYNCHRONIZE,false, "DFCLMutex");
DFCLMutex = OpenMutex(SYNCHRONIZE,false, clmutexname);
if(DFCLMutex == 0)
{
CloseHandle(DFSVMutex);
@ -107,7 +117,7 @@ void SHM_Init ( void )
}
// 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(GetLastError() == ERROR_ALREADY_EXISTS)
{
@ -131,8 +141,7 @@ void SHM_Init ( void )
shm = (char *) MapViewOfFile(shmHandle,FILE_MAP_ALL_ACCESS, 0,0, SHM_SIZE);
if(shm)
{
((shm_cmd *)shm)->pingpong = DFPP_RUNNING;
//MessageBox(0,"Sucessfully mapped SHM","FUN", MB_OK);
((shm_cmd *)shm)->pingpong = CORE_RUNNING;
}
else
{
@ -142,22 +151,35 @@ void SHM_Init ( void )
CloseHandle(DFSVMutex);
CloseHandle(DFCLMutex);
}
InitModules();
}
void SHM_Destroy ( void )
{
if(errorstate)
return;
KillModules();
ReleaseMutex(DFSVMutex);
CloseHandle(DFSVMutex);
CloseHandle(DFCLMutex);
}
uint32_t getPID()
uint32_t OS_getPID()
{
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?
bool isValidSHM()
{
@ -665,7 +687,7 @@ DFhackCExport void SDL_Quit(void)
static void (*_SDL_GL_SwapBuffers)(void) = 0;
DFhackCExport void SDL_GL_SwapBuffers(void)
{
if(!errorstate && ((shm_cmd *)shm)->pingpong != DFPP_RUNNING)
if(!errorstate && ((shm_cmd *)shm)->pingpong != CORE_RUNNING)
{
SHM_Act();
}
@ -678,7 +700,7 @@ DFhackCExport int SDL_Flip(void * some_ptr)
{
if(_SDL_Flip)
{
if(!errorstate && ((shm_cmd *)shm)->pingpong != DFPP_RUNNING)
if(!errorstate && ((shm_cmd *)shm)->pingpong != CORE_RUNNING)
{
SHM_Act();
}

@ -1,10 +1,9 @@
#ifndef DFCONNECT_H
#define DFCONNECT_H
#define PINGPONG_VERSION 2
#define SHM_KEY 123466
#define SHM_HEADER 1024
#define SHM_BODY 1024*1024
#define SHM_HEADER 1024 // 1kB reserved for a header
#define SHM_BODY 1024*1024 // 1MB reserved for bulk data transfer
#define SHM_SIZE SHM_HEADER+SHM_BODY
@ -12,16 +11,14 @@
#ifdef LINUX_BUILD
// a full memory barrier! better be safe than sorry.
#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 usleep(0); // extremely slow
// #define SCHED_YIELD // works only on multi-core
#define SCHED_YIELD sched_yield(); // a requirement for single-core
#else
// we need windows.h for Sleep()
#define _WIN32_WINNT 0x0501 // needed for INPUT struct
#define WINVER 0x0501 // OpenThread(), PSAPI, Toolhelp32
#define WIN32_LEAN_AND_MEAN
#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
#ifdef __MINGW32__
#define full_barrier asm volatile("" ::: "memory");
@ -32,124 +29,76 @@
#endif
#endif
/*
* 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
enum DFPP_CmdType
{
SHM_OK, // all OK
SHM_CANT_GET_SHM, // getting the SHM ID failed for some reason
SHM_CANT_ATTACH, // we can't attach the shm for some reason
SHM_SECOND_DF // we are a second DF process, can't use SHM at all
CANCELLATION, // we should jump out of the Act()
CLIENT_WAIT, // we are waiting for the client
FUNCTION, // we call a function as a result of the command
};
enum DF_PINGPONG
struct DFPP_command
{
DFPP_RUNNING = 0, // no command, normal server execution
DFPP_VERSION, // protocol version query
DFPP_RET_VERSION, // return the protocol version
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
void (*_function)(void *);
DFPP_CmdType type:32; // force the enum to 32 bits for compatibility reasons
std::string name;
uint32_t nextState;
};
enum DF_ERROR
struct DFPP_module
{
DFEE_INVALID_COMMAND,
DFEE_BUFFER_OVERFLOW
DFPP_module()
{
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
{
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
typedef union
{
struct
{
volatile uint16_t command;
volatile uint16_t module;
} parts;
volatile uint32_t pingpong;
uint32_t address;
} shm_read_small;
typedef struct
{
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;
inline void set(uint16_t module, uint16_t command)
{
pingpong = module + command << 16;
}
} shm_cmd;
void SHM_Act (void);
void InitModules (void);
void KillModules (void);
bool isValidSHM();
uint32_t getPID();
uint32_t OS_getPID();
DFPP_module InitMaps(void);
uint32_t OS_getAffinity(); // limited to 32 processors. Silly, eh?
#endif