Stop synchronous suspend from eating CPU cycles.

Untested on windows.
Breaks the SHM protocol. New SHM server library is required.
develop
Petr Mrázek 2010-03-18 19:55:01 +01:00
parent e18828e466
commit d2afd21318
5 changed files with 96 additions and 63 deletions

@ -26,7 +26,7 @@ int main (void)
cerr << e.what() << endl;
return 1;
}
/*
// attach/detach test
cout << "Testing attach/detach" << endl;
time(&start);
@ -62,7 +62,7 @@ int main (void)
time_diff = difftime(end, start);
cout << "attach tests done in " << time_diff << " seconds." << endl;
*/
cout << "Testing suspend/resume" << endl;
DF.Attach();
time(&start);

@ -275,9 +275,9 @@ main(int argc, char *argv[])
DFHack::t_designation designations[16][16];
uint8_t regionoffsets[16];
*/
mapblock40d Block;
map <int16_t, uint32_t> materials;
materials.clear();
mapblock40d blocks[3][3];
vector<DFHack::t_matgloss> stonetypes;
vector< vector <uint16_t> > layerassign;
vector<t_vein> veinVector;
@ -338,13 +338,16 @@ main(int argc, char *argv[])
bool dirtybit = false;
uint32_t blockaddr = 0;
uint32_t blockaddr2 = 0;
// walk the map!
// resume so we don't block DF while we wait for input
DF.Resume();
for (;;)
{
dig = false;
dump = false;
digbit = false;
DF.Resume();
int c = getch(); /* refresh, accept single keystroke of input */
clrscr();
/* process the command keystroke */
@ -394,71 +397,80 @@ main(int argc, char *argv[])
cursorY = min(cursorY, y_max - 1);
cursorZ = min(cursorZ, z_max - 1);
// clear data before we suspend
memset(blocks,0,sizeof(blocks));
veinVector.clear();
IceVeinVector.clear();
dirtybit = 0;
// Supend, read/write data
DF.Suspend();
for(int i = -1; i <= 1; i++)
for(int i = -1; i <= 1; i++) for(int j = -1; j <= 1; j++)
{
for(int j = -1; j <= 1; j++)
mapblock40d * Block = &blocks[i+1][j+1];
if(DF.isValidBlock(cursorX+i,cursorY+j,cursorZ))
{
if(DF.isValidBlock(cursorX+i,cursorY+j,cursorZ))
DF.ReadBlock40d(cursorX+i,cursorY+j,cursorZ, Block);
// extra processing of the block in the middle
if(i == 0 && j == 0)
{
// read data
DF.ReadBlock40d(cursorX+i,cursorY+j,cursorZ, &Block);
/*
DF.ReadTileTypes(cursorX+i,cursorY+j,cursorZ, (uint16_t *) tiletypes);
DF.ReadDesignations(cursorX+i,cursorY+j,cursorZ, (uint32_t *) designations);
*/
for(int x = 0; x < 16; x++)
// read veins
DF.ReadVeins(cursorX+i,cursorY+j,cursorZ,veinVector,IceVeinVector);
// get pointer to block
blockaddr = DF.getBlockPtr(cursorX+i,cursorY+j,cursorZ);
blockaddr2 = Block->origin;
// dig all veins and trees
if(dig)
{
for(int y = 0; y < 16; y++)
for(int x = 0; x < 16; x++) for(int y = 0; y < 16; y++)
{
if(dig)
TileClass tc = tileTypeTable[Block->tiletypes[x][y]].c;
TileMaterial tm = tileTypeTable[Block->tiletypes[x][y]].m;
if( tc == WALL && tm == VEIN || tc == TREE_OK || tc == TREE_DEAD)
{
TileClass tc = tileTypeTable[Block.tiletypes[x][y]].c;
TileMaterial tm = tileTypeTable[Block.tiletypes[x][y]].m;
if( tc == WALL && tm == VEIN || tc == TREE_OK || tc == TREE_DEAD)
{
Block.designaton[x][y].bits.dig = designation_default;
}
}
int color = COLOR_BLACK;
color = pickColor(Block.tiletypes[x][y]);
if(Block.designaton[x][y].bits.hidden)
{
puttile(x+(i+1)*16,y+(j+1)*16,Block.tiletypes[x][y], color);
}
else
{
attron(A_STANDOUT);
puttile(x+(i+1)*16,y+(j+1)*16,Block.tiletypes[x][y], color);
attroff(A_STANDOUT);
Block->designaton[x][y].bits.dig = designation_default;
}
}
DF.WriteDesignations(cursorX+i,cursorY+j,cursorZ, (uint32_t *) Block->designaton);
}
if(i == 0 && j == 0)
// do a dump of the block data
if(dump)
{
blockaddr = DF.getBlockPtr(cursorX+i,cursorY+j,cursorZ);
blockaddr2 = Block.origin;
if(dump)
{
hexdump(DF,blockaddr,0x1E00,filenum);
filenum++;
}
if(dig)
DF.WriteDesignations(cursorX+i,cursorY+j,cursorZ, (uint32_t *) Block.designaton);
DF.ReadDirtyBit(cursorX+i,cursorY+j,cursorZ,dirtybit);
if(digbit)
{
dirtybit = !dirtybit;
DF.WriteDirtyBit(cursorX+i,cursorY+j,cursorZ,dirtybit);
}
veinVector.clear();
IceVeinVector.clear();
DF.ReadVeins(cursorX+i,cursorY+j,cursorZ,veinVector,IceVeinVector);
hexdump(DF,blockaddr,0x1E00,filenum);
filenum++;
}
// read/write dirty bit of the block
DF.ReadDirtyBit(cursorX+i,cursorY+j,cursorZ,dirtybit);
if(digbit)
{
dirtybit = !dirtybit;
DF.WriteDirtyBit(cursorX+i,cursorY+j,cursorZ,dirtybit);
}
}
}
}
// Resume, print stuff to the terminal
DF.Resume();
for(int i = -1; i <= 1; i++) for(int j = -1; j <= 1; j++)
{
mapblock40d * Block = &blocks[i+1][j+1];
for(int x = 0; x < 16; x++) for(int y = 0; y < 16; y++)
{
int color = COLOR_BLACK;
color = pickColor(Block->tiletypes[x][y]);
if(Block->designaton[x][y].bits.hidden)
{
puttile(x+(i+1)*16,y+(j+1)*16,Block->tiletypes[x][y], color);
}
else
{
attron(A_STANDOUT);
puttile(x+(i+1)*16,y+(j+1)*16,Block->tiletypes[x][y], color);
attroff(A_STANDOUT);
}
}
}

@ -429,20 +429,26 @@ bool SHMProcess::suspend()
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))");
}
*/
D_SHMCMD = CORE_STEP;
}
else
{
//fprintf(stderr,"%d invokes suspend\n",d->attachmentIdx);
// lock now
/*
if(!d->SetAndWait(CORE_SUSPEND))
{
throw Error::SHMLockingError("if(!d->SetAndWait(CORE_SUSPEND))");
}
*/
D_SHMCMD = CORE_SUSPEND;
}
//fprintf(stderr,"waiting for lock\n");
// we wait for the server to give up our suspend lock (held by default)

