Another try at locking

develop
Petr Mrázek 2010-03-12 00:13:50 +01:00
parent f72bb0373d
commit 9d503515dd
12 changed files with 599 additions and 370 deletions

@ -221,6 +221,61 @@ namespace DFHack
return "The server process has disappeared"; return "The server process has disappeared";
} }
}; };
class DFHACK_EXPORT SHMLockingError : public std::exception
{
public:
SHMLockingError(const char* _type) : type(_type) {}
virtual ~SHMLockingError() throw(){};
std::string type;
virtual const char* what() const throw()
{
std::stringstream s;
s << "SHM locking error: " << type;
return s.str().c_str();
}
};
class DFHACK_EXPORT SHMAccessDenied : public std::exception
{
public:
SHMAccessDenied() {}
virtual ~SHMAccessDenied() throw(){};
std::string type;
virtual const char* what() const throw()
{
return "SHM ACCESS DENIED";
}
};
class DFHACK_EXPORT SHMVersionMismatch : public std::exception
{
public:
SHMVersionMismatch() {}
virtual ~SHMVersionMismatch() throw(){};
std::string type;
virtual const char* what() const throw()
{
return "SHM VERSION MISMATCH";
}
};
class DFHACK_EXPORT SHMAttachFailure : public std::exception
{
public:
SHMAttachFailure() {}
virtual ~SHMAttachFailure() throw(){};
std::string type;
virtual const char* what() const throw()
{
return "SHM ATTACH FAILURE";
}
};
} }
} }

@ -190,7 +190,7 @@ API::~API()
delete d; delete d;
} }
#define SHMCMD ((shm_cmd *)d->shm_start)->pingpong #define SHMCMD(num) ((shm_cmd *)d->shm_start)[num]->pingpong
#define SHMHDR ((shm_core_hdr *)d->shm_start) #define SHMHDR ((shm_core_hdr *)d->shm_start)
#define SHMMAPSHDR ((Maps::shm_maps_hdr *)d->shm_start) #define SHMMAPSHDR ((Maps::shm_maps_hdr *)d->shm_start)
#define SHMDATA(type) ((type *)(d->shm_start + SHM_HEADER)) #define SHMDATA(type) ((type *)(d->shm_start + SHM_HEADER))
@ -243,8 +243,7 @@ bool API::InitMap()
off->z_count_offset = z_count_offset; off->z_count_offset = z_count_offset;
full_barrier full_barrier
const uint32_t cmd = Maps::MAP_INIT + d->maps_module << 16; const uint32_t cmd = Maps::MAP_INIT + d->maps_module << 16;
SHMCMD = cmd; g_pProcess->SetAndWait(cmd);
g_pProcess->waitWhile(cmd);
//cerr << "Map acceleration enabled!" << endl; //cerr << "Map acceleration enabled!" << endl;
} }
@ -324,13 +323,8 @@ bool API::ReadBlock40d(uint32_t x, uint32_t y, uint32_t z, mapblock40d * buffer)
SHMMAPSHDR->y = y; SHMMAPSHDR->y = y;
SHMMAPSHDR->z = z; SHMMAPSHDR->z = z;
volatile uint32_t cmd = Maps::MAP_READ_BLOCK_BY_COORDS + (d->maps_module << 16); volatile uint32_t cmd = Maps::MAP_READ_BLOCK_BY_COORDS + (d->maps_module << 16);
full_barrier if(!g_pProcess->SetAndWait(cmd))
SHMCMD = cmd;
full_barrier
if(!g_pProcess->waitWhile(cmd))
{
return false; return false;
}
memcpy(buffer,SHMDATA(mapblock40d),sizeof(mapblock40d)); memcpy(buffer,SHMDATA(mapblock40d),sizeof(mapblock40d));
return true; return true;
} }

