Merge branch 'shm-multi'

develop
Petr Mrázek 2010-03-14 23:17:54 +01:00
commit e4dc165954
14 changed files with 1219 additions and 770 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,96 +43,77 @@ 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;
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 attached; bool attached;
bool suspended; bool locked;
bool identified; bool identified;
bool useYield; bool useYield;
bool validate(char* exe_file, uint32_t pid, std::vector< memory_info* >& known_versions); bool validate(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(!attached) 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; FreeLocks();
attached = locked = identified = false;
// we aren't the current process anymore // we aren't the current process anymore
g_pProcess = NULL; g_pProcess = NULL;
FreeLocks();
throw Error::SHMServerDisappeared(); throw Error::SHMServerDisappeared();
return false;
} }
else else
{ {
@ -145,12 +126,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,9 +138,9 @@ 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);
} }
uint32_t OS_getAffinity() uint32_t OS_getAffinity()
@ -174,30 +152,13 @@ uint32_t OS_getAffinity()
return affinity; return affinity;
} }
// test if we have client and server locks and the server is present
bool SHMProcess::Private::Aux_Core_Attach(bool & versionOK, pid_t & PID)
{
SHMDATA(coreattach)->cl_affinity = OS_getAffinity();
gcc_barrier
SHMCMD = CORE_ATTACH;
if(!waitWhile(CORE_ATTACH))
return false;
gcc_barrier
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::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 +169,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,123 +194,102 @@ 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); // open the client suspend locked
return false; sprintf(name, "/tmp/DFHack/%d/CLSlock%d",process_ID,i);
} suspend_lock = open(name,O_WRONLY);
if(lockf(my_CLfileLock,F_TLOCK, 0) == -1) if(suspend_lock == -1)
{ {
// couldn't acquire lock cerr << "can't open cl S-lock " << i << endl;
close(my_SVfileLock); // couldn't open lock
close(my_CLfileLock); continue;
return false; }
// 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)
: d(new Private()) : d(new Private())
{ {
char exe_link_name [256]; d->process_ID = PID;
char target_name[1024]; if(!attach())
int target_result;
/*
* Locate the segment.
*/
if ((d->my_shmid = shmget(SHM_KEY + PID, SHM_SIZE, 0666)) < 0)
{
return;
}
/*
* Attach the segment
*/
if ((d->my_shm = (char *) shmat(d->my_shmid, NULL, 0)) == (char *) -1)
{
return;
}
// set pid and gets lock for it
d->my_pid = PID;
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;
} }
if(!bridgeOK) if(!bridgeOK)
{ {
fprintf(stderr,"SHM bridge version mismatch\n"); detach();
shmdt(d->my_shm); throw Error::SHMVersionMismatch();
// free locks
d->FreeLocks();
return;
}
// 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)
{
perror("readlink");
shmdt(d->my_shm);
// free locks
d->FreeLocks();
return;
} }
// make sure we have a null terminated string... // try to identify the DF version (md5 the binary, compare with known versions)
// see http://www.opengroup.org/onlinepubs/000095399/functions/readlink.html d->validate(known_versions);
target_name[target_result] = 0; d->window = new DFWindow(this);
// try to identify the DF version // detach
d->validate(target_name, d->my_pid, known_versions); detach();
d->my_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
d->FreeLocks();
} }
bool SHMProcess::isSuspended() bool SHMProcess::isSuspended()
{ {
return d->suspended; return d->locked;
} }
bool SHMProcess::isAttached() bool SHMProcess::isAttached()
{ {
@ -354,13 +301,28 @@ bool SHMProcess::isIdentified()
return d->identified; return d->identified;
} }
bool SHMProcess::Private::validate(char * exe_file, uint32_t pid, vector <memory_info *> & known_versions) bool SHMProcess::Private::validate(vector <memory_info *> & known_versions)
{ {
char exe_link_name [256];
char target_name[1024];
int target_result;
// find the binary
sprintf(exe_link_name,"/proc/%d/exe", process_ID);
target_result = readlink(exe_link_name, target_name, sizeof(target_name)-1);
if (target_result == -1)
{
perror("readlink");
return false;
}
// make sure we have a null terminated string...
// see http://www.opengroup.org/onlinepubs/000095399/functions/readlink.html
target_name[target_result] = 0;
md5wrapper md5; md5wrapper md5;
// get hash of the running DF process // get hash of the running DF process
string hash = md5.getHashFromFile(exe_file); string hash = md5.getHashFromFile(target_name);
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 +330,9 @@ 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;
identified = true; identified = true;
cerr << "identified " << m->getVersion() << endl; // cerr << "identified " << m->getVersion() << endl;
return true; return true;
} }
} }
@ -390,31 +351,37 @@ 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 // there is only one we care about.
bool SHMProcess::getThreadIDs(vector<uint32_t> & threads ) bool SHMProcess::getThreadIDs(vector<uint32_t> & threads )
{ {
if(d->attached)
{
threads.clear();
threads.push_back(d->process_ID);
return true;
}
return false; return false;
} }
@ -424,7 +391,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;
@ -451,37 +418,79 @@ bool SHMProcess::suspend()
{ {
return false; return false;
} }
if(d->suspended) if(d->locked)
{ {
return true; return true;
} }
D_SHMCMD = CORE_SUSPEND;
if(!waitWhile(CORE_SUSPEND)) // FIXME: this should be controlled on the server side
// FIXME: IF server got CORE_RUN in this frame, interpret CORE_SUSPEND as CORE_STEP
// did we just resume a moment ago?
if(D_SHMCMD == CORE_RUN)
{
//fprintf(stderr,"%d invokes step\n",d->attachmentIdx);
// wait for the next window
if(!d->SetAndWait(CORE_STEP))
{
throw Error::SHMLockingError("if(!d->SetAndWait(CORE_STEP))");
}
}
else
{ {
return false; //fprintf(stderr,"%d invokes suspend\n",d->attachmentIdx);
// lock now
if(!d->SetAndWait(CORE_SUSPEND))
{
throw Error::SHMLockingError("if(!d->SetAndWait(CORE_SUSPEND))");
}
} }
d->suspended = true; //fprintf(stderr,"waiting for lock\n");
return true; // we wait for the server to give up our suspend lock (held by default)
if(lockf(d->suspend_lock,F_LOCK,0) == 0)
{
d->locked = true;
return true;
}
return false;
} }
// FIXME: needs a good think-through
bool SHMProcess::asyncSuspend() bool SHMProcess::asyncSuspend()
{ {
if(!d->attached) if(!d->attached)
{ {
return false; return false;
} }
if(d->suspended) if(d->locked)
{ {
return true; return true;
} }
if(D_SHMCMD == CORE_SUSPENDED) uint32_t cmd = D_SHMCMD;
if(cmd == 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;
return true;
}
return false;
} }
else else
{ {
D_SHMCMD = CORE_SUSPEND; // did we just resume a moment ago?
if(cmd == CORE_STEP)
{
return false;
}
else if(cmd == CORE_RUN)
{
D_SHMCMD = CORE_STEP;
}
else
{
D_SHMCMD = CORE_SUSPEND;
}
return false; return false;
} }
} }
@ -491,21 +500,30 @@ 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->locked)
return true; return true;
D_SHMCMD = CORE_RUNNING; // unlock the suspend lock
d->suspended = false; if(lockf(d->suspend_lock,F_ULOCK,0) == 0)
return true; {
d->locked = false;
if(d->SetAndWait(CORE_RUN)) // we have to make sure the server responds!
{
return true;
}
throw Error::SHMLockingError("if(d->SetAndWait(CORE_RUN))");
}
throw Error::SHMLockingError("if(lockf(d->suspend_lock,F_ULOCK,0) == 0)");
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
@ -514,31 +532,39 @@ bool SHMProcess::attach()
} }
if(!d->GetLocks()) if(!d->GetLocks())
{ {
cerr << "server is full or not really there!" << endl; //cerr << "server is full or not really there!" << endl;
return false; return false;
} }
/*
* Locate the segment.
*/
if ((d->shm_ID = shmget(SHM_KEY + d->process_ID, SHM_SIZE, 0666)) < 0)
{
d->FreeLocks();
cerr << "can't find segment" << endl; // FIXME: throw
return false;
}
/* /*
* 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;
if(suspend())
{
d->suspended = true;
g_pProcess = this;
return true;
}
d->attached = false;
cerr << "unable to suspend" << endl;
shmdt(d->my_shm);
d->FreeLocks(); d->FreeLocks();
cerr << "can't attach segment" << endl; // FIXME: throw
return false; return false;
} }
cerr << "unable to attach" << endl; d->attached = true;
d->FreeLocks(); if(!suspend())
return false; {
shmdt(d->shm_addr);
d->FreeLocks();
cerr << "unable to suspend" << endl;
return false;
}
g_pProcess = this;
return true;
} }
bool SHMProcess::detach() bool SHMProcess::detach()
@ -547,18 +573,18 @@ bool SHMProcess::detach()
{ {
return false; return false;
} }
if(d->suspended) if(d->locked)
{ {
resume(); resume();
} }
// detach segment // detach segment
if(shmdt(d->my_shm) != -1) if(shmdt(d->shm_addr) != -1)
{ {
d->FreeLocks();
d->locked = false;
d->attached = false; d->attached = false;
d->suspended = false; d->shm_addr = 0;
d->my_shm = 0;
g_pProcess = 0; g_pProcess = 0;
d->FreeLocks();
return true; return true;
} }
// fail if we can't detach // fail if we can't detach
@ -569,15 +595,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 +617,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 +632,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 +695,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 +747,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 +764,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 +783,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 +801,42 @@ 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); return(string( D_SHMDATA(char) ));
//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) 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 +845,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 +871,26 @@ 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;
}
bool SHMProcess::Private::Aux_Core_Attach(bool & versionOK, pid_t & PID)
{
if(!locked) throw Error::SHMAccessDenied();
SHMDATA(coreattach)->cl_affinity = OS_getAffinity();
if(!SetAndWait(CORE_ATTACH)) return false;
/*
cerr <<"CORE_VERSION" << CORE_VERSION << endl;
cerr <<"server CORE_VERSION" << SHMDATA(coreattach)->sv_version << endl;
*/
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;
} }