@ -202,7 +202,7 @@ DFPP_module InitCore(void)
//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_SUSPEND, FUNCTION, "Suspend", ReleaseSuspendLock , CORE_SUSPENDED, LOCKING_LOCKS);
core.set_command(CORE_SUSPENDED, CLIENT_WAIT, "Suspended");
core.set_command(CORE_ERROR, CANCELLATION, "Error");
@ -298,13 +298,20 @@ void SHM_Act (void)
}
full_barrier
*/
// set next state BEFORE we act on the command - good for locks
if(cmd.locking == LOCKING_LOCKS)
{
if(cmd.nextState != -1) SHMCMD = cmd.nextState;
}
if(cmd._function)
{
cmd._function(mod.modulestate);
}
full_barrier
if(cmd.nextState != -1)
// set next state AFTER we act on the command - good for busy waits
if(cmd.locking == LOCKING_BUSY)
{
/*
char text [512];
@ -313,7 +320,7 @@ void SHM_Act (void)
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;
if(cmd.nextState != -1) SHMCMD = cmd.nextState;
//MessageBox(0,text,text2, MB_OK);
//fflush(stderr); // make sure this finds its way to the terminal!

@ -31,6 +31,12 @@
#endif
#endif
enum DFPP_Locking
{
LOCKING_BUSY = 0,
LOCKING_LOCKS = 1
};
enum DFPP_CmdType
{
CANCELLATION, // we should jump out of the Act()
@ -44,6 +50,7 @@ struct DFPP_command
DFPP_CmdType type:32; // force the enum to 32 bits for compatibility reasons
std::string name;
uint32_t nextState;
DFPP_Locking locking;
};
struct DFPP_module
@ -62,12 +69,13 @@ struct DFPP_module
modulestate = orig.modulestate;
version = orig.version;
}
inline void set_command(const unsigned int index, const DFPP_CmdType type, const char * name, void (*_function)(void *) = 0,uint32_t nextState = -1)
inline void set_command(const unsigned int index, const DFPP_CmdType type, const char * name, void (*_function)(void *) = 0,uint32_t nextState = -1, DFPP_Locking locking = LOCKING_BUSY)
{
commands[index].type = type;
commands[index].name = name;
commands[index]._function = _function;
commands[index].nextState = nextState;
commands[index].locking = locking;
}
inline void reserve (unsigned int numcommands)
{