use of memory barriers in the shm server and client code

develop
Petr Mrázek 2009-12-27 03:51:54 +00:00
parent b0d65de269
commit aef02eddce
10 changed files with 232 additions and 30 deletions

@ -969,6 +969,10 @@ bool API::Attach()
{ {
d->pm = new ProcessEnumerator (d->xml); // FIXME: handle bad XML better d->pm = new ProcessEnumerator (d->xml); // FIXME: handle bad XML better
} }
else
{
d->pm->purge();
}
// find a process (ProcessManager can find multiple when used properly) // find a process (ProcessManager can find multiple when used properly)
if (!d->pm->findProcessess()) if (!d->pm->findProcessess())

@ -28,8 +28,50 @@ distribution.
#include <sys/ipc.h> #include <sys/ipc.h>
#include <time.h> #include <time.h>
#include "shmserver/dfconnect.h" #include "shmserver/dfconnect.h"
#include <sys/time.h>
#include <time.h>
#include <linux/futex.h>
#include <sys/syscall.h>
using namespace DFHack; using namespace DFHack;
// a full memory barrier! better be safe than sorry.
#define gcc_barrier asm volatile("" ::: "memory"); __sync_synchronize();
/*
* wait for futex
* futex has to be aligned to 4 bytes
* futex has to be equal to val (returns EWOULDBLOCK otherwise)
* wait can be broken by arriving signals (returns EINTR)
* returns 0 when broken by futex_wake
*/
inline int futex_wait(int * futex, int val)
{
return syscall(SYS_futex, futex, FUTEX_WAIT, val, 0, 0, 0);
}
/*
* wait for futex
* futex has to be aligned to 4 bytes
* futex has to be equal to val (returns EWOULDBLOCK otherwise)
* wait can be broken by arriving signals (returns EINTR)
* returns 0 when broken by futex_wake
* returns ETIMEDOUT on timeout
*/
inline int futex_wait_timed(int * futex, int val, const struct timespec *timeout)
{
return syscall(SYS_futex, futex, FUTEX_WAIT, val, timeout, 0, 0);
}
/*
* wake up futex. returns number of waked processes
*/
inline int futex_wake(int * futex)
{
return syscall(SYS_futex, futex, FUTEX_WAKE, 1, 0, 0, 0);
}
static timespec one_second = { 1,0 };
static timespec five_second = { 5,0 };
class SHMProcess::Private class SHMProcess::Private
{ {
public: public:
@ -38,6 +80,8 @@ class SHMProcess::Private
my_datamodel = NULL; my_datamodel = NULL;
my_descriptor = NULL; my_descriptor = NULL;
my_pid = 0; my_pid = 0;
my_shm = 0;
my_shmid = -1;
my_window = NULL; my_window = NULL;
attached = false; attached = false;
suspended = false; suspended = false;
@ -54,6 +98,7 @@ class SHMProcess::Private
bool attached; bool attached;
bool suspended; bool suspended;
bool identified; bool identified;
bool validate(char * exe_file, uint32_t pid, vector <memory_info> & known_versions); bool validate(char * exe_file, uint32_t pid, vector <memory_info> & known_versions);
bool waitWhile (DF_PINGPONG state); bool waitWhile (DF_PINGPONG state);
bool DF_TestBridgeVersion(bool & ret); bool DF_TestBridgeVersion(bool & ret);
@ -71,6 +116,7 @@ bool SHMProcess::Private::waitWhile (DF_PINGPONG state)
shmctl(my_shmid, IPC_STAT, &descriptor); shmctl(my_shmid, IPC_STAT, &descriptor);
if(descriptor.shm_nattch == 1)// DF crashed? if(descriptor.shm_nattch == 1)// DF crashed?
{ {
gcc_barrier
((shm_cmd *)my_shm)->pingpong = DFPP_RUNNING; ((shm_cmd *)my_shm)->pingpong = DFPP_RUNNING;
attached = suspended = false; attached = suspended = false;
return false; return false;
@ -96,8 +142,10 @@ bool SHMProcess::Private::waitWhile (DF_PINGPONG state)
bool SHMProcess::Private::DF_TestBridgeVersion(bool & ret) bool SHMProcess::Private::DF_TestBridgeVersion(bool & ret)
{ {
((shm_cmd *)my_shm)->pingpong = DFPP_VERSION; ((shm_cmd *)my_shm)->pingpong = DFPP_VERSION;
gcc_barrier
if(!waitWhile(DFPP_VERSION)) if(!waitWhile(DFPP_VERSION))
return false; return false;
gcc_barrier
((shm_cmd *)my_shm)->pingpong = DFPP_SUSPENDED; ((shm_cmd *)my_shm)->pingpong = DFPP_SUSPENDED;
ret =( ((shm_retval *)my_shm)->value == PINGPONG_VERSION ); ret =( ((shm_retval *)my_shm)->value == PINGPONG_VERSION );
return true; return true;
@ -106,8 +154,10 @@ bool SHMProcess::Private::DF_TestBridgeVersion(bool & ret)
bool SHMProcess::Private::DF_GetPID(pid_t & ret) bool SHMProcess::Private::DF_GetPID(pid_t & ret)
{ {
((shm_cmd *)my_shm)->pingpong = DFPP_PID; ((shm_cmd *)my_shm)->pingpong = DFPP_PID;
gcc_barrier
if(!waitWhile(DFPP_PID)) if(!waitWhile(DFPP_PID))
return false; return false;
gcc_barrier
((shm_cmd *)my_shm)->pingpong = DFPP_SUSPENDED; ((shm_cmd *)my_shm)->pingpong = DFPP_SUSPENDED;
ret = ((shm_retval *)my_shm)->value; ret = ((shm_retval *)my_shm)->value;
return true; return true;
@ -139,11 +189,12 @@ SHMProcess::SHMProcess(vector <memory_info> & known_versions)
/* /*
* Check if there are two processes connected to the segment * Check if there are two processes connected to the segment
*/ */
struct shmid_ds descriptor; shmid_ds descriptor;
shmctl(d->my_shmid, IPC_STAT, &descriptor); shmctl(d->my_shmid, IPC_STAT, &descriptor);
if(descriptor.shm_nattch != 2)// badness if(descriptor.shm_nattch != 2)// badness
{ {
fprintf(stderr,"dfhack: no DF or different client already connected\n"); fprintf(stderr,"dfhack: %d : invalid no. of processes connected\n", descriptor.shm_nattch);
fprintf(stderr,"detach: %d",shmdt(d->my_shm));
return; return;
} }
@ -182,8 +233,10 @@ SHMProcess::SHMProcess(vector <memory_info> & known_versions)
d->validate(target_name, d->my_pid, known_versions); d->validate(target_name, d->my_pid, known_versions);
d->my_window = new DFWindow(this); d->my_window = new DFWindow(this);
} }
gcc_barrier
// at this point, DF is stopped and waiting for commands. make it run again // at this point, DF is stopped and waiting for commands. make it run again
((shm_cmd *)d->my_shm)->pingpong = DFPP_RUNNING; ((shm_cmd *)d->my_shm)->pingpong = DFPP_RUNNING;
fprintf(stderr,"detach: %d",shmdt(d->my_shm));
} }
bool SHMProcess::isSuspended() bool SHMProcess::isSuspended()
@ -239,6 +292,10 @@ SHMProcess::~SHMProcess()
{ {
delete d->my_window; delete d->my_window;
} }
if(d->my_shm)
{
fprintf(stderr,"detach: %d",shmdt(d->my_shm));
}
delete d; delete d;
} }
@ -341,6 +398,11 @@ bool SHMProcess::attach()
cerr << "there's already a different process attached" << endl; cerr << "there's already a different process attached" << endl;
return false; return false;
} }
/*
* Attach the segment
*/
if ((d->my_shm = (char *) shmat(d->my_shmid, NULL, 0)) != (char *) -1)
{
d->attached = true; d->attached = true;
if(suspend()) if(suspend())
{ {
@ -352,6 +414,9 @@ bool SHMProcess::attach()
cerr << "unable to suspend" << endl; cerr << "unable to suspend" << endl;
return false; return false;
} }
cerr << "unable to attach" << endl;
return false;
}
bool SHMProcess::detach() bool SHMProcess::detach()
{ {
@ -375,6 +440,7 @@ void SHMProcess::read (const uint32_t offset, const uint32_t size, uint8_t *targ
assert (size < (SHM_SIZE - sizeof(shm_read))); assert (size < (SHM_SIZE - sizeof(shm_read)));
((shm_read *)d->my_shm)->address = offset; ((shm_read *)d->my_shm)->address = offset;
((shm_read *)d->my_shm)->length = size; ((shm_read *)d->my_shm)->length = size;
gcc_barrier
((shm_read *)d->my_shm)->pingpong = DFPP_READ; ((shm_read *)d->my_shm)->pingpong = DFPP_READ;
d->waitWhile(DFPP_READ); d->waitWhile(DFPP_READ);
memcpy (target, d->my_shm + sizeof(shm_ret_data),size); memcpy (target, d->my_shm + sizeof(shm_ret_data),size);
@ -383,6 +449,7 @@ void SHMProcess::read (const uint32_t offset, const uint32_t size, uint8_t *targ
uint8_t SHMProcess::readByte (const uint32_t offset) uint8_t SHMProcess::readByte (const uint32_t offset)
{ {
((shm_read_small *)d->my_shm)->address = offset; ((shm_read_small *)d->my_shm)->address = offset;
gcc_barrier
((shm_read_small *)d->my_shm)->pingpong = DFPP_READ_BYTE; ((shm_read_small *)d->my_shm)->pingpong = DFPP_READ_BYTE;
d->waitWhile(DFPP_READ_BYTE); d->waitWhile(DFPP_READ_BYTE);
return ((shm_retval *)d->my_shm)->value; return ((shm_retval *)d->my_shm)->value;
@ -391,6 +458,7 @@ uint8_t SHMProcess::readByte (const uint32_t offset)
void SHMProcess::readByte (const uint32_t offset, uint8_t &val ) void SHMProcess::readByte (const uint32_t offset, uint8_t &val )
{ {
((shm_read_small *)d->my_shm)->address = offset; ((shm_read_small *)d->my_shm)->address = offset;
gcc_barrier
((shm_read_small *)d->my_shm)->pingpong = DFPP_READ_BYTE; ((shm_read_small *)d->my_shm)->pingpong = DFPP_READ_BYTE;
d->waitWhile(DFPP_READ_BYTE); d->waitWhile(DFPP_READ_BYTE);
val = ((shm_retval *)d->my_shm)->value; val = ((shm_retval *)d->my_shm)->value;
@ -399,6 +467,7 @@ void SHMProcess::readByte (const uint32_t offset, uint8_t &val )
uint16_t SHMProcess::readWord (const uint32_t offset) uint16_t SHMProcess::readWord (const uint32_t offset)
{ {
((shm_read_small *)d->my_shm)->address = offset; ((shm_read_small *)d->my_shm)->address = offset;
gcc_barrier
((shm_read_small *)d->my_shm)->pingpong = DFPP_READ_WORD; ((shm_read_small *)d->my_shm)->pingpong = DFPP_READ_WORD;
d->waitWhile(DFPP_READ_WORD); d->waitWhile(DFPP_READ_WORD);
return ((shm_retval *)d->my_shm)->value; return ((shm_retval *)d->my_shm)->value;
@ -407,6 +476,7 @@ uint16_t SHMProcess::readWord (const uint32_t offset)
void SHMProcess::readWord (const uint32_t offset, uint16_t &val) void SHMProcess::readWord (const uint32_t offset, uint16_t &val)
{ {
((shm_read_small *)d->my_shm)->address = offset; ((shm_read_small *)d->my_shm)->address = offset;
gcc_barrier
((shm_read_small *)d->my_shm)->pingpong = DFPP_READ_WORD; ((shm_read_small *)d->my_shm)->pingpong = DFPP_READ_WORD;
d->waitWhile(DFPP_READ_WORD); d->waitWhile(DFPP_READ_WORD);
val = ((shm_retval *)d->my_shm)->value; val = ((shm_retval *)d->my_shm)->value;
@ -415,6 +485,7 @@ void SHMProcess::readWord (const uint32_t offset, uint16_t &val)
uint32_t SHMProcess::readDWord (const uint32_t offset) uint32_t SHMProcess::readDWord (const uint32_t offset)
{ {
((shm_read_small *)d->my_shm)->address = offset; ((shm_read_small *)d->my_shm)->address = offset;
gcc_barrier
((shm_read_small *)d->my_shm)->pingpong = DFPP_READ_DWORD; ((shm_read_small *)d->my_shm)->pingpong = DFPP_READ_DWORD;
d->waitWhile(DFPP_READ_DWORD); d->waitWhile(DFPP_READ_DWORD);
return ((shm_retval *)d->my_shm)->value; return ((shm_retval *)d->my_shm)->value;
@ -422,6 +493,7 @@ uint32_t SHMProcess::readDWord (const uint32_t offset)
void SHMProcess::readDWord (const uint32_t offset, uint32_t &val) void SHMProcess::readDWord (const uint32_t offset, uint32_t &val)
{ {
((shm_read_small *)d->my_shm)->address = offset; ((shm_read_small *)d->my_shm)->address = offset;
gcc_barrier
((shm_read_small *)d->my_shm)->pingpong = DFPP_READ_DWORD; ((shm_read_small *)d->my_shm)->pingpong = DFPP_READ_DWORD;
d->waitWhile(DFPP_READ_DWORD); d->waitWhile(DFPP_READ_DWORD);
val = ((shm_retval *)d->my_shm)->value; val = ((shm_retval *)d->my_shm)->value;
@ -435,6 +507,7 @@ void SHMProcess::writeDWord (uint32_t offset, uint32_t data)
{ {
((shm_write_small *)d->my_shm)->address = offset; ((shm_write_small *)d->my_shm)->address = offset;
((shm_write_small *)d->my_shm)->value = data; ((shm_write_small *)d->my_shm)->value = data;
gcc_barrier
((shm_write_small *)d->my_shm)->pingpong = DFPP_WRITE_DWORD; ((shm_write_small *)d->my_shm)->pingpong = DFPP_WRITE_DWORD;
d->waitWhile(DFPP_WRITE_DWORD); d->waitWhile(DFPP_WRITE_DWORD);
} }
@ -444,6 +517,7 @@ void SHMProcess::writeWord (uint32_t offset, uint16_t data)
{ {
((shm_write_small *)d->my_shm)->address = offset; ((shm_write_small *)d->my_shm)->address = offset;
((shm_write_small *)d->my_shm)->value = data; ((shm_write_small *)d->my_shm)->value = data;
gcc_barrier
((shm_write_small *)d->my_shm)->pingpong = DFPP_WRITE_WORD; ((shm_write_small *)d->my_shm)->pingpong = DFPP_WRITE_WORD;
d->waitWhile(DFPP_WRITE_WORD); d->waitWhile(DFPP_WRITE_WORD);
} }
@ -452,6 +526,7 @@ void SHMProcess::writeByte (uint32_t offset, uint8_t data)
{ {
((shm_write_small *)d->my_shm)->address = offset; ((shm_write_small *)d->my_shm)->address = offset;
((shm_write_small *)d->my_shm)->value = data; ((shm_write_small *)d->my_shm)->value = data;
gcc_barrier
((shm_write_small *)d->my_shm)->pingpong = DFPP_WRITE_BYTE; ((shm_write_small *)d->my_shm)->pingpong = DFPP_WRITE_BYTE;
d->waitWhile(DFPP_WRITE_BYTE); d->waitWhile(DFPP_WRITE_BYTE);
} }
@ -461,6 +536,7 @@ void SHMProcess::write (uint32_t offset, uint32_t size, const uint8_t *source)
((shm_write *)d->my_shm)->address = offset; ((shm_write *)d->my_shm)->address = offset;
((shm_write *)d->my_shm)->length = size; ((shm_write *)d->my_shm)->length = size;
memcpy(d->my_shm+sizeof(shm_write),source, size); memcpy(d->my_shm+sizeof(shm_write),source, size);
gcc_barrier
((shm_write *)d->my_shm)->pingpong = DFPP_WRITE; ((shm_write *)d->my_shm)->pingpong = DFPP_WRITE;
d->waitWhile(DFPP_WRITE); d->waitWhile(DFPP_WRITE);
} }

@ -110,14 +110,19 @@ ProcessEnumerator::ProcessEnumerator( string path_to_xml )
d->meminfo = new MemInfoManager(path_to_xml); d->meminfo = new MemInfoManager(path_to_xml);
} }
void ProcessEnumerator::purge()
ProcessEnumerator::~ProcessEnumerator()
{ {
// delete all processes
for(uint32_t i = 0;i < d->processes.size();i++) for(uint32_t i = 0;i < d->processes.size();i++)
{ {
delete d->processes[i]; delete d->processes[i];
} }
d->processes.clear();
}
ProcessEnumerator::~ProcessEnumerator()
{
// delete all processes
purge();
delete d->meminfo; delete d->meminfo;
delete d; delete d;
} }

@ -115,14 +115,19 @@ ProcessEnumerator::ProcessEnumerator( string path_to_xml )
d->meminfo = new MemInfoManager(path_to_xml); d->meminfo = new MemInfoManager(path_to_xml);
} }
ProcessEnumerator::purge()
ProcessEnumerator::~ProcessEnumerator()
{ {
// delete all processes
for(uint32_t i = 0;i < d->processes.size();i++) for(uint32_t i = 0;i < d->processes.size();i++)
{ {
delete d->processes[i]; delete d->processes[i];
} }
d->processes.clear();
}
ProcessEnumerator::~ProcessEnumerator()
{
// delete all processes
purge();
delete d->meminfo; delete d->meminfo;
delete d; delete d;
} }

@ -48,6 +48,7 @@ namespace DFHack
bool findProcessess(); bool findProcessess();
uint32_t size(); uint32_t size();
Process * operator[](uint32_t index); Process * operator[](uint32_t index);
void purge(void);
}; };
} }
#endif // PROCESSMANAGER_H_INCLUDED #endif // PROCESSMANAGER_H_INCLUDED

@ -0,0 +1,14 @@
#!/bin/sh
DF_DIR=$(dirname "$0")
cd "${DF_DIR}"
export SDL_DISABLE_LOCK_KEYS=1 # Work around for bug in Debian/Ubuntu SDL patch.
#export SDL_VIDEO_CENTERED=1 # Centre the screen. Messes up resizing.
ldd dwarfort.exe | grep SDL_image | grep -qv "not found$"
if [ $? -eq 0 ]; then
mkdir unused_libs
mv libs/libSDL* unused_libs/
fi
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:"./libs" # Update library search path.
export LD_PRELOAD="./libs/dfconnect.so" # Hack DF!
./dwarfort.exe $* # Go, go, go! :)

@ -25,8 +25,6 @@ distribution.
/** /**
* This is the source for the DF <-> dfhack shm bridge * This is the source for the DF <-> dfhack shm bridge
*/ */
#define _GNU_SOURCE
#include <stdio.h> #include <stdio.h>
#include <dlfcn.h> #include <dlfcn.h>
#include <stdint.h> #include <stdint.h>
@ -37,27 +35,77 @@ distribution.
#include <sys/ipc.h> #include <sys/ipc.h>
#include <unistd.h> #include <unistd.h>
#include "dfconnect.h" #include "dfconnect.h"
#include <sys/time.h>
#include <time.h>
#include <linux/futex.h>
#include <sys/syscall.h>
// a full memory barrier! better be safe than sorry.
#define gcc_barrier asm volatile("" ::: "memory"); __sync_synchronize();
/*
* wait for futex
* futex has to be aligned to 4 bytes
* futex has to be equal to val (returns EWOULDBLOCK otherwise)
* wait can be broken by arriving signals (returns EINTR)
* returns 0 when broken by futex_wake
*/
inline int futex_wait(int * futex, int val)
{
return syscall(SYS_futex, futex, FUTEX_WAIT, val, 0, 0, 0);
}
/*
* wait for futex
* futex has to be aligned to 4 bytes
* futex has to be equal to val (returns EWOULDBLOCK otherwise)
* wait can be broken by arriving signals (returns EINTR)
* returns 0 when broken by futex_wake
* returns ETIMEDOUT on timeout
*/
inline int futex_wait_timed(int * futex, int val, const struct timespec *timeout)
{
return syscall(SYS_futex, futex, FUTEX_WAIT, val, timeout, 0, 0);
}
/*
* wake up futex. returns number of waked processes
*/
inline int futex_wake(int * futex)
{
return syscall(SYS_futex, futex, FUTEX_WAKE, 1, 0, 0, 0);
}
static timespec one_second = { 1,0 };
static timespec five_second = { 5,0 };
// ptr to the real functions // ptr to the real functions
static void (*_SDL_GL_SwapBuffers)(void) = 0; static void (*_SDL_GL_SwapBuffers)(void) = 0;
static void (*_SDL_Quit)(void) = 0; static void (*_SDL_Quit)(void) = 0;
static int (*_SDL_Init)(uint32_t flags) = 0; static int (*_SDL_Init)(uint32_t flags) = 0;
static int (*_SDL_Flip)(void * some_ptr) = 0;
// various crud // various crud
int counter = 0; int counter = 0;
int errorstate = 0; int errorstate = 0;
char *shm; char *shm;
int shmid; int shmid;
static unsigned char * BigFat;
void SHM_Init ( void ) void SHM_Init ( void )
{ {
// name for the segment // name for the segment
key_t key = 123466; key_t key = 123466;
BigFat = (unsigned char *) malloc(SHM_SIZE);
// create the segment // find previous segment, check if it's used by some processes. if it isn't, kill it with fire
if ((shmid = shmget(key, SHM_SIZE, IPC_CREAT | 0600)) < 0) if ((shmid = shmget(key, SHM_SIZE, 0600)) != -1)
{
shmid_ds descriptor;
shmctl(shmid, IPC_STAT, &descriptor);
if(descriptor.shm_nattch == 0)
{
shmctl(shmid,IPC_RMID,NULL);
fprintf(stderr,"dfhack: killed dangling resources from crashed DF.\n");
}
}
// create the segment, make sure only ww are really creating it
if ((shmid = shmget(key, SHM_SIZE, IPC_CREAT | IPC_EXCL | 0600)) < 0)
{ {
perror("shmget"); perror("shmget");
errorstate = 1; errorstate = 1;
@ -71,22 +119,31 @@ void SHM_Init ( void )
errorstate = 1; errorstate = 1;
return; return;
} }
gcc_barrier
((shm_cmd *)shm)->pingpong = DFPP_RUNNING; // make sure we don't stall or do crazy stuff ((shm_cmd *)shm)->pingpong = DFPP_RUNNING; // make sure we don't stall or do crazy stuff
} }
void SHM_Destroy ( void ) void SHM_Destroy ( void )
{ {
// blah, I don't care shmid_ds descriptor;
shmctl(shmid, IPC_STAT, &descriptor);
shmdt(shm);
while(descriptor.shm_nattch != 0)
{
shmctl(shmid, IPC_STAT, &descriptor);
}
shmctl(shmid,IPC_RMID,NULL);
fprintf(stderr,"dfhack: destroyed shared segment.\n");
} }
void SHM_Act (void) void SHM_Act (void)
{ {
struct shmid_ds descriptor;
uint32_t numwaits = 0;
if(errorstate) if(errorstate)
{ {
return; return;
} }
shmid_ds descriptor;
uint32_t numwaits = 0;
uint32_t length; uint32_t length;
uint32_t address; uint32_t address;
check_again: // goto target!!! check_again: // goto target!!!
@ -95,6 +152,7 @@ void SHM_Act (void)
shmctl(shmid, IPC_STAT, &descriptor); shmctl(shmid, IPC_STAT, &descriptor);
if(descriptor.shm_nattch == 1)// other guy crashed if(descriptor.shm_nattch == 1)// other guy crashed
{ {
gcc_barrier
((shm_cmd *)shm)->pingpong = DFPP_RUNNING; ((shm_cmd *)shm)->pingpong = DFPP_RUNNING;
fprintf(stderr,"dfhack: Broke out of loop, other process disappeared.\n"); fprintf(stderr,"dfhack: Broke out of loop, other process disappeared.\n");
return; return;
@ -117,23 +175,26 @@ void SHM_Act (void)
numwaits++; numwaits++;
goto check_again; goto check_again;
case DFPP_SUSPEND: case DFPP_SUSPEND:
gcc_barrier
((shm_cmd *)shm)->pingpong = DFPP_SUSPENDED; ((shm_cmd *)shm)->pingpong = DFPP_SUSPENDED;
goto check_again; goto check_again;
/*
case DFPP_BOUNCE: case DFPP_BOUNCE:
length = ((shm_bounce *)shm)->length; length = ((shm_bounce *)shm)->length;
memcpy(BigFat,shm + sizeof(shm_bounce),length); memcpy(BigFat,shm + sizeof(shm_bounce),length);
memcpy(shm + sizeof(shm_ret_data),BigFat,length); memcpy(shm + sizeof(shm_ret_data),BigFat,length);
((shm_cmd *)shm)->pingpong = DFPP_RET_DATA; ((shm_cmd *)shm)->pingpong = DFPP_RET_DATA;
goto check_again; goto check_again;
*/
case DFPP_PID: case DFPP_PID:
((shm_retval *)shm)->value = getpid(); ((shm_retval *)shm)->value = getpid();
gcc_barrier
((shm_retval *)shm)->pingpong = DFPP_RET_PID; ((shm_retval *)shm)->pingpong = DFPP_RET_PID;
goto check_again; goto check_again;
case DFPP_VERSION: case DFPP_VERSION:
((shm_retval *)shm)->value = PINGPONG_VERSION; ((shm_retval *)shm)->value = PINGPONG_VERSION;
gcc_barrier
((shm_retval *)shm)->pingpong = DFPP_RET_VERSION; ((shm_retval *)shm)->pingpong = DFPP_RET_VERSION;
goto check_again; goto check_again;
@ -141,24 +202,28 @@ void SHM_Act (void)
length = ((shm_read *)shm)->length; length = ((shm_read *)shm)->length;
address = ((shm_read *)shm)->address; address = ((shm_read *)shm)->address;
memcpy(shm + sizeof(shm_ret_data), (void *) address,length); memcpy(shm + sizeof(shm_ret_data), (void *) address,length);
gcc_barrier
((shm_cmd *)shm)->pingpong = DFPP_RET_DATA; ((shm_cmd *)shm)->pingpong = DFPP_RET_DATA;
goto check_again; goto check_again;
case DFPP_READ_DWORD: case DFPP_READ_DWORD:
address = ((shm_read_small *)shm)->address; address = ((shm_read_small *)shm)->address;
((shm_retval *)shm)->value = *((uint32_t*) address); ((shm_retval *)shm)->value = *((uint32_t*) address);
gcc_barrier
((shm_retval *)shm)->pingpong = DFPP_RET_DWORD; ((shm_retval *)shm)->pingpong = DFPP_RET_DWORD;
goto check_again; goto check_again;
case DFPP_READ_WORD: case DFPP_READ_WORD:
address = ((shm_read_small *)shm)->address; address = ((shm_read_small *)shm)->address;
((shm_retval *)shm)->value = *((uint16_t*) address); ((shm_retval *)shm)->value = *((uint16_t*) address);
gcc_barrier
((shm_retval *)shm)->pingpong = DFPP_RET_WORD; ((shm_retval *)shm)->pingpong = DFPP_RET_WORD;
goto check_again; goto check_again;
case DFPP_READ_BYTE: case DFPP_READ_BYTE:
address = ((shm_read_small *)shm)->address; address = ((shm_read_small *)shm)->address;
((shm_retval *)shm)->value = *((uint8_t*) address); ((shm_retval *)shm)->value = *((uint8_t*) address);
gcc_barrier
((shm_retval *)shm)->pingpong = DFPP_RET_BYTE; ((shm_retval *)shm)->pingpong = DFPP_RET_BYTE;
goto check_again; goto check_again;
@ -166,21 +231,25 @@ void SHM_Act (void)
address = ((shm_write *)shm)->address; address = ((shm_write *)shm)->address;
length = ((shm_write *)shm)->length; length = ((shm_write *)shm)->length;
memcpy((void *)address, shm + sizeof(shm_write),length); memcpy((void *)address, shm + sizeof(shm_write),length);
gcc_barrier
((shm_cmd *)shm)->pingpong = DFPP_SUSPENDED; ((shm_cmd *)shm)->pingpong = DFPP_SUSPENDED;
goto check_again; goto check_again;
case DFPP_WRITE_DWORD: case DFPP_WRITE_DWORD:
(*(uint32_t*)((shm_write_small *)shm)->address) = ((shm_write_small *)shm)->value; (*(uint32_t*)((shm_write_small *)shm)->address) = ((shm_write_small *)shm)->value;
gcc_barrier
((shm_cmd *)shm)->pingpong = DFPP_SUSPENDED; ((shm_cmd *)shm)->pingpong = DFPP_SUSPENDED;
goto check_again; goto check_again;
case DFPP_WRITE_WORD: case DFPP_WRITE_WORD:
(*(uint16_t*)((shm_write_small *)shm)->address) = ((shm_write_small *)shm)->value; (*(uint16_t*)((shm_write_small *)shm)->address) = ((shm_write_small *)shm)->value;
gcc_barrier
((shm_cmd *)shm)->pingpong = DFPP_SUSPENDED; ((shm_cmd *)shm)->pingpong = DFPP_SUSPENDED;
goto check_again; goto check_again;
case DFPP_WRITE_BYTE: case DFPP_WRITE_BYTE:
(*(uint8_t*)((shm_write_small *)shm)->address) = ((shm_write_small *)shm)->value; (*(uint8_t*)((shm_write_small *)shm)->address) = ((shm_write_small *)shm)->value;
gcc_barrier
((shm_cmd *)shm)->pingpong = DFPP_SUSPENDED; ((shm_cmd *)shm)->pingpong = DFPP_SUSPENDED;
goto check_again; goto check_again;
@ -191,12 +260,13 @@ void SHM_Act (void)
default: default:
((shm_retval *)shm)->value = DFEE_INVALID_COMMAND; ((shm_retval *)shm)->value = DFEE_INVALID_COMMAND;
gcc_barrier
((shm_retval *)shm)->pingpong = DFPP_SV_ERROR; ((shm_retval *)shm)->pingpong = DFPP_SV_ERROR;
break; break;
} }
} }
// hook - called every tick // hook - called every tick in OpenGL mode of DF
extern "C" void SDL_GL_SwapBuffers(void) extern "C" void SDL_GL_SwapBuffers(void)
{ {
if(_SDL_GL_SwapBuffers) if(_SDL_GL_SwapBuffers)
@ -210,6 +280,20 @@ extern "C" void SDL_GL_SwapBuffers(void)
} }
} }
// hook - called every tick in the 2D mode of DF
extern "C" int SDL_Flip(void * some_ptr)
{
if(_SDL_Flip)
{
if(((shm_cmd *)shm)->pingpong != DFPP_RUNNING)
{
SHM_Act();
}
counter ++;
return _SDL_Flip(some_ptr);
}
}
// hook - called at program exit // hook - called at program exit
extern "C" void SDL_Quit(void) extern "C" void SDL_Quit(void)
{ {
@ -217,7 +301,8 @@ extern "C" void SDL_Quit(void)
{ {
_SDL_Quit(); _SDL_Quit();
} }
fprintf(stderr,"dfhack: DF called SwapBuffers %d times, lol\n", counter); fprintf(stderr,"dfhack: DF called SwapBuffers %d times\n", counter);
SHM_Destroy();
} }
// hook - called at program start, initialize some stuffs we'll use later // hook - called at program start, initialize some stuffs we'll use later
@ -226,6 +311,7 @@ extern "C" int SDL_Init(uint32_t flags)
// find real functions // find real functions
_SDL_GL_SwapBuffers = (void (*)( void )) dlsym(RTLD_NEXT, "SDL_GL_SwapBuffers"); _SDL_GL_SwapBuffers = (void (*)( void )) dlsym(RTLD_NEXT, "SDL_GL_SwapBuffers");
_SDL_Init = (int (*)( uint32_t )) dlsym(RTLD_NEXT, "SDL_Init"); _SDL_Init = (int (*)( uint32_t )) dlsym(RTLD_NEXT, "SDL_Init");
_SDL_Flip = (int (*)( void * )) dlsym(RTLD_NEXT, "SDL_Flip");
_SDL_Quit = (void (*)( void )) dlsym(RTLD_NEXT, "SDL_Quit"); _SDL_Quit = (void (*)( void )) dlsym(RTLD_NEXT, "SDL_Quit");
// check if we got them // check if we got them

@ -12,6 +12,14 @@
* end - sent to DF for breaking out of the wait * end - sent to DF for breaking out of the wait
*/ */
enum DF_SHM_ERRORSTATE
{
SHM_OK, // all OK
SHM_CANT_GET_SHM, // getting the SHM ID failed for some reason
SHM_CANT_ATTACH, // we can't attach the shm for some reason
SHM_SECOND_DF // we are a second DF process, can't use SHM at all
};
enum DF_PINGPONG enum DF_PINGPONG
{ {
DFPP_RUNNING = 0, // no command, normal server execution DFPP_RUNNING = 0, // no command, normal server execution

Binary file not shown.

@ -9,3 +9,6 @@ export LD_PRELOAD="./libs/dfconnect.so" # Hack DF!
save and run the script! save and run the script!
Has to be compiled for 32bit arch, otherwise the library isn't recognised. Client can be any arch. Has to be compiled for 32bit arch, otherwise the library isn't recognised. Client can be any arch.
Precompiled dfconnect library is made available. dfconnect.so goes in DF/libs, df-hacked script goes in DF/
Run ./df-hacked to use the shared memory API