@ -43,27 +43,35 @@ class SHMProcess::Private
public: public:
Private() Private()
{ {
my_descriptor = NULL; memdescriptor = NULL;
my_pid = 0; process_ID = 0;
my_shm = 0; shm_addr = 0;
my_shmid = -1; //shm_addr_with_cl_idx = 0;
my_window = NULL; shm_ID = -1;
window = NULL;
attached = false; attached = false;
suspended = false; suspended = false;
identified = false; identified = false;
useYield = false; useYield = false;
my_SVfileLock = -1; server_lock = -1;
my_CLfileLock = -1; client_lock = -1;
suspend_lock = -1;
attachmentIdx = 0;
locked = false;
}; };
~Private(){}; ~Private(){};
memory_info * my_descriptor; memory_info * memdescriptor;
DFWindow * my_window; DFWindow * window;
pid_t my_pid; pid_t process_ID;
char *my_shm; char *shm_addr;
int my_shmid; int shm_ID;
Process* q; Process* q;
int my_SVfileLock; int server_lock;
int my_CLfileLock; int client_lock;
int suspend_lock;
int attachmentIdx;
bool locked;
bool attached; bool attached;
bool suspended; bool suspended;
@ -73,60 +81,36 @@ class SHMProcess::Private
bool validate(char* exe_file, uint32_t pid, std::vector< memory_info* >& known_versions); bool validate(char* exe_file, uint32_t pid, std::vector< memory_info* >& known_versions);
bool Aux_Core_Attach(bool & versionOK, pid_t & PID); bool Aux_Core_Attach(bool & versionOK, pid_t & PID);
bool waitWhile (uint32_t state); //bool waitWhile (uint32_t state);
bool SetAndWait (uint32_t state);
bool GetLocks(); bool GetLocks();
bool AreLocksOk(); bool AreLocksOk();
void FreeLocks(); void FreeLocks();
}; };
// some helpful macros to keep the code bloat in check #define SHMCMD ( (uint32_t *) shm_addr)[attachmentIdx]
#define SHMCMD ((shm_cmd *)my_shm)->pingpong #define D_SHMCMD ( (uint32_t *) (d->shm_addr))[d->attachmentIdx]
#define D_SHMCMD ((shm_cmd *)d->my_shm)->pingpong
#define SHMHDR ((shm_core_hdr *)my_shm) #define SHMHDR ((shm_core_hdr *)shm_addr)
#define D_SHMHDR ((shm_core_hdr *)d->my_shm) #define D_SHMHDR ((shm_core_hdr *)(d->shm_addr))
#define SHMDATA(type) ((type *)(my_shm + SHM_HEADER)) #define SHMDATA(type) ((type *)(shm_addr + SHM_HEADER))
#define D_SHMDATA(type) ((type *)(d->my_shm + SHM_HEADER)) #define D_SHMDATA(type) ((type *)(d->shm_addr + SHM_HEADER))
/* bool SHMProcess::Private::SetAndWait (uint32_t state)
Yeah. with no way to synchronize things (locks are slow, the OS doesn't give us enough control over scheduling)
we end up with this silly thing
*/
bool SHMProcess::Private::waitWhile (uint32_t state)
{ {
uint32_t cnt = 0; uint32_t cnt = 0;
struct shmid_ds descriptor; if(!locked) return false;
SHMCMD = state;
while (SHMCMD == state) while (SHMCMD == state)
{ {
if(cnt == 10000)// check if the other process is still there if(cnt == 10000)// check if the other process is still there, don't hammer the kernel too much.
{ {
/*
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
{
cnt = 0;
}
*/
if(!AreLocksOk()) if(!AreLocksOk())
{ {
//detach the shared memory //detach the shared memory
shmdt(my_shm); shmdt(shm_addr);
attached = suspended = false; attached = suspended = identified = false;
// we aren't the current process anymore // we aren't the current process anymore
g_pProcess = NULL; g_pProcess = NULL;
FreeLocks(); FreeLocks();
@ -145,12 +129,9 @@ bool SHMProcess::Private::waitWhile (uint32_t state)
} }
cnt++; cnt++;
} }
// server returned a generic error
if(SHMCMD == CORE_ERROR) if(SHMCMD == CORE_ERROR)
{ {
SHMCMD = CORE_RUNNING;
attached = suspended = false;
cerr << "shm server error!" << endl;
assert (false);
return false; return false;
} }
return true; return true;
@ -160,11 +141,19 @@ bool SHMProcess::Private::waitWhile (uint32_t state)
Yeah. with no way to synchronize things (locks are slow, the OS doesn't give us enough control over scheduling) 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 we end up with this silly thing
*/ */
bool SHMProcess::waitWhile (uint32_t state) bool SHMProcess::SetAndWait (uint32_t state)
{ {
return d->waitWhile(state); return d->SetAndWait(state);
} }
/*
// set SHM command.
void SHMProcess::setCmd (uint32_t newstate)
{
if(d->attached && d->suspended)
D_SHMCMD = newstate;
};
*/
uint32_t OS_getAffinity() uint32_t OS_getAffinity()
{ {
cpu_set_t mask; cpu_set_t mask;
@ -174,15 +163,16 @@ uint32_t OS_getAffinity()
return affinity; return affinity;
} }
bool SHMProcess::Private::Aux_Core_Attach(bool & versionOK, pid_t & PID) bool SHMProcess::Private::Aux_Core_Attach(bool & versionOK, pid_t & PID)
{ {
if(!locked) return false;
SHMDATA(coreattach)->cl_affinity = OS_getAffinity(); SHMDATA(coreattach)->cl_affinity = OS_getAffinity();
gcc_barrier if(!SetAndWait(CORE_ATTACH)) return false;
SHMCMD = CORE_ATTACH; /*
if(!waitWhile(CORE_ATTACH)) cerr <<"CORE_VERSION" << CORE_VERSION << endl;
return false; cerr <<"server CORE_VERSION" << SHMDATA(coreattach)->sv_version << endl;
gcc_barrier */
versionOK =( SHMDATA(coreattach)->sv_version == CORE_VERSION ); versionOK =( SHMDATA(coreattach)->sv_version == CORE_VERSION );
PID = SHMDATA(coreattach)->sv_PID; PID = SHMDATA(coreattach)->sv_PID;
useYield = SHMDATA(coreattach)->sv_useYield; useYield = SHMDATA(coreattach)->sv_useYield;
@ -192,12 +182,13 @@ bool SHMProcess::Private::Aux_Core_Attach(bool & versionOK, pid_t & PID)
return true; return true;
} }
// test if we have client and server locks and the server is present
bool SHMProcess::Private::AreLocksOk() bool SHMProcess::Private::AreLocksOk()
{ {
// both locks are inited (we hold our lock) // both locks are inited (we hold our lock)
if(my_CLfileLock != -1 && my_SVfileLock != -1) if(client_lock != -1 && server_lock != -1)
{ {
if(lockf(my_SVfileLock,F_TEST,0) == -1) // and server holds its lock if(lockf(server_lock,F_TEST,0) == -1) // and server holds its lock
{ {
return true; // OK, locks are good return true; // OK, locks are good
} }
@ -208,16 +199,23 @@ bool SHMProcess::Private::AreLocksOk()
void SHMProcess::Private::FreeLocks() void SHMProcess::Private::FreeLocks()
{ {
if(my_CLfileLock != -1) attachmentIdx = -1;
if(client_lock != -1)
{
lockf(client_lock,F_ULOCK,0);
close(client_lock);
client_lock = -1;
}
if(server_lock != -1)
{ {
lockf(my_CLfileLock,F_ULOCK,0); close(server_lock);
close(my_CLfileLock); server_lock = -1;
my_CLfileLock = -1;
} }
if(my_SVfileLock != -1) if(suspend_lock != -1)
{ {
close(my_SVfileLock); close(suspend_lock);
my_SVfileLock = -1; locked = false;
suspend_lock = -1;
} }
} }
@ -226,36 +224,65 @@ bool SHMProcess::Private::GetLocks()
char name[256]; char name[256];
// try to acquire locks // try to acquire locks
// look at the server lock, if it's locked, the server is present // look at the server lock, if it's locked, the server is present
sprintf(name, "/tmp/DFHack/%d/SVlock",my_pid,name); sprintf(name, "/tmp/DFHack/%d/SVlock",process_ID);
my_SVfileLock = open(name,O_WRONLY); server_lock = open(name,O_WRONLY);
if(my_SVfileLock == -1) if(server_lock == -1)
{ {
cerr << "can't open sv lock" << endl;
return false; return false;
} }
if(lockf( my_SVfileLock, F_TEST, 0 ) != -1) if(lockf( server_lock, F_TEST, 0 ) != -1)
{ {
close(my_SVfileLock); cerr << "sv lock not locked" << endl;
close(server_lock);
server_lock = -1;
return false; return false;
} }
// open the client lock, try to lock it for(int i = 0; i < SHM_MAX_CLIENTS; i++)
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 // open the client suspend locked
close(my_SVfileLock); sprintf(name, "/tmp/DFHack/%d/CLSlock%d",process_ID,i);
close(my_CLfileLock); suspend_lock = open(name,O_WRONLY);
return false; if(suspend_lock == -1)
{
cerr << "can't open cl S-lock " << i << endl;
// couldn't open lock
continue;
}
// open the client lock, try to lock it
sprintf(name, "/tmp/DFHack/%d/CLlock%d",process_ID,i);
client_lock = open(name,O_WRONLY);
if(client_lock == -1)
{
cerr << "can't open cl lock " << i << endl;
close(suspend_lock);
locked = false;
suspend_lock = -1;
// couldn't open lock
continue;
}
if(lockf(client_lock,F_TLOCK, 0) == -1)
{
// couldn't acquire lock
cerr << "can't acquire cl lock " << i << endl;
close(suspend_lock);
locked = false;
suspend_lock = -1;
close(client_lock);
client_lock = -1;
continue;
}
// ok, we have all the locks we need!
attachmentIdx = i;
return true;
} }
// ok, we have all the locks! close(server_lock);
return true; server_lock = -1;
cerr << "can't get any client locks" << endl;
return false;
} }
SHMProcess::SHMProcess(uint32_t PID, vector< memory_info* >& known_versions) SHMProcess::SHMProcess(uint32_t PID, vector< memory_info* >& known_versions)
@ -268,7 +295,7 @@ SHMProcess::SHMProcess(uint32_t PID, vector< memory_info* >& known_versions)
/* /*
* Locate the segment. * Locate the segment.
*/ */
if ((d->my_shmid = shmget(SHM_KEY + PID, SHM_SIZE, 0666)) < 0) if ((d->shm_ID = shmget(SHM_KEY + PID, /*SHM_ALL_CLIENTS*/SHM_SIZE, 0666)) < 0)
{ {
return; return;
} }
@ -276,68 +303,54 @@ SHMProcess::SHMProcess(uint32_t PID, vector< memory_info* >& known_versions)
/* /*
* Attach the segment * Attach the segment
*/ */
if ((d->my_shm = (char *) shmat(d->my_shmid, NULL, 0)) == (char *) -1) /*
if ((d->shm_addr = (char *) shmat(d->shm_ID, NULL, 0)) == (char *) -1)
{ {
return; return;
} }
*/
// set pid and gets lock for it d->process_ID = PID;
d->my_pid = PID; if(!attach())
if(!d->GetLocks())
{ {
fprintf(stderr,"Couldn't get locks for PID %d'\n", PID); // couldn't attach to process
shmdt(d->my_shm);
return; return;
} }
/* /*
* Test bridge version, get PID, sync Yield * Test bridge version, get PID, sync Yield
*/ */
bool bridgeOK; bool bridgeOK;
if(!d->Aux_Core_Attach(bridgeOK,d->my_pid)) if(!d->Aux_Core_Attach(bridgeOK,d->process_ID))
{ {
fprintf(stderr,"DF terminated during reading\n"); detach();
shmdt(d->my_shm); throw Error::SHMAttachFailure();
// free locks
d->FreeLocks();
return; return;
} }
if(!bridgeOK) if(!bridgeOK)
{ {
fprintf(stderr,"SHM bridge version mismatch\n"); detach();
shmdt(d->my_shm); throw Error::SHMVersionMismatch();
// free locks
d->FreeLocks();
return; return;
} }
// find the binary // find the binary
sprintf(exe_link_name,"/proc/%d/exe", d->my_pid); sprintf(exe_link_name,"/proc/%d/exe", d->process_ID);
target_result = readlink(exe_link_name, target_name, sizeof(target_name)-1); target_result = readlink(exe_link_name, target_name, sizeof(target_name)-1);
if (target_result == -1) if (target_result == -1)
{ {
perror("readlink"); perror("readlink");
shmdt(d->my_shm); detach();
// free locks
d->FreeLocks();
return; return;
} }
// make sure we have a null terminated string... // make sure we have a null terminated string...
// see http://www.opengroup.org/onlinepubs/000095399/functions/readlink.html // see http://www.opengroup.org/onlinepubs/000095399/functions/readlink.html
target_name[target_result] = 0; target_name[target_result] = 0;
// try to identify the DF version // try to identify the DF version (md5 the binary, compare with known versions)
d->validate(target_name, d->my_pid, known_versions); d->validate(target_name, d->process_ID, known_versions);
d->my_window = new DFWindow(this); d->window = new DFWindow(this);
gcc_barrier
// at this point, DF is stopped and waiting for commands. make it run again
D_SHMCMD = CORE_RUNNING;
shmdt(d->my_shm); // detach so we don't attach twice when attach() is called
// free locks // detach
d->FreeLocks(); detach();
} }
bool SHMProcess::isSuspended() bool SHMProcess::isSuspended()
@ -360,7 +373,7 @@ bool SHMProcess::Private::validate(char * exe_file, uint32_t pid, vector <memory
// get hash of the running DF process // get hash of the running DF process
string hash = md5.getHashFromFile(exe_file); string hash = md5.getHashFromFile(exe_file);
vector<memory_info *>::iterator it; vector<memory_info *>::iterator it;
cerr << exe_file << " " << hash << endl; // cerr << exe_file << " " << hash << endl;
// iterate over the list of memory locations // iterate over the list of memory locations
for ( it=known_versions.begin() ; it < known_versions.end(); it++ ) for ( it=known_versions.begin() ; it < known_versions.end(); it++ )
{ {
@ -368,10 +381,10 @@ bool SHMProcess::Private::validate(char * exe_file, uint32_t pid, vector <memory
if(hash == (*it)->getString("md5")) // are the md5 hashes the same? if(hash == (*it)->getString("md5")) // are the md5 hashes the same?
{ {
memory_info * m = *it; memory_info * m = *it;
my_descriptor = m; memdescriptor = m;
my_pid = pid; process_ID = pid;
identified = true; identified = true;
cerr << "identified " << m->getVersion() << endl; // cerr << "identified " << m->getVersion() << endl;
return true; return true;
} }
} }
@ -390,26 +403,26 @@ SHMProcess::~SHMProcess()
detach(); detach();
} }
// destroy data model. this is assigned by processmanager // destroy data model. this is assigned by processmanager
if(d->my_window) if(d->window)
{ {
delete d->my_window; delete d->window;
} }
delete d; delete d;
} }
memory_info * SHMProcess::getDescriptor() memory_info * SHMProcess::getDescriptor()
{ {
return d->my_descriptor; return d->memdescriptor;
} }
DFWindow * SHMProcess::getWindow() DFWindow * SHMProcess::getWindow()
{ {
return d->my_window; return d->window;
} }
int SHMProcess::getPID() int SHMProcess::getPID()
{ {
return d->my_pid; return d->process_ID;
} }
//FIXME: implement //FIXME: implement
@ -424,7 +437,7 @@ void SHMProcess::getMemRanges( vector<t_memrange> & ranges )
char buffer[1024]; char buffer[1024];
char permissions[5]; // r/-, w/-, x/-, p/s, 0 char permissions[5]; // r/-, w/-, x/-, p/s, 0
sprintf(buffer, "/proc/%lu/maps", d->my_pid); sprintf(buffer, "/proc/%lu/maps", d->process_ID);
FILE *mapFile = ::fopen(buffer, "r"); FILE *mapFile = ::fopen(buffer, "r");
uint64_t offset, device1, device2, node; uint64_t offset, device1, device2, node;
@ -455,13 +468,27 @@ bool SHMProcess::suspend()
{ {
return true; return true;
} }
D_SHMCMD = CORE_SUSPEND;
if(!waitWhile(CORE_SUSPEND)) // did we just resume a moment ago?
if(D_SHMCMD == CORE_RUN)
{ {
return false; //fprintf(stderr,"%d invokes step\n",d->attachmentIdx);
D_SHMCMD = CORE_STEP;
} }
d->suspended = true; else
return true; {
//fprintf(stderr,"%d invokes suspend\n",d->attachmentIdx);
D_SHMCMD = CORE_SUSPEND;
}
//fprintf(stderr,"waiting for lock\n");
// we wait for the server to give up our suspend lock (held by default)
if(lockf(d->suspend_lock,F_LOCK,0) == 0)
{
d->suspended = true;
d->locked = true;
return true;
}
return false;
} }
bool SHMProcess::asyncSuspend() bool SHMProcess::asyncSuspend()
@ -474,14 +501,37 @@ bool SHMProcess::asyncSuspend()
{ {
return true; return true;
} }
if(D_SHMCMD == CORE_SUSPENDED) if(D_SHMCMD == CORE_SUSPENDED)
{ {
d->suspended = true; // we have to hold the lock to be really suspended
return true; if(lockf(d->suspend_lock,F_LOCK,0) == 0)
{
d->locked = true;
d->suspended = true;
return true;
}
return false;
} }
else else
{ {
D_SHMCMD = CORE_SUSPEND; // did we just resume a moment ago?
if(D_SHMCMD == CORE_RUN)
{
D_SHMCMD = CORE_STEP;
}
else
{
D_SHMCMD = CORE_SUSPEND;
}
// try locking
if(lockf(d->suspend_lock,F_TLOCK,0) == 0)
{
d->locked = true;
d->suspended = true;
return true;
}
return false; return false;
} }
} }
@ -491,21 +541,29 @@ bool SHMProcess::forceresume()
return resume(); return resume();
} }
// FIXME: wait for the server to advance a step!
bool SHMProcess::resume() bool SHMProcess::resume()
{ {
if(!d->attached) if(!d->attached)
return false; return false;
if(!d->suspended) if(!d->suspended)
return true; return true;
D_SHMCMD = CORE_RUNNING; // set core to run
D_SHMCMD = CORE_RUN;
d->suspended = false; d->suspended = false;
return true; // unlock the suspend lock
if(lockf(d->suspend_lock,F_ULOCK,0) == 0)
{
d->locked = false;
return true;
}
throw Error::SHMLockingError("bool SHMProcess::resume()");
return false;
} }
bool SHMProcess::attach() bool SHMProcess::attach()
{ {
int status;
if(g_pProcess != 0) if(g_pProcess != 0)
{ {
// FIXME: throw exception here - programmer error // FIXME: throw exception here - programmer error
@ -521,7 +579,7 @@ bool SHMProcess::attach()
/* /*
* Attach the segment * Attach the segment
*/ */
if ((d->my_shm = (char *) shmat(d->my_shmid, NULL, 0)) != (char *) -1) if ((d->shm_addr = (char *) shmat(d->shm_ID, NULL, 0)) != (char *) -1)
{ {
d->attached = true; d->attached = true;
if(suspend()) if(suspend())
@ -532,7 +590,7 @@ bool SHMProcess::attach()
} }
d->attached = false; d->attached = false;
cerr << "unable to suspend" << endl; cerr << "unable to suspend" << endl;
shmdt(d->my_shm); shmdt(d->shm_addr);
d->FreeLocks(); d->FreeLocks();
return false; return false;
} }
@ -552,11 +610,11 @@ bool SHMProcess::detach()
resume(); resume();
} }
// detach segment // detach segment
if(shmdt(d->my_shm) != -1) if(shmdt(d->shm_addr) != -1)
{ {
d->attached = false; d->attached = false;
d->suspended = false; d->suspended = false;
d->my_shm = 0; d->shm_addr = 0;
g_pProcess = 0; g_pProcess = 0;
d->FreeLocks(); d->FreeLocks();
return true; return true;
@ -569,15 +627,16 @@ bool SHMProcess::detach()
void SHMProcess::read (uint32_t src_address, uint32_t size, uint8_t *target_buffer) void SHMProcess::read (uint32_t src_address, uint32_t size, uint8_t *target_buffer)
{ {
if(!d->locked) throw Error::SHMAccessDenied();
// normal read under 1MB // normal read under 1MB
if(size <= SHM_BODY) if(size <= SHM_BODY)
{ {
D_SHMHDR->address = src_address; D_SHMHDR->address = src_address;
D_SHMHDR->length = size; D_SHMHDR->length = size;
gcc_barrier gcc_barrier
D_SHMCMD = CORE_DFPP_READ; d->SetAndWait(CORE_READ);
waitWhile(CORE_DFPP_READ); memcpy (target_buffer, D_SHMDATA(void),size);
memcpy (target_buffer, d->my_shm + SHM_HEADER,size);
} }
// a big read, we pull data over the shm in iterations // a big read, we pull data over the shm in iterations
else else
@ -590,9 +649,8 @@ void SHMProcess::read (uint32_t src_address, uint32_t size, uint8_t *target_buff
D_SHMHDR->address = src_address; D_SHMHDR->address = src_address;
D_SHMHDR->length = to_read; D_SHMHDR->length = to_read;
gcc_barrier gcc_barrier
D_SHMCMD = CORE_DFPP_READ; d->SetAndWait(CORE_READ);
waitWhile(CORE_DFPP_READ); memcpy (target_buffer, D_SHMDATA(void) ,size);
memcpy (target_buffer, d->my_shm + SHM_HEADER,size);
// decrease size by bytes read // decrease size by bytes read
size -= to_read; size -= to_read;
// move the cursors // move the cursors
@ -606,54 +664,60 @@ void SHMProcess::read (uint32_t src_address, uint32_t size, uint8_t *target_buff
uint8_t SHMProcess::readByte (const uint32_t offset) uint8_t SHMProcess::readByte (const uint32_t offset)
{ {
if(!d->locked) throw Error::SHMAccessDenied();
D_SHMHDR->address = offset; D_SHMHDR->address = offset;
gcc_barrier gcc_barrier
D_SHMCMD = CORE_READ_BYTE; d->SetAndWait(CORE_READ_BYTE);
waitWhile(CORE_READ_BYTE);
return D_SHMHDR->value; return D_SHMHDR->value;
} }
void SHMProcess::readByte (const uint32_t offset, uint8_t &val ) void SHMProcess::readByte (const uint32_t offset, uint8_t &val )
{ {
if(!d->locked) throw Error::SHMAccessDenied();
D_SHMHDR->address = offset; D_SHMHDR->address = offset;
gcc_barrier gcc_barrier
D_SHMCMD = CORE_READ_BYTE; d->SetAndWait(CORE_READ_BYTE);
waitWhile(CORE_READ_BYTE);
val = D_SHMHDR->value; val = D_SHMHDR->value;
} }
uint16_t SHMProcess::readWord (const uint32_t offset) uint16_t SHMProcess::readWord (const uint32_t offset)
{ {
if(!d->locked) throw Error::SHMAccessDenied();
D_SHMHDR->address = offset; D_SHMHDR->address = offset;
gcc_barrier gcc_barrier
D_SHMCMD = CORE_READ_WORD; d->SetAndWait(CORE_READ_WORD);
waitWhile(CORE_READ_WORD);
return D_SHMHDR->value; return D_SHMHDR->value;
} }
void SHMProcess::readWord (const uint32_t offset, uint16_t &val) void SHMProcess::readWord (const uint32_t offset, uint16_t &val)
{ {
if(!d->locked) throw Error::SHMAccessDenied();
D_SHMHDR->address = offset; D_SHMHDR->address = offset;
gcc_barrier gcc_barrier
D_SHMCMD = CORE_READ_WORD; d->SetAndWait(CORE_READ_WORD);
waitWhile(CORE_READ_WORD);
val = D_SHMHDR->value; val = D_SHMHDR->value;
} }
uint32_t SHMProcess::readDWord (const uint32_t offset) uint32_t SHMProcess::readDWord (const uint32_t offset)
{ {
if(!d->locked) throw Error::SHMAccessDenied();
D_SHMHDR->address = offset; D_SHMHDR->address = offset;
gcc_barrier gcc_barrier
D_SHMCMD = CORE_READ_DWORD; d->SetAndWait(CORE_READ_DWORD);
waitWhile(CORE_READ_DWORD);
return D_SHMHDR->value; return D_SHMHDR->value;
} }
void SHMProcess::readDWord (const uint32_t offset, uint32_t &val) void SHMProcess::readDWord (const uint32_t offset, uint32_t &val)
{ {
if(!d->locked) throw Error::SHMAccessDenied();
D_SHMHDR->address = offset; D_SHMHDR->address = offset;
gcc_barrier gcc_barrier
D_SHMCMD = CORE_READ_DWORD; d->SetAndWait(CORE_READ_DWORD);
waitWhile(CORE_READ_DWORD);
val = D_SHMHDR->value; val = D_SHMHDR->value;
} }
@ -663,43 +727,47 @@ void SHMProcess::readDWord (const uint32_t offset, uint32_t &val)
void SHMProcess::writeDWord (uint32_t offset, uint32_t data) void SHMProcess::writeDWord (uint32_t offset, uint32_t data)
{ {
if(!d->locked) throw Error::SHMAccessDenied();
D_SHMHDR->address = offset; D_SHMHDR->address = offset;
D_SHMHDR->value = data; D_SHMHDR->value = data;
gcc_barrier gcc_barrier
D_SHMCMD = CORE_WRITE_DWORD; d->SetAndWait(CORE_WRITE_DWORD);
waitWhile(CORE_WRITE_DWORD);
} }
// using these is expensive. // using these is expensive.
void SHMProcess::writeWord (uint32_t offset, uint16_t data) void SHMProcess::writeWord (uint32_t offset, uint16_t data)
{ {
if(!d->locked) throw Error::SHMAccessDenied();
D_SHMHDR->address = offset; D_SHMHDR->address = offset;
D_SHMHDR->value = data; D_SHMHDR->value = data;
gcc_barrier gcc_barrier
D_SHMCMD = CORE_WRITE_WORD; d->SetAndWait(CORE_WRITE_WORD);
waitWhile(CORE_WRITE_WORD);
} }
void SHMProcess::writeByte (uint32_t offset, uint8_t data) void SHMProcess::writeByte (uint32_t offset, uint8_t data)
{ {
if(!d->locked) throw Error::SHMAccessDenied();
D_SHMHDR->address = offset; D_SHMHDR->address = offset;
D_SHMHDR->value = data; D_SHMHDR->value = data;
gcc_barrier gcc_barrier
D_SHMCMD = CORE_WRITE_BYTE; d->SetAndWait(CORE_WRITE_BYTE);
waitWhile(CORE_WRITE_BYTE);
} }
void SHMProcess::write (uint32_t dst_address, uint32_t size, uint8_t *source_buffer) void SHMProcess::write (uint32_t dst_address, uint32_t size, uint8_t *source_buffer)
{ {
if(!d->locked) throw Error::SHMAccessDenied();
// normal write under 1MB // normal write under 1MB
if(size <= SHM_BODY) if(size <= SHM_BODY)
{ {
D_SHMHDR->address = dst_address; D_SHMHDR->address = dst_address;
D_SHMHDR->length = size; D_SHMHDR->length = size;
memcpy(d->my_shm+SHM_HEADER,source_buffer, size); memcpy(D_SHMDATA(void),source_buffer, size);
gcc_barrier gcc_barrier
D_SHMCMD = CORE_WRITE; d->SetAndWait(CORE_WRITE);
waitWhile(CORE_WRITE);
} }
// a big write, we push this over the shm in iterations // a big write, we push this over the shm in iterations
else else
@ -711,10 +779,9 @@ void SHMProcess::write (uint32_t dst_address, uint32_t size, uint8_t *source_buf
// write to_write bytes to dst_cursor // write to_write bytes to dst_cursor
D_SHMHDR->address = dst_address; D_SHMHDR->address = dst_address;
D_SHMHDR->length = to_write; D_SHMHDR->length = to_write;
memcpy(d->my_shm+SHM_HEADER,source_buffer, to_write); memcpy(D_SHMDATA(void),source_buffer, to_write);
gcc_barrier gcc_barrier
D_SHMCMD = CORE_WRITE; d->SetAndWait(CORE_WRITE);
waitWhile(CORE_WRITE);
// decrease size by bytes written // decrease size by bytes written
size -= to_write; size -= to_write;
// move the cursors // move the cursors
@ -729,6 +796,8 @@ void SHMProcess::write (uint32_t dst_address, uint32_t size, uint8_t *source_buf
// FIXME: butt-fugly // FIXME: butt-fugly
const std::string SHMProcess::readCString (uint32_t offset) const std::string SHMProcess::readCString (uint32_t offset)
{ {
if(!d->locked) throw Error::SHMAccessDenied();
std::string temp; std::string temp;
char temp_c[256]; char temp_c[256];
int counter = 0; int counter = 0;
@ -746,6 +815,8 @@ const std::string SHMProcess::readCString (uint32_t offset)
DfVector SHMProcess::readVector (uint32_t offset, uint32_t item_size) DfVector SHMProcess::readVector (uint32_t offset, uint32_t item_size)
{ {
if(!d->locked) throw Error::SHMAccessDenied();
/* /*
GNU libstdc++ vector is three pointers long GNU libstdc++ vector is three pointers long
ptr start ptr start
@ -762,38 +833,43 @@ DfVector SHMProcess::readVector (uint32_t offset, uint32_t item_size)
const std::string SHMProcess::readSTLString(uint32_t offset) const std::string SHMProcess::readSTLString(uint32_t offset)
{ {
if(!d->locked) throw Error::SHMAccessDenied();
D_SHMHDR->address = offset; D_SHMHDR->address = offset;
full_barrier full_barrier
D_SHMCMD = CORE_READ_STL_STRING; d->SetAndWait(CORE_READ_STL_STRING);
waitWhile(CORE_READ_STL_STRING);
//int length = ((shm_retval *)d->my_shm)->value; //int length = ((shm_retval *)d->my_shm)->value;
return(string( (char *)d->my_shm+SHM_HEADER)); return(string( D_SHMDATA(char) ));
} }
size_t SHMProcess::readSTLString (uint32_t offset, char * buffer, size_t bufcapacity) size_t SHMProcess::readSTLString (uint32_t offset, char * buffer, size_t bufcapacity)
{ {
if(!d->locked) throw Error::SHMAccessDenied();
D_SHMHDR->address = offset; D_SHMHDR->address = offset;
full_barrier full_barrier
D_SHMCMD = CORE_READ_STL_STRING; d->SetAndWait(CORE_READ_STL_STRING);
waitWhile(CORE_READ_STL_STRING);
size_t length = D_SHMHDR->value; size_t length = D_SHMHDR->value;
size_t fit = min(bufcapacity - 1, length); size_t fit = min(bufcapacity - 1, length);
strncpy(buffer,(char *)d->my_shm+SHM_HEADER,fit); strncpy(buffer,D_SHMDATA(char),fit);
buffer[fit] = 0; buffer[fit] = 0;
return fit; return fit;
} }
void SHMProcess::writeSTLString(const uint32_t address, const std::string writeString) void SHMProcess::writeSTLString(const uint32_t address, const std::string writeString)
{ {
if(!d->locked) throw Error::SHMAccessDenied();
D_SHMHDR->address = address; D_SHMHDR->address = address;
strncpy(d->my_shm+SHM_HEADER,writeString.c_str(),writeString.length()+1); // length + 1 for the null terminator strncpy(D_SHMDATA(char),writeString.c_str(),writeString.length()+1); // length + 1 for the null terminator
full_barrier full_barrier
D_SHMCMD = CORE_WRITE_STL_STRING; d->SetAndWait(CORE_WRITE_STL_STRING);
waitWhile(CORE_WRITE_STL_STRING);
} }
string SHMProcess::readClassName (uint32_t vptr) string SHMProcess::readClassName (uint32_t vptr)
{ {
if(!d->locked) throw Error::SHMAccessDenied();
int typeinfo = readDWord(vptr - 0x4); int typeinfo = readDWord(vptr - 0x4);
int typestring = readDWord(typeinfo + 0x4); int typestring = readDWord(typeinfo + 0x4);
string raw = readCString(typestring); string raw = readCString(typestring);
@ -802,22 +878,18 @@ string SHMProcess::readClassName (uint32_t vptr)
return raw.substr(start,end-start - 2); // trim the 'st' from the end return raw.substr(start,end-start - 2); // trim the 'st' from the end
} }
// FIXME: having this around could lead to bad things in the hands of unsuspecting fools // get module index by name and version. bool 0 = error
// *!!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) bool SHMProcess::getModuleIndex (const char * name, const uint32_t version, uint32_t & OUTPUT)
{ {
modulelookup * payload = (modulelookup *) (d->my_shm + SHM_HEADER); if(!d->locked) throw Error::SHMAccessDenied();
modulelookup * payload = D_SHMDATA(modulelookup);
payload->version = version; payload->version = version;
strncpy(payload->name,name,255); strncpy(payload->name,name,255);
payload->name[255] = 0; payload->name[255] = 0;
full_barrier if(!SetAndWait(CORE_ACQUIRE_MODULE))
D_SHMCMD = CORE_ACQUIRE_MODULE;
if(!waitWhile(CORE_ACQUIRE_MODULE))
{ {
return false; // FIXME: throw a fatal exception instead return false; // FIXME: throw a fatal exception instead
} }
@ -832,5 +904,7 @@ bool SHMProcess::getModuleIndex (const char * name, const uint32_t version, uint
char * SHMProcess::getSHMStart (void) char * SHMProcess::getSHMStart (void)
{ {
return d->my_shm; if(!d->locked) return 0; //THROW HERE!
return /*d->shm_addr_with_cl_idx*/ d->shm_addr;
} }

@ -32,10 +32,10 @@ class SHMProcess::Private
public: public:
Private() Private()
{ {
my_descriptor = NULL; memdescriptor = NULL;
my_pid = 0; process_ID = 0;
my_shm = 0; shm_addr = 0;
my_window = NULL; window = NULL;
attached = false; attached = false;
suspended = false; suspended = false;
identified = false; identified = false;
@ -44,10 +44,10 @@ class SHMProcess::Private
DFCLMutex = 0; DFCLMutex = 0;
}; };
~Private(){}; ~Private(){};
memory_info * my_descriptor; memory_info * memdescriptor;
DFWindow * my_window; DFWindow * window;
uint32_t my_pid; uint32_t process_ID;
char *my_shm; char *shm_addr;
HANDLE DFSVMutex; HANDLE DFSVMutex;
HANDLE DFCLMutex; HANDLE DFCLMutex;
@ -120,7 +120,7 @@ bool SHMProcess::Private::waitWhile (uint32_t state)
{ {
attached = suspended = false; attached = suspended = false;
ReleaseMutex(DFCLMutex); ReleaseMutex(DFCLMutex);
UnmapViewOfFile(my_shm); UnmapViewOfFile(shm_addr);
throw Error::SHMServerDisappeared(); throw Error::SHMServerDisappeared();
return false; return false;
} }
@ -185,7 +185,7 @@ SHMProcess::SHMProcess(uint32_t PID, vector <memory_info *> & known_versions)
{ {
return; return;
} }
d->my_pid = PID; d->process_ID = PID;
// attach the SHM // attach the SHM
if(!attach()) if(!attach())
@ -196,7 +196,7 @@ SHMProcess::SHMProcess(uint32_t PID, vector <memory_info *> & known_versions)
// Test bridge version, get PID, sync Yield // Test bridge version, get PID, sync Yield
bool bridgeOK; bool bridgeOK;
bool error = 0; bool error = 0;
if(!d->Aux_Core_Attach(bridgeOK,d->my_pid)) if(!d->Aux_Core_Attach(bridgeOK,d->process_ID))
{ {
fprintf(stderr,"DF terminated during reading\n"); fprintf(stderr,"DF terminated during reading\n");
error = 1; error = 1;
@ -209,7 +209,7 @@ SHMProcess::SHMProcess(uint32_t PID, vector <memory_info *> & known_versions)
if(error) if(error)
{ {
D_SHMCMD = CORE_RUNNING; D_SHMCMD = CORE_RUNNING;
UnmapViewOfFile(d->my_shm); UnmapViewOfFile(d->shm_addr);
ReleaseMutex(d->DFCLMutex); ReleaseMutex(d->DFCLMutex);
CloseHandle(d->DFSVMutex); CloseHandle(d->DFSVMutex);
d->DFSVMutex = 0; d->DFSVMutex = 0;
@ -229,7 +229,7 @@ SHMProcess::SHMProcess(uint32_t PID, vector <memory_info *> & known_versions)
bool found = false; bool found = false;
d->identified = false; d->identified = false;
// open process, we only need the process open // open process, we only need the process open
hProcess = OpenProcess( PROCESS_ALL_ACCESS, FALSE, d->my_pid ); hProcess = OpenProcess( PROCESS_ALL_ACCESS, FALSE, d->process_ID );
if (NULL == hProcess) if (NULL == hProcess)
break; break;
@ -265,7 +265,7 @@ SHMProcess::SHMProcess(uint32_t PID, vector <memory_info *> & known_versions)
{ {
memory_info *m = new memory_info(**it); memory_info *m = new memory_info(**it);
m->RebaseAll(base); m->RebaseAll(base);
d->my_descriptor = m; d->memdescriptor = m;
d->identified = true; d->identified = true;
cerr << "identified " << m->getVersion() << endl; cerr << "identified " << m->getVersion() << endl;
break; break;
@ -276,13 +276,13 @@ SHMProcess::SHMProcess(uint32_t PID, vector <memory_info *> & known_versions)
if(d->identified) if(d->identified)
{ {
d->my_window = new DFWindow(this); d->window = new DFWindow(this);
} }
else else
{ {
D_SHMCMD = CORE_RUNNING; D_SHMCMD = CORE_RUNNING;
UnmapViewOfFile(d->my_shm); UnmapViewOfFile(d->shm_addr);
d->my_shm = 0; d->shm_addr = 0;
ReleaseMutex(d->DFCLMutex); ReleaseMutex(d->DFCLMutex);
CloseHandle(d->DFSVMutex); CloseHandle(d->DFSVMutex);
d->DFSVMutex = 0; d->DFSVMutex = 0;
@ -316,13 +316,13 @@ SHMProcess::~SHMProcess()
detach(); detach();
} }
// destroy data model. this is assigned by processmanager // destroy data model. this is assigned by processmanager
if(d->my_descriptor) if(d->memdescriptor)
{ {
delete d->my_descriptor; delete d->memdescriptor;
} }
if(d->my_window) if(d->window)
{ {
delete d->my_window; delete d->window;
} }
// release mutex handles we have // release mutex handles we have
if(d->DFCLMutex) if(d->DFCLMutex)
@ -338,17 +338,17 @@ SHMProcess::~SHMProcess()
memory_info * SHMProcess::getDescriptor() memory_info * SHMProcess::getDescriptor()
{ {
return d->my_descriptor; return d->memdescriptor;
} }
DFWindow * SHMProcess::getWindow() DFWindow * SHMProcess::getWindow()
{ {
return d->my_window; return d->window;
} }
int SHMProcess::getPID() int SHMProcess::getPID()
{ {
return d->my_pid; return d->process_ID;
} }
//FIXME: implement //FIXME: implement
@ -363,7 +363,7 @@ void SHMProcess::getMemRanges( vector<t_memrange> & ranges )
char buffer[1024]; char buffer[1024];
char permissions[5]; // r/-, w/-, x/-, p/s, 0 char permissions[5]; // r/-, w/-, x/-, p/s, 0
sprintf(buffer, "/proc/%lu/maps", d->my_pid); sprintf(buffer, "/proc/%lu/maps", d->process_ID);
FILE *mapFile = ::fopen(buffer, "r"); FILE *mapFile = ::fopen(buffer, "r");
uint64_t offset, device1, device2, node; uint64_t offset, device1, device2, node;
@ -476,7 +476,7 @@ bool SHMProcess::attach()
} }
char shmname [256]; char shmname [256];
sprintf(shmname,"DFShm-%d",d->my_pid); sprintf(shmname,"DFShm-%d",d->process_ID);
// now try getting and attaching the shared memory // now try getting and attaching the shared memory
HANDLE shmHandle = OpenFileMapping(FILE_MAP_ALL_ACCESS,false,shmname); HANDLE shmHandle = OpenFileMapping(FILE_MAP_ALL_ACCESS,false,shmname);
@ -487,8 +487,8 @@ bool SHMProcess::attach()
} }
// attempt to attach the opened mapping // attempt to attach the opened mapping
d->my_shm = (char *) MapViewOfFile(shmHandle,FILE_MAP_ALL_ACCESS, 0,0, SHM_SIZE); d->shm_addr = (char *) MapViewOfFile(shmHandle,FILE_MAP_ALL_ACCESS, 0,0, SHM_ALL_CLIENTS);
if(!d->my_shm) if(!d->shm_addr)
{ {
CloseHandle(shmHandle); CloseHandle(shmHandle);
ReleaseMutex(d->DFCLMutex); ReleaseMutex(d->DFCLMutex);
@ -509,7 +509,7 @@ bool SHMProcess::detach()
return false; return false;
} }
// detach segment // detach segment
UnmapViewOfFile(d->my_shm); UnmapViewOfFile(d->shm_addr);
// release it for some other client // release it for some other client
ReleaseMutex(d->DFCLMutex); // we keep the mutex handles ReleaseMutex(d->DFCLMutex); // we keep the mutex handles
d->attached = false; d->attached = false;
@ -528,7 +528,7 @@ void SHMProcess::read (uint32_t src_address, uint32_t size, uint8_t *target_buff
full_barrier full_barrier
D_SHMCMD = CORE_DFPP_READ; D_SHMCMD = CORE_DFPP_READ;
d->waitWhile(CORE_DFPP_READ); d->waitWhile(CORE_DFPP_READ);
memcpy (target_buffer, d->my_shm + SHM_HEADER,size); memcpy (target_buffer, d->shm_addr + SHM_HEADER,size);
} }
// a big read, we pull data over the shm in iterations // a big read, we pull data over the shm in iterations
else else
@ -543,7 +543,7 @@ void SHMProcess::read (uint32_t src_address, uint32_t size, uint8_t *target_buff
full_barrier full_barrier
D_SHMCMD = CORE_DFPP_READ; D_SHMCMD = CORE_DFPP_READ;
d->waitWhile(CORE_DFPP_READ); d->waitWhile(CORE_DFPP_READ);
memcpy (target_buffer, d->my_shm + SHM_HEADER,size); memcpy (target_buffer, d->shm_addr + SHM_HEADER,size);
// decrease size by bytes read // decrease size by bytes read
size -= to_read; size -= to_read;
// move the cursors // move the cursors
@ -647,7 +647,7 @@ void SHMProcess::write (uint32_t dst_address, uint32_t size, uint8_t *source_buf
{ {
D_SHMHDR->address = dst_address; D_SHMHDR->address = dst_address;
D_SHMHDR->length = size; D_SHMHDR->length = size;
memcpy(d->my_shm+SHM_HEADER,source_buffer, size); memcpy(d->shm_addr+SHM_HEADER,source_buffer, size);
full_barrier full_barrier
D_SHMCMD = CORE_WRITE; D_SHMCMD = CORE_WRITE;
d->waitWhile(CORE_WRITE); d->waitWhile(CORE_WRITE);
@ -662,7 +662,7 @@ void SHMProcess::write (uint32_t dst_address, uint32_t size, uint8_t *source_buf
// write to_write bytes to dst_cursor // write to_write bytes to dst_cursor
D_SHMHDR->address = dst_address; D_SHMHDR->address = dst_address;
D_SHMHDR->length = to_write; D_SHMHDR->length = to_write;
memcpy(d->my_shm+SHM_HEADER,source_buffer, to_write); memcpy(d->shm_addr+SHM_HEADER,source_buffer, to_write);
full_barrier full_barrier
D_SHMCMD = CORE_WRITE; D_SHMCMD = CORE_WRITE;
d->waitWhile(CORE_WRITE); d->waitWhile(CORE_WRITE);
@ -723,7 +723,7 @@ const std::string SHMProcess::readSTLString(uint32_t offset)
int length = D_SHMHDR->value; int length = D_SHMHDR->value;
// char temp_c[256]; // char temp_c[256];
// strncpy(temp_c, d->my_shm+SHM_HEADER,length+1); // length + 1 for the null terminator // strncpy(temp_c, d->my_shm+SHM_HEADER,length+1); // length + 1 for the null terminator
return(string(d->my_shm+SHM_HEADER)); return(string(d->shm_addr+SHM_HEADER));
} }
size_t SHMProcess::readSTLString (uint32_t offset, char * buffer, size_t bufcapacity) size_t SHMProcess::readSTLString (uint32_t offset, char * buffer, size_t bufcapacity)
@ -735,7 +735,7 @@ size_t SHMProcess::readSTLString (uint32_t offset, char * buffer, size_t bufcapa
d->waitWhile(CORE_READ_STL_STRING); d->waitWhile(CORE_READ_STL_STRING);
size_t length = D_SHMHDR->value; size_t length = D_SHMHDR->value;
size_t real = min(length, bufcapacity - 1); size_t real = min(length, bufcapacity - 1);
strncpy(buffer, d->my_shm+SHM_HEADER,real); // length + 1 for the null terminator strncpy(buffer, d->shm_addr+SHM_HEADER,real); // length + 1 for the null terminator
buffer[real] = 0; buffer[real] = 0;
return real; return real;
} }
@ -743,7 +743,7 @@ size_t SHMProcess::readSTLString (uint32_t offset, char * buffer, size_t bufcapa
void SHMProcess::writeSTLString(const uint32_t address, const std::string writeString) void SHMProcess::writeSTLString(const uint32_t address, const std::string writeString)
{ {
D_SHMHDR->address = address/*-4*/; D_SHMHDR->address = address/*-4*/;
strncpy(d->my_shm+SHM_HEADER,writeString.c_str(),writeString.length()+1); // length + 1 for the null terminator strncpy(d->shm_addr+SHM_HEADER,writeString.c_str(),writeString.length()+1); // length + 1 for the null terminator
full_barrier full_barrier
D_SHMCMD = CORE_WRITE_STL_STRING; D_SHMCMD = CORE_WRITE_STL_STRING;
d->waitWhile(CORE_WRITE_STL_STRING); d->waitWhile(CORE_WRITE_STL_STRING);
@ -761,7 +761,7 @@ string SHMProcess::readClassName (uint32_t vptr)
// get module index by name and version. bool 1 = error // get module index by name and version. bool 1 = error
bool SHMProcess::getModuleIndex (const char * name, const uint32_t version, uint32_t & OUTPUT) bool SHMProcess::getModuleIndex (const char * name, const uint32_t version, uint32_t & OUTPUT)
{ {
modulelookup * payload = (modulelookup *) (d->my_shm + SHM_HEADER); modulelookup * payload = (modulelookup *) (d->shm_addr + SHM_HEADER);
payload->version = version; payload->version = version;
strcpy(payload->name,name); strcpy(payload->name,name);
full_barrier full_barrier
@ -774,5 +774,5 @@ bool SHMProcess::getModuleIndex (const char * name, const uint32_t version, uint
char * SHMProcess::getSHMStart (void) char * SHMProcess::getSHMStart (void)
{ {
return d->my_shm; return d->shm_addr;
} }

@ -123,8 +123,14 @@ namespace DFHack
virtual bool getModuleIndex (const char * name, const uint32_t version, uint32_t & OUTPUT) = 0; virtual bool getModuleIndex (const char * name, const uint32_t version, uint32_t & OUTPUT) = 0;
// get the SHM start if available // get the SHM start if available
virtual char * getSHMStart (void) = 0; virtual char * getSHMStart (void) = 0;
// wait for a SHM state. returns 0 without the SHM // set a SHM command and wait for a response, return 0 on error or throw exception
virtual bool SetAndWait (uint32_t state) = 0;
/*
// wait while SHM command == state. returns 0 without the SHM
virtual bool waitWhile (uint32_t state) = 0; virtual bool waitWhile (uint32_t state) = 0;
// set SHM command.
virtual void setCmd (uint32_t newstate) = 0;
*/
}; };
class DFHACK_EXPORT NormalProcess : virtual public Process class DFHACK_EXPORT NormalProcess : virtual public Process
@ -181,8 +187,14 @@ namespace DFHack
bool getModuleIndex (const char * name, const uint32_t version, uint32_t & OUTPUT) {return false;}; bool getModuleIndex (const char * name, const uint32_t version, uint32_t & OUTPUT) {return false;};
// get the SHM start if available // get the SHM start if available
char * getSHMStart (void){return 0;}; char * getSHMStart (void){return 0;};
// set a SHM command and wait for a response
bool SetAndWait (uint32_t state){return false;};
/*
// wait for a SHM state. returns 0 without the SHM // wait for a SHM state. returns 0 without the SHM
bool waitWhile (uint32_t state){return false;}; bool waitWhile (uint32_t state){return false;};
// set SHM command.
void setCmd (uint32_t newstate){};
*/
}; };
class DFHACK_EXPORT SHMProcess : virtual public Process class DFHACK_EXPORT SHMProcess : virtual public Process
@ -240,8 +252,13 @@ namespace DFHack
bool getModuleIndex (const char * name, const uint32_t version, uint32_t & OUTPUT); bool getModuleIndex (const char * name, const uint32_t version, uint32_t & OUTPUT);
// get the SHM start if available // get the SHM start if available
char * getSHMStart (void); char * getSHMStart (void);
bool SetAndWait (uint32_t state);
/*
// wait for a SHM state. returns 0 without the SHM // wait for a SHM state. returns 0 without the SHM
bool waitWhile (uint32_t state); bool waitWhile (uint32_t state);
// set SHM command.
void setCmd (uint32_t newstate);
*/
}; };
#ifdef LINUX_BUILD #ifdef LINUX_BUILD
@ -299,8 +316,13 @@ namespace DFHack
bool getModuleIndex (const char * name, const uint32_t version, uint32_t & OUTPUT) {return false;}; bool getModuleIndex (const char * name, const uint32_t version, uint32_t & OUTPUT) {return false;};
// get the SHM start if available // get the SHM start if available
char * getSHMStart (void){return 0;}; char * getSHMStart (void){return 0;};
bool SetAndWait (uint32_t state){return false;};
/*
// wait for a SHM state. returns 0 without the SHM // wait for a SHM state. returns 0 without the SHM
bool waitWhile (uint32_t state){return false;}; bool waitWhile (uint32_t state){return false;};
// set SHM command.
void setCmd (uint32_t newstate){};
*/
}; };
#endif #endif
} }

@ -41,19 +41,22 @@ distribution.
std::vector <DFPP_module> module_registry; std::vector <DFPP_module> module_registry;
// various crud // shared by shms_OS
extern int errorstate; extern int errorstate;
extern char *shm; extern char *shm;
extern int shmid; extern int shmid;
// file-globals
bool useYield = 0; bool useYield = 0;
int currentClient = -1;
#define SHMHDR ((shm_core_hdr *)shm) #define SHMHDR ((shm_core_hdr *)shm)
#define SHMCMD ((shm_cmd *)shm)->pingpong #define SHMCMDPP ((shm_core_hdr *) shm)->cmd[currentClient].pingpong
#define SHMDATA(type) ((type *)(shm + SHM_HEADER)) #define SHMDATA(type) ((type *)(shm + SHM_HEADER))
void ReadRaw (void * data) void ReadRaw (void * data)
{ {
memcpy(shm + SHM_HEADER, (void *) SHMHDR->address,SHMHDR->length); memcpy(SHMDATA(void), (void *) SHMHDR->address,SHMHDR->length);
} }
void ReadDWord (void * data) void ReadDWord (void * data)
@ -73,7 +76,7 @@ void ReadByte (void * data)
void WriteRaw (void * data) void WriteRaw (void * data)
{ {
memcpy((void *)SHMHDR->address, shm + SHM_HEADER,SHMHDR->length); memcpy((void *)SHMHDR->address, SHMDATA(void),SHMHDR->length);
} }
void WriteDWord (void * data) void WriteDWord (void * data)
@ -97,14 +100,14 @@ void ReadSTLString (void * data)
unsigned int l = myStringPtr->length(); unsigned int l = myStringPtr->length();
SHMHDR->value = l; SHMHDR->value = l;
// FIXME: there doesn't have to be a null terminator! // FIXME: there doesn't have to be a null terminator!
strncpy(shm+SHM_HEADER,myStringPtr->c_str(),l+1); strncpy( SHMDATA(char),myStringPtr->c_str(),l+1);
} }
void WriteSTLString (void * data) void WriteSTLString (void * data)
{ {
std::string * myStringPtr = (std::string *) SHMHDR->address; std::string * myStringPtr = (std::string *) SHMHDR->address;
// here we DO expect a 0 terminator // here we DO expect a 0 terminator
myStringPtr->assign((const char *) (shm + SHM_HEADER)); myStringPtr->assign( SHMDATA(const char) );
} }
// MIT HAKMEM bitcount // MIT HAKMEM bitcount
@ -133,7 +136,7 @@ void CoreAttach (void * data)
void FindModule (void * data) void FindModule (void * data)
{ {
bool found = false; bool found = false;
modulelookup * payload = (modulelookup *) (shm + SHM_HEADER); modulelookup * payload = SHMDATA(modulelookup);
std::string test = payload->name; std::string test = payload->name;
uint32_t version = payload->version; uint32_t version = payload->version;
for(unsigned int i = 0; i < module_registry.size();i++) for(unsigned int i = 0; i < module_registry.size();i++)
@ -175,6 +178,11 @@ void FindCommand (void * data)
SHMHDR->error = true; SHMHDR->error = true;
} }
void ReleaseSuspendLock( void * data )
{
OS_releaseSuspendLock(currentClient);
}
DFPP_module InitCore(void) DFPP_module InitCore(void)
{ {
DFPP_module core; DFPP_module core;
@ -185,7 +193,9 @@ DFPP_module InitCore(void)
core.reserve(NUM_CORE_CMDS); core.reserve(NUM_CORE_CMDS);
// basic states // basic states
core.set_command(CORE_RUNNING, CANCELLATION, "Running"); core.set_command(CORE_RUNNING, CANCELLATION, "Running");
core.set_command(CORE_SUSPEND, CLIENT_WAIT, "Suspend", 0 , CORE_SUSPENDED); core.set_command(CORE_RUN, FUNCTION, "Run!",0,CORE_RUNNING);
core.set_command(CORE_STEP, CANCELLATION, "Suspend on next step",0,CORE_SUSPEND);// set command to CORE_SUSPEND, check next client
core.set_command(CORE_SUSPEND, FUNCTION, "Suspend", ReleaseSuspendLock , CORE_SUSPENDED);
core.set_command(CORE_SUSPENDED, CLIENT_WAIT, "Suspended"); core.set_command(CORE_SUSPENDED, CLIENT_WAIT, "Suspended");
core.set_command(CORE_ERROR, CANCELLATION, "Error"); core.set_command(CORE_ERROR, CANCELLATION, "Error");
@ -195,7 +205,7 @@ DFPP_module InitCore(void)
core.set_command(CORE_ACQUIRE_COMMAND, FUNCTION, "Command lookup", FindCommand, CORE_SUSPENDED); core.set_command(CORE_ACQUIRE_COMMAND, FUNCTION, "Command lookup", FindCommand, CORE_SUSPENDED);
// raw reads // raw reads
core.set_command(CORE_DFPP_READ, FUNCTION,"Raw read",ReadRaw, CORE_SUSPENDED); core.set_command(CORE_READ, FUNCTION,"Raw read",ReadRaw, CORE_SUSPENDED);
core.set_command(CORE_READ_DWORD, FUNCTION,"Read DWORD",ReadDWord, 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_WORD, FUNCTION,"Read WORD",ReadWord, CORE_SUSPENDED);
core.set_command(CORE_READ_BYTE, FUNCTION,"Read BYTE",ReadByte, CORE_SUSPENDED); core.set_command(CORE_READ_BYTE, FUNCTION,"Read BYTE",ReadByte, CORE_SUSPENDED);
@ -233,60 +243,84 @@ void KillModules (void)
void SHM_Act (void) void SHM_Act (void)
{ {
volatile uint32_t atomic = 0;
if(errorstate) if(errorstate)
{ {
return; return;
} }
uint32_t numwaits = 0; //static uint oldcl = 88;
check_again: // goto target!!! for(currentClient = 0; currentClient < SHM_MAX_CLIENTS;currentClient++)
if(numwaits == 10000)
{ {
// this tests if there's a process on the other side // set the offset for the shared memory used for the client
if(isValidSHM()) uint32_t numwaits = 0;
check_again: // goto target!!!
if(numwaits == 10000)
{ {
numwaits = 0; // this tests if there's a process on the other side
if(isValidSHM(currentClient))
{
numwaits = 0;
}
else
{
full_barrier
SHMCMDPP = CORE_RUNNING;
fprintf(stderr,"dfhack: Broke out of loop, other process disappeared.\n");
}
} }
else full_barrier // I don't want the compiler to reorder my code.
//fprintf(stderr,"%d: %x %x\n",currentClient, (uint) SHMHDR, (uint) &(SHMHDR->cmd[currentClient]));
// 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
atomic = *(uint32_t *) (shm + 4*currentClient); //SHMHDR->cmd[currentClient];
full_barrier
DFPP_module & mod = module_registry[ ((shm_cmd)atomic).parts.module ];
DFPP_command & cmd = mod.commands[ ((shm_cmd)atomic).parts.command ];
/*
if(atomic == CORE_RUNNING)
{ {
full_barrier // we are running again for this process
SHMCMD = CORE_RUNNING; // reaquire the suspend lock
fprintf(stderr,"dfhack: Broke out of loop, other process disappeared.\n"); OS_lockSuspendLock(currentClient);
continue;
} }
}
// 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 full_barrier
if(cmd.nextState != -1) */
{ if(cmd._function)
SHMCMD = cmd.nextState; {
} cmd._function(mod.modulestate);
}
full_barrier full_barrier
if(cmd.type != CANCELLATION)
{ if(cmd.nextState != -1)
if(useYield)
{ {
SCHED_YIELD fprintf(stderr, "Client %d invoked %d:%d = %x = ",
currentClient,((shm_cmd)atomic).parts.module,((shm_cmd)atomic).parts.command, cmd._function);
fprintf(stderr, "%s\n",cmd.name.c_str());
// FIXME: WHAT HAPPENS WHEN A 'NEXTSTATE' IS FROM A DIFFERENT MODULE THAN 'CORE'? Yeah. It doesn't work.
SHMCMDPP = cmd.nextState;
fprintf(stderr, "Server set %d\n",cmd.nextState);
} }
numwaits ++; // watchdog timeout full_barrier
goto check_again;
if(cmd.type != CANCELLATION)
{
if(useYield)
{
SCHED_YIELD
}
numwaits ++; // watchdog timeout
goto check_again;
}
full_barrier
// we are running again for this process
// reaquire the suspend lock
OS_lockSuspendLock(currentClient);
} }
} }

@ -26,11 +26,11 @@ distribution.
#define SHMS_CORE_H #define SHMS_CORE_H
// increment on every core change // increment on every core change
#define CORE_VERSION 7 #define CORE_VERSION 8
typedef struct typedef struct
{ {
shm_cmd cmd; shm_cmd cmd[SHM_MAX_CLIENTS]; // MANDATORY!
uint32_t address; uint32_t address;
uint32_t value; uint32_t value;
uint32_t length; uint32_t length;
@ -62,6 +62,8 @@ enum CORE_COMMAND
{ {
// basic states // basic states
CORE_RUNNING = 0, // no command, normal server execution CORE_RUNNING = 0, // no command, normal server execution
CORE_RUN, // sent by the client to restart the server execution
CORE_STEP, // client suspend sets step
CORE_SUSPEND, // client notifies server to wait for commands (server is stalled in busy wait) 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_SUSPENDED, // response to WAIT, server is stalled in busy wait
CORE_ERROR, // there was a server error CORE_ERROR, // there was a server error
@ -72,7 +74,7 @@ enum CORE_COMMAND
CORE_ACQUIRE_COMMAND, // get module::command callsign by module name, command name and module version CORE_ACQUIRE_COMMAND, // get module::command callsign by module name, command name and module version
// raw reads // raw reads
CORE_DFPP_READ, // cl -> sv, read some data CORE_READ, // cl -> sv, read some data
CORE_READ_DWORD, // cl -> sv, read a dword CORE_READ_DWORD, // cl -> sv, read a dword
CORE_READ_WORD, // cl -> sv, read a word CORE_READ_WORD, // cl -> sv, read a word
CORE_READ_BYTE, // cl -> sv, read a byte CORE_READ_BYTE, // cl -> sv, read a byte

@ -19,7 +19,7 @@ extern char *shm;
#define SHMHDR ((shm_maps_hdr *)shm) #define SHMHDR ((shm_maps_hdr *)shm)
#define SHMCMD ((shm_cmd *)shm)->pingpong #define SHMCMD ((shm_cmd *)shm)->pingpong
#define SHMDATA ((char *)(shm + SHM_HEADER)) #define SHMDATA(type) ((type *)(shm + SHM_HEADER))
void NullCommand (void* data) void NullCommand (void* data)
{ {
@ -28,7 +28,7 @@ void NullCommand (void* data)
void InitOffsets (void* data) void InitOffsets (void* data)
{ {
maps_modulestate * state = (maps_modulestate *) data; maps_modulestate * state = (maps_modulestate *) data;
memcpy((void *) &(state->offsets), SHMDATA, sizeof(maps_offsets)); memcpy((void *) &(state->offsets), SHMDATA(void), sizeof(maps_offsets));
((maps_modulestate *) data)->inited = true; ((maps_modulestate *) data)->inited = true;
} }
@ -53,8 +53,6 @@ struct mblock
uint32_t * ptr_to_dirty; uint32_t * ptr_to_dirty;
}; };
#define SHMBLOCK ((mapblock40d *)(shm + SHM_HEADER))
inline void ReadBlockByAddress (void * data) inline void ReadBlockByAddress (void * data)
{ {
maps_modulestate * state = (maps_modulestate *) data; maps_modulestate * state = (maps_modulestate *) data;
@ -62,13 +60,13 @@ inline void ReadBlockByAddress (void * data)
mblock * block = (mblock *) SHMHDR->address; mblock * block = (mblock *) SHMHDR->address;
if(block) if(block)
{ {
memcpy(&(SHMBLOCK->tiletypes), ((char *) block) + offsets.tile_type_offset, sizeof(SHMBLOCK->tiletypes)); memcpy(&(SHMDATA(mapblock40d)->tiletypes), ((char *) block) + offsets.tile_type_offset, sizeof(SHMDATA(mapblock40d)->tiletypes));
memcpy(&(SHMBLOCK->designaton), ((char *) block) + offsets.designation_offset, sizeof(SHMBLOCK->designaton)); memcpy(&(SHMDATA(mapblock40d)->designaton), ((char *) block) + offsets.designation_offset, sizeof(SHMDATA(mapblock40d)->designaton));
memcpy(&(SHMBLOCK->occupancy), ((char *) block) + offsets.occupancy_offset, sizeof(SHMBLOCK->occupancy)); memcpy(&(SHMDATA(mapblock40d)->occupancy), ((char *) block) + offsets.occupancy_offset, sizeof(SHMDATA(mapblock40d)->occupancy));
memcpy(&(SHMBLOCK->biome_indices), ((char *) block) + offsets.biome_stuffs, sizeof(SHMBLOCK->biome_indices)); memcpy(&(SHMDATA(mapblock40d)->biome_indices), ((char *) block) + offsets.biome_stuffs, sizeof(SHMDATA(mapblock40d)->biome_indices));
SHMBLOCK->dirty_dword = *block->ptr_to_dirty; SHMDATA(mapblock40d)->dirty_dword = *block->ptr_to_dirty;
SHMBLOCK->origin = (uint32_t)block; SHMDATA(mapblock40d)->origin = (uint32_t)block;
SHMHDR->error = false; SHMHDR->error = false;
} }
else else

@ -71,7 +71,7 @@ typedef struct
typedef struct typedef struct
{ {
shm_cmd cmd; shm_cmd cmd[SHM_MAX_CLIENTS]; // MANDATORY!
uint32_t x; uint32_t x;
uint32_t y; uint32_t y;
uint32_t z; uint32_t z;

@ -51,38 +51,27 @@ char *shm = 0;
int shmid = 0; int shmid = 0;
bool inited = 0; bool inited = 0;
int fd_svlock = 0; int fd_svlock = -1;
int fd_cllock = 0; int fd_cllock[SHM_MAX_CLIENTS];
int fd_clSlock[SHM_MAX_CLIENTS];
int held_clSlock[SHM_MAX_CLIENTS];
int numheld = SHM_MAX_CLIENTS;
/******************************************************************************* /*******************************************************************************
* SHM part starts here * * SHM part starts here *
*******************************************************************************/ *******************************************************************************/
/*
// FIXME: add error checking?
bool isValidSHM()
{
shmid_ds descriptor;
shmctl(shmid, IPC_STAT, &descriptor);
//fprintf(stderr,"ID %d, attached: %d\n",shmid, descriptor.shm_nattch);
return (descriptor.shm_nattch == 2);
}
*/
// is the other side still there? // is the other side still there?
bool isValidSHM() bool isValidSHM(int which)
{ {
// try if CL lock file is free // if we get the client lock here, the client process failed and we need to reclaim our suspend lock
int result = lockf(fd_cllock,F_TEST,0); if(lockf(fd_cllock[which],F_TLOCK,0) == 0)
/* {
F_TEST: Test the lock: // we get back our suspend lock from the cold, dead hands of the former client :P
return 0 if the specified section is unlocked or locked by this process; OS_lockSuspendLock(which);
return -1, set errno to EAGAIN (EACCES on some other systems), if another process holds a lock. // free the client lock again
*/ lockf(fd_cllock[which],F_ULOCK,0);
return false;
// 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; return true;
} }
@ -100,6 +89,45 @@ uint32_t OS_getAffinity()
return affinity; return affinity;
} }
void OS_lockSuspendLock(int which)
{
if(numheld == SHM_MAX_CLIENTS)
return;
// lock not held by server and can be picked up. OK.
if(held_clSlock[which] == 0 && lockf(fd_clSlock[which],F_LOCK,0) == 0)
{
held_clSlock[which] = 1;
numheld++;
}
// lock couldn't be picked up!
else if (held_clSlock[which] == 0)
{
fprintf(stderr,"lock %d failed to lock\n", which);
}
}
void OS_releaseSuspendLock(int which)
{
/*
if(which >=0 && which < SHM_MAX_CLIENTS)
return;
*/
if(numheld != SHM_MAX_CLIENTS)
{
fprintf(stderr,"TOTAL FAILURE OF LOCKING SYSTEM\n");
return;
}
// lock hel by server and can be released -> OK
if(held_clSlock[which] == 1 && lockf(fd_clSlock[which],F_ULOCK,0) == 0)
{
numheld--;
held_clSlock[which] = 0;
}
// locked and not can't be released? FAIL!
else if (held_clSlock[which] == 1)
fprintf(stderr,"lock %d failed to unlock\n", which);
}
void SHM_Init ( void ) void SHM_Init ( void )
{ {
// check that we do this only once per process // check that we do this only once per process
@ -111,7 +139,6 @@ void SHM_Init ( void )
inited = true; inited = true;
char name[256]; char name[256];
char name2[256]; char name2[256];
// make folder structure for our lock files // make folder structure for our lock files
sprintf(name, "/tmp/DFHack/%d",OS_getPID()); sprintf(name, "/tmp/DFHack/%d",OS_getPID());
mode_t createmode = S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH; mode_t createmode = S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH;
@ -123,9 +150,17 @@ void SHM_Init ( void )
fd_svlock = open(name2,O_WRONLY | O_CREAT, createmode); fd_svlock = open(name2,O_WRONLY | O_CREAT, createmode);
lockf( fd_svlock, F_LOCK, 0 ); lockf( fd_svlock, F_LOCK, 0 );
// create the client lock file for(int i = 0; i < SHM_MAX_CLIENTS; i++)
sprintf(name2, "%s/CLlock",name); {
fd_cllock = open(name2,O_WRONLY | O_CREAT, createmode); // create the client lock file
sprintf(name2, "%s/CLlock%d",name,i);
fd_cllock[i] = open(name2,O_WRONLY | O_CREAT, createmode);
// get and lock the suspend locks
sprintf(name2, "%s/CLSlock%d",name,i);
fd_clSlock[i] = open(name2,O_WRONLY | O_CREAT, createmode);
lockf(fd_clSlock[i],F_LOCK,0);
held_clSlock[i] = 1;
}
// name for the segment, an accident waiting to happen // name for the segment, an accident waiting to happen
key_t key = SHM_KEY + OS_getPID(); key_t key = SHM_KEY + OS_getPID();
@ -159,7 +194,10 @@ void SHM_Init ( void )
} }
full_barrier full_barrier
// make sure we don't stall or do crazy stuff // make sure we don't stall or do crazy stuff
((shm_cmd *)shm)->pingpong = CORE_RUNNING; for(int i = 0; i < SHM_MAX_CLIENTS;i++)
{
((shm_cmd *)shm)[i].pingpong = CORE_RUNNING;
}
InitModules(); InitModules();
} }
@ -177,21 +215,29 @@ void SHM_Destroy ( void )
} }
shmctl(shmid,IPC_RMID,NULL); 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 name[256];
char name2[256]; char name2[256];
sprintf(name, "/tmp/DFHack/%d",OS_getPID()); sprintf(name, "/tmp/DFHack/%d",OS_getPID());
// unlock and close server lock, close client lock, destroy files
lockf(fd_svlock,F_ULOCK,0);
for(int i = 0; i < SHM_MAX_CLIENTS; i++)
{
close(fd_cllock[i]);
fd_cllock[i] = 0;
close(fd_clSlock[i]);
fd_clSlock[i] = 0;
held_clSlock[i] = 0;
sprintf(name2, "%s/CLlock%d",name,i);
unlink(name2);
sprintf(name2, "%s/CLSlock%d",name,i);
unlink(name2);
}
close(fd_svlock);
fd_svlock = 0;
sprintf(name2, "%s/SVlock",name); sprintf(name2, "%s/SVlock",name);
unlink(name2); unlink(name2);
sprintf(name2, "%s/CLlock",name); // remove the PID folder
unlink(name2);
rmdir(name); rmdir(name);
fprintf(stderr,"dfhack: destroyed shared segment.\n"); fprintf(stderr,"dfhack: destroyed shared segment.\n");
inited = false; inited = false;
@ -213,7 +259,7 @@ DFhackCExport void SDL_GL_SwapBuffers(void)
{ {
if(_SDL_GL_SwapBuffers) if(_SDL_GL_SwapBuffers)
{ {
if(!errorstate && ((shm_cmd *)shm)->pingpong != CORE_RUNNING) if(!errorstate)
{ {
SHM_Act(); SHM_Act();
} }
@ -227,7 +273,7 @@ DFhackCExport int SDL_Flip(void * some_ptr)
{ {
if(_SDL_Flip) if(_SDL_Flip)
{ {
if(!errorstate && ((shm_cmd *)shm)->pingpong != CORE_RUNNING) if(!errorstate)
{ {
SHM_Act(); SHM_Act();
} }
@ -285,7 +331,7 @@ DFhackCExport int refresh (void)
{ {
if(_refresh) if(_refresh)
{ {
if(!errorstate && ((shm_cmd *)shm)->pingpong != CORE_RUNNING) if(!errorstate)
{ {
SHM_Act(); SHM_Act();
} }

@ -117,7 +117,7 @@ void SHM_Init ( void )
} }
// create virtual memory mapping // create virtual memory mapping
shmHandle = CreateFileMapping(INVALID_HANDLE_VALUE,NULL,PAGE_READWRITE,0,SHM_SIZE,shmname); shmHandle = CreateFileMapping(INVALID_HANDLE_VALUE,NULL,PAGE_READWRITE,0,SHM_ALL_CLIENTS,shmname);
// if can't create or already exists -> nothing happens // if can't create or already exists -> nothing happens
if(GetLastError() == ERROR_ALREADY_EXISTS) if(GetLastError() == ERROR_ALREADY_EXISTS)
{ {
@ -138,7 +138,7 @@ void SHM_Init ( void )
return; return;
} }
// attempt to attach the created mapping // attempt to attach the created mapping
shm = (char *) MapViewOfFile(shmHandle,FILE_MAP_ALL_ACCESS, 0,0, SHM_SIZE); shm = (char *) MapViewOfFile(shmHandle,FILE_MAP_ALL_ACCESS, 0,0, SHM_ALL_CLIENTS);
if(shm) if(shm)
{ {
((shm_cmd *)shm)->pingpong = CORE_RUNNING; ((shm_cmd *)shm)->pingpong = CORE_RUNNING;

@ -2,10 +2,12 @@
#define DFCONNECT_H #define DFCONNECT_H
#define SHM_KEY 123466 #define SHM_KEY 123466
#define SHM_MAX_CLIENTS 4
#define SHM_HEADER 1024 // 1kB reserved for a header #define SHM_HEADER 1024 // 1kB reserved for a header
#define SHM_BODY 1024*1024 // 1MB reserved for bulk data transfer #define SHM_BODY 1024*1024 // 4MB reserved for bulk data transfer
#define SHM_SIZE SHM_HEADER+SHM_BODY #define SHM_SIZE SHM_HEADER+SHM_BODY
//#define SHM_ALL_CLIENTS SHM_MAX_CLIENTS*(SHM_SIZE)
//#define SHM_CL(client_idx) client_idx*(SHM_SIZE)
// FIXME: add YIELD for linux, add single-core and multi-core compile targets for optimal speed // FIXME: add YIELD for linux, add single-core and multi-core compile targets for optimal speed
#ifdef LINUX_BUILD #ifdef LINUX_BUILD
@ -79,26 +81,28 @@ struct DFPP_module
void * modulestate; void * modulestate;
}; };
typedef union union shm_cmd
{ {
struct struct
{ {
volatile uint16_t command; volatile uint16_t command;
volatile uint16_t module; volatile uint16_t module;
} parts; } parts;
volatile uint32_t pingpong; volatile uint32_t pingpong;
inline void set(uint16_t module, uint16_t command) shm_cmd(volatile uint32_t z)
{ {
pingpong = module + command << 16; pingpong = z;
} }
} shm_cmd; };
void SHM_Act (void); void SHM_Act (void);
void InitModules (void); void InitModules (void);
void KillModules (void); void KillModules (void);
bool isValidSHM(); bool isValidSHM(int current);
uint32_t OS_getPID(); uint32_t OS_getPID();
DFPP_module InitMaps(void); DFPP_module InitMaps(void);
uint32_t OS_getAffinity(); // limited to 32 processors. Silly, eh? uint32_t OS_getAffinity(); // limited to 32 processors. Silly, eh?
void OS_releaseSuspendLock(int currentClient);
void OS_lockSuspendLock(int currentClient);
#endif #endif