File diff suppressed because it is too large Load Diff

@ -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
} }

Binary file not shown.

Binary file not shown.

@ -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 SHMCMD ((uint32_t *)shm )[currentClient]
#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,17 @@ void FindCommand (void * data)
SHMHDR->error = true; SHMHDR->error = true;
} }
void ReleaseSuspendLock( void * data )
{
OS_releaseSuspendLock(currentClient);
}
void AcquireSuspendLock( void * data )
{
OS_lockSuspendLock(currentClient);
}
DFPP_module InitCore(void) DFPP_module InitCore(void)
{ {
DFPP_module core; DFPP_module core;
@ -185,7 +199,10 @@ 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!",AcquireSuspendLock,CORE_RUNNING);
core.set_command(CORE_RUN, CANCELLATION, "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 +212,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 +250,90 @@ 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
SHMCMD = 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 = SHMCMD;
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) {
/*
char text [512];
char text2 [512];
sprintf (text,"Client %d invoked %d:%d = %x = %s\n",currentClient,((shm_cmd)atomic).parts.module,((shm_cmd)atomic).parts.command, cmd._function,cmd.name.c_str());
sprintf(text2, "Server set %d\n",cmd.nextState);
*/
// FIXME: WHAT HAPPENS WHEN A 'NEXTSTATE' IS FROM A DIFFERENT MODULE THAN 'CORE'? Yeah. It doesn't work.
SHMCMD = cmd.nextState;
//MessageBox(0,text,text2, MB_OK);
//fflush(stderr); // make sure this finds its way to the terminal!
}
full_barrier
if(cmd.type != CANCELLATION)
{ {
SCHED_YIELD if(useYield)
{
SCHED_YIELD
}
numwaits ++; // watchdog timeout
goto check_again;
} }
numwaits ++; // watchdog timeout full_barrier
goto check_again;
// 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++)
{
((uint32_t *)shm)[i] = 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();
} }

@ -44,8 +44,65 @@ char *shm = 0;
int shmid = 0; int shmid = 0;
bool inited = 0; bool inited = 0;
HANDLE shmHandle = 0; HANDLE shmHandle = 0;
HANDLE DFSVMutex = 0; HANDLE DFSVMutex = 0;
HANDLE DFCLMutex = 0; HANDLE DFCLMutex[SHM_MAX_CLIENTS];
HANDLE DFCLSuspendMutex[SHM_MAX_CLIENTS];
int held_DFCLSuspendMutex[SHM_MAX_CLIENTS];
int numheld = SHM_MAX_CLIENTS;
void OS_lockSuspendLock(int which)
{
if(numheld == SHM_MAX_CLIENTS)
return;
// lock not held by server and can be picked up. OK.
if(held_DFCLSuspendMutex[which] == 0)
{
uint32_t state = WaitForSingleObject(DFCLSuspendMutex[which],INFINITE);
if(state == WAIT_ABANDONED || state == WAIT_OBJECT_0)
{
held_DFCLSuspendMutex[which] = 1;
numheld++;
return;
}
// lock couldn't be picked up!
errorstate = 1;
MessageBox(0,"Suspend lock locking failed. Further communication disabled!","Error", MB_OK);
return;
}
errorstate = 1;
MessageBox(0,"Server tried to lock already locked suspend lock? Further communication disabled!","Error", MB_OK);
return;
}
void OS_releaseSuspendLock(int which)
{
/*
if(which >=0 && which < SHM_MAX_CLIENTS)
return;
*/
if(numheld != SHM_MAX_CLIENTS)
{
MessageBox(0,"Locking system failure. Further communication disabled!","Error", MB_OK);
errorstate = 1;
return;
}
// lock hel by server and can be released -> OK
if(held_DFCLSuspendMutex[which] == 1 && ReleaseMutex(DFCLSuspendMutex[which]))
{
numheld--;
held_DFCLSuspendMutex[which] = 0;
}
// locked and not can't be released? FAIL!
else if (held_DFCLSuspendMutex[which] == 1)
{
MessageBox(0,"Suspend lock failed to unlock. Further communication disabled!","Error", MB_OK);
return;
}
}
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
@ -56,66 +113,48 @@ void SHM_Init ( void )
} }
inited = true; inited = true;
char svmutexname [256];
sprintf(svmutexname,"DFSVMutex-%d",OS_getPID());
char clmutexname [256]; char clmutexname [256];
sprintf(clmutexname,"DFCLMutex-%d",OS_getPID()); char clsmutexname [256];
char shmname [256]; char shmname [256];
sprintf(shmname,"DFShm-%d",OS_getPID()); sprintf(shmname,"DFShm-%d",OS_getPID());
// create or open mutexes // create a locked server mutex
char svmutexname [256];
sprintf(svmutexname,"DFSVMutex-%d",OS_getPID());
DFSVMutex = CreateMutex( 0, 1, svmutexname); DFSVMutex = CreateMutex( 0, 1, svmutexname);
if(DFSVMutex == 0) if(DFSVMutex == 0)
{ {
DFSVMutex = OpenMutex(SYNCHRONIZE,false, svmutexname); MessageBox(0,"Server mutex creation failed. Further communication disabled!","Error", MB_OK);
if(DFSVMutex == 0) errorstate = 1;
{ return;
errorstate = 1;
return;
}
} }
DFCLMutex = CreateMutex( 0, 0, clmutexname); // the mutex already existed. we don't want to know.
if(DFCLMutex == 0) if(GetLastError() == ERROR_ALREADY_EXISTS)
{ {
DFCLMutex = OpenMutex(SYNCHRONIZE,false, clmutexname); MessageBox(0,"Server mutex already existed. Further communication disabled!","Error", MB_OK);
if(DFCLMutex == 0) errorstate = 1;
{ return;
CloseHandle(DFSVMutex);
errorstate = 1;
return;
}
} }
// try locking server mutex // create client and suspend mutexes
uint32_t result; for(int i = 0; i < SHM_MAX_CLIENTS; i++)
result = WaitForSingleObject(DFSVMutex,0);
switch (result)
{ {
case WAIT_ABANDONED: sprintf(clmutexname,"DFCLMutex-%d-%d",OS_getPID(),i);
sprintf(clsmutexname,"DFCLSuspendMutex-%d-%d",OS_getPID(),i);
DFCLMutex[i] = CreateMutex( 0, 0, clmutexname); // client mutex, not held
DFCLSuspendMutex[i] = CreateMutex( 0, 1, clsmutexname); // suspend mutexes held on start
held_DFCLSuspendMutex[i] = 1;
if(DFCLMutex[i] == 0 || DFCLSuspendMutex[i] == 0 || GetLastError() == ERROR_ALREADY_EXISTS)
{ {
// picked up after a crashed DF process MessageBox(0,"Client mutex creation failed. Close all tools before starting DF.","Error", MB_OK);
// do some sanity checks on client attached
// otherwise the same thing as WAIT_OBJECT_0
break;
}
case WAIT_OBJECT_0:
{
// all right, we have the mutex and are the one and only DF server
break;
}
case WAIT_TIMEOUT:
case WAIT_FAILED:
default:
{
// error, bail
errorstate = 1; errorstate = 1;
MessageBox(0,"Could not aquire mutex","Error", MB_OK);
CloseHandle(DFSVMutex);
CloseHandle(DFCLMutex);
return; return;
} }
} }
// 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_SIZE,shmname);
// if can't create or already exists -> nothing happens // if can't create or already exists -> nothing happens
@ -123,35 +162,32 @@ void SHM_Init ( void )
{ {
MessageBox(0,"SHM bridge already in use","Error", MB_OK); MessageBox(0,"SHM bridge already in use","Error", MB_OK);
errorstate = 1; errorstate = 1;
ReleaseMutex(DFSVMutex);
CloseHandle(DFSVMutex);
CloseHandle(DFCLMutex);
return; return;
} }
if(!shmHandle) if(!shmHandle)
{ {
MessageBox(0,"Couldn't create SHM bridge","Error", MB_OK); MessageBox(0,"Couldn't create SHM bridge","Error", MB_OK);
errorstate = 1; errorstate = 1;
ReleaseMutex(DFSVMutex);
CloseHandle(DFSVMutex);
CloseHandle(DFCLMutex);
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_SIZE);
if(shm) if(shm)
{ {
((shm_cmd *)shm)->pingpong = CORE_RUNNING; // make sure we don't stall or do crazy stuff
for(int i = 0; i < SHM_MAX_CLIENTS;i++)
{
((uint32_t *)shm)[i] = CORE_RUNNING;
}
// init modules :)
InitModules();
} }
else else
{ {
MessageBox(0,"Couldn't attach SHM bridge","Error", MB_OK); MessageBox(0,"Couldn't attach SHM bridge","Error", MB_OK);
errorstate = 1; errorstate = 1;
ReleaseMutex(DFSVMutex); return;
CloseHandle(DFSVMutex);
CloseHandle(DFCLMutex);
} }
InitModules();
} }
void SHM_Destroy ( void ) void SHM_Destroy ( void )
@ -159,9 +195,13 @@ void SHM_Destroy ( void )
if(errorstate) if(errorstate)
return; return;
KillModules(); KillModules();
ReleaseMutex(DFSVMutex); // get rid of all the locks
CloseHandle(DFSVMutex); CloseHandle(DFSVMutex);
CloseHandle(DFCLMutex); for(int i=0; i < SHM_MAX_CLIENTS; i++)
{
CloseHandle(DFCLSuspendMutex[i]);
CloseHandle(DFCLMutex[i]);
}
} }
uint32_t OS_getPID() uint32_t OS_getPID()
@ -181,17 +221,18 @@ uint32_t OS_getAffinity()
// is the other side still there? // is the other side still there?
bool isValidSHM() bool isValidSHM(int which)
{ {
// try if CL mutex is free // try if CL mutex is free (by locking client mutex)
uint32_t result = WaitForSingleObject(DFCLMutex,0); uint32_t result = WaitForSingleObject(DFCLMutex[which],0);
switch (result) switch (result)
{ {
case WAIT_ABANDONED: case WAIT_ABANDONED:
case WAIT_OBJECT_0: case WAIT_OBJECT_0:
{ {
ReleaseMutex(DFCLMutex); OS_lockSuspendLock(which);
ReleaseMutex(DFCLMutex[which]);
return false; return false;
} }
case WAIT_TIMEOUT: case WAIT_TIMEOUT:

@ -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