SHM rework, stage 1

develop
Petr Mrázek 2010-03-03 05:43:38 +01:00
parent b3424418e6
commit 0192520d43
11 changed files with 1328 additions and 1571 deletions

@ -1,138 +0,0 @@
Here's how you build dfhack!
----------------------------
First, there is one dependency, regardless of the OS you use:
cmake - it's the build system
Building on Linux:
--------------------
* To run in the output folder (without installing):
building the library is simple. Enter the build folder, run the tools. Like this:
cd build
cmake .. -DCMAKE_BUILD_TYPE:string=Release
make
This will build the library and its tools and place them in /output.
You can also use a cmake-friendly IDE like KDevelop 4 or the cmake GUI program.
* To be installed into the system or packaged
cd build
cmake -DCMAKE_BUILD_TYPE:string=Release -DCMAKE_INSTALL_PREFIX=/usr -DMEMXML_DATA_PATH:path=/usr/share/dfhack ..
make
make install
With this dfhack installs:
library to $CMAKE_INSTALL_PREFIX/lib
executables to $CMAKE_INSTALL_PREFIX/bin
The Memory.xml file to /usr/share/dfhack
See the section on the shared memory hook library (SHM).
Building on Windows:
--------------------
You need cmake. Get the win32 installer version from the official site: http://www.cmake.org/cmake/resources/software.html
It has the usual installer wizard thing.
* Using mingw:
You also need a compiler. I build dfhack using mingw. You can get it from the mingw site:
Get the automated installer, it will download newest version of mingw and set things up nicely.
You'll have to add C:\MinGW\ to your PATH variable.
- Building:
open up cmd and navigate to the dfhack\build folder, run cmake and the mingw version of make:
cd build
cmake .. -G"MinGW Makefiles" -DCMAKE_BUILD_TYPE:string=Release
mingw32-make
* Using MSVC
open up cmd and navigate to the dfhack\build folder, run cmake:
cd build
cmake ..
This will generate MSVC solution and project files. Note that: you are working in the /build folder.
Files added to projects will end up there! (and that's wrong). Any changes to the build system should
be done by changing cmake configs and running cmake on them!
* Using some other compiler:
I'm afraid you are on your own. dfhack wasn't tested with any other compiler.
Try using a different cmake generator that's intended for your tools.
Building the shared memory hook library (SHM)
---------------------------------------------
Unlike the rest of DFHack, The SHM needs special treatment when it comes to compilation.
Because it shares the memory space with DF itself, it has to be built with the same tools as DF
and use the same C and C++/STL libraries.
For DF 40d15 - 40d17 on Windows, use MSVC 2008. You can get the Express edition for free from Microsoft.
Windows dependencies can be determined by a tool like depends.exe (google it). Both the fake SDL.dll
and DF have to use the same version of the C runtime (MSVCRT).
The SHM can't be debugged, because debug builds in MSVC use a different CRT!
Linux dependencies can be determined by setting the LD_DEBUG variable and running ./df:
export LD_DEBUG=versions
./df
Example of (a part of a) relevant output from a working SHM installation:
24472: checking for version `GLIBC_2.0' in file /opt/lib32/lib/libpthread.so.0 [0] required by file ./dwarfort.exe [0]
24472: checking for version `GCC_3.0' in file ./libs/libgcc_s.so.1 [0] required by file ./dwarfort.exe [0]
24472: checking for version `GLIBC_2.0' in file ./libs/libgcc_s.so.1 [0] required by file ./dwarfort.exe [0]
24472: checking for version `GLIBC_2.1' in file /opt/lib32/lib/libm.so.6 [0] required by file ./dwarfort.exe [0]
24472: checking for version `GLIBC_2.0' in file /opt/lib32/lib/libm.so.6 [0] required by file ./dwarfort.exe [0]
24472: checking for version `GLIBC_2.1.3' in file /opt/lib32/lib/libc.so.6 [0] required by file ./dwarfort.exe [0]
24472: checking for version `GLIBC_2.3.4' in file /opt/lib32/lib/libc.so.6 [0] required by file ./dwarfort.exe [0]
24472: checking for version `GLIBC_2.4' in file /opt/lib32/lib/libc.so.6 [0] required by file ./dwarfort.exe [0]
24472: checking for version `GLIBC_2.0' in file /opt/lib32/lib/libc.so.6 [0] required by file ./dwarfort.exe [0]
24472: checking for version `GLIBCXX_3.4.9' in file ./libs/libstdc++.so.6 [0] required by file ./dwarfort.exe [0]
24472: checking for version `CXXABI_1.3' in file ./libs/libstdc++.so.6 [0] required by file ./dwarfort.exe [0]
24472: checking for version `GLIBCXX_3.4' in file ./libs/libstdc++.so.6 [0] required by file ./dwarfort.exe [0]
24472: checking for version `CXXABI_1.3' in file ./libs/libstdc++.so.6 [0] required by file ./libs/libdfconnect.so [0]
24472: checking for version `GLIBCXX_3.4' in file ./libs/libstdc++.so.6 [0] required by file ./libs/libdfconnect.so [0]
24472: checking for version `GLIBC_2.1.3' in file /opt/lib32/lib/libc.so.6 [0] required by file ./libs/libdfconnect.so [0]
24472: checking for version `GLIBC_2.2' in file /opt/lib32/lib/libc.so.6 [0] required by file ./libs/libdfconnect.so [0]
24472: checking for version `GLIBC_2.3.4' in file /opt/lib32/lib/libc.so.6 [0] required by file ./libs/libdfconnect.so [0]
24472: checking for version `GLIBC_2.0' in file /opt/lib32/lib/libc.so.6 [0] required by file ./libs/libdfconnect.so [0]
libdfconnect is the SHM. Both are compiled against the same C++ library and share the same CXXABI version.
Precompiled SHM libraries are provided in binary releases.
* Checking strings support
Strings are one of the important C++ types and a great indicator that the SHM works. Tools like Dwarf Therapist depend
on string support. Reading of strings can be checked by running any of the tools that deal with materials.
String writing is best tested with a fresh throw-away fort and dfrenamer. Embark, give one dwarf a very long name using dfrenamer
and save/exit. If DF crashes during the save sequence, your SHM is not compatible with DF and the throw-away fort is lost.
Build targets
-------------
dfhack has a few build targets. If you're only after the library run 'make dfhack'.
'make' will build everything.
'make expbench' will build the expbench throughput testing program and the library.
Build types
-----------
cmake allows you to pick a build type by changing this variable: CMAKE_BUILD_TYPE
cmake .. -DCMAKE_BUILD_TYPE:string=BUILD_TYPE
Without specifying a build type or 'None', cmake uses the CMAKE_CXX_FLAGS variable for building.
Valid build types include 'Release' and 'Debug'. There are others, but they aren't really that useful.
Have fun.

@ -1,174 +0,0 @@
Introduction
------------
DFHack is a Dwarf Fortress memory access library and a set of basic tools using
this library. The library is a work in progress, so things might change as more
tools are written for it.
It is an attempt to unite the various ways tools access DF memory and allow for
easier development of new tools.
Getting DFHack
----------------
The project is currently hosted on github:
http://github.com/peterix/dfhack
There's an SVN repository at sourceforge, but will only be updated for major releases:
https://sourceforge.net/projects/dfhack/
* subversion access:
svn co https://dfhack.svn.sourceforge.net/svnroot/dfhack/trunk dfhack
Compatibility
-------------
DFHack works on Windows XP, Vista, 7 or any modern Linux distribution.
Windows 2000 is currently *not supported* due to missing OS functionality.
If you know how to easily suspend processes, you can fix it :)
OSX is also not supported due to lack of developers with a Mac.
Currently supported Dwarf Fortress versions:
* Windows
40d
40d9 - 40d18
* Linux
40d9 - 40d18
Using the library
-----------------
The library is compilable under Linux with GCC and under Windows with MinGW32
and MSVC compilers. It is using the cmake build system. See COMPILE for details.
DFHack is using the zlib/libpng license. This makes it easy to link to it, use
it in-source or add your own extensions. Contributing back to the dfhack
repository is welcome and the right thing to do :)
At the time of writing there's no API reference or documentation. The code does
have a lot of comments though.
Using DFHack Tools
------------------
The project comes with a special extra library you should add to your DF
installation. It's used to boost the transfer speed between DF and DFHack, and
provide data consistency and synchronization. DFHack will work without the
library, but at suboptimal speeds and the consistency of data written back
to DF is questionable.
!!! on Windows this currently only works with DF 40d15 - 40d18 !!!
On Linux, it works with the whole range of supported DF versions.
!!! use the pre-compiled library intended for your OS and version of DF !!!
You can find them in the 'precompiled' folder.
** Installing on Windows
- Open your DF folder, locate SDL.dll and rename it to SDLreal.dll (making
a backup of it is a good idea)
- Copy the right DFHack SDL.dll into your DF folder.
- Restart DF if it is running
** Unistalling on Windows
- Open your DF folder, locate SDL.dll and delete it
- Rename SDLreal.dll to SDL.dll
- Restart DF if it is running
** Installing on Linux
- Open your DF folder and the libs folder within it
- copy DFHack libdfconnect.so to the libs folder
- copy the df startup script, name it dfhacked
- open the new dfhacked startup script and add this line:
export LD_PRELOAD="./libs/libdfconnect.so" # Hack DF!
just before the line that launches DF
Here's an example how the file can look after the change:
#!/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/libdfconnect.so" # Hack DF!
./dwarfort.exe $* # Go, go, go! :)
- Use this new startup script to start DF
** Uninstalling on Linux
- Open your DF and DF/libs folders
- Delete libdfconnect.so and the dfhacked startup script
- Go back to using the df startup script
Tools
-----
All the DFHack tools are terminal programs. This might seem strange to Windows
users, but these are meant mostly as examples for developers. Still, they can
be useful and are cross-platform just like the library itself.
If the tool writes back to DF's memory, make sure you are using the shared
memory interface mentioned in the previous section!
* reveal - plain old reveal tool. It reveals all the map blocks already
initialized by DF.
* prospector - scans the map for minerals. by default it only scans only visible
veins. You can make it show hidden things with '-a' and base rock
and soil layers with '-b'. These can be combined ('-ab')
* cleanmap - cleans mud, vomit, snow and all kinds of mess from the map.
It will clean your irrigated farms too, so consider yourself
warned.
* incremental - incremental search utility.
* bauxite - converts all mechanisms into bauxite mechanisms.
* itemdesignator - Allows mass-designating items by type and material - dump,
forbid, melt and set on fire ;)
* digger - allows designating tiles for digging/cutting/ramp removal
A list of accepted tile classes:
1 = WALL
2 = PILLAR
3 = FORTIFICATION
4 = STAIR_UP
5 = STAIR_DOWN
6 = STAIR_UPDOWN
7 = RAMP
8 = FLOOR
9 = TREE_DEAD
10 = TREE_OK
11 = SAPLING_DEAD
12 = SAPLING_OK
13 = SHRUB_DEAD
14 = SHRUB_OK
15 = BOULDER
16 = PEBBLES
Example : dfdigger -o 100,100,15 -t 9,10 -m 10
This will start looking for trees at coords 100,100,15 and designate ten of them for cutting.
Memory offset definitions
-------------------------
The file with memory offset definitions used by dfhack can be found in the
output folder.
~ EOF ~

@ -50,6 +50,7 @@ class Process::Private
attached = false;
suspended = false;
identified = false;
useYield = false;
};
~Private(){};
memory_info * my_descriptor;
@ -61,18 +62,26 @@ class Process::Private
bool attached;
bool suspended;
bool identified;
bool useYield;
bool validate(char* exe_file, uint32_t pid, std::vector< memory_info* >& known_versions);
bool waitWhile (DF_PINGPONG state);
bool waitWhile (CORE_COMMAND state);
bool DF_TestBridgeVersion(bool & ret);
bool DF_GetPID(pid_t & ret);
};
bool Process::Private::waitWhile (DF_PINGPONG state)
// some helpful macros to keep the code bloat in check
#define SHMCMD ((shm_cmd *)my_shm)->pingpong
#define D_SHMCMD ((shm_cmd *)d->my_shm)->pingpong
#define SHMHDR ((shm_header *)my_shm)
#define D_SHMHDR ((shm_header *)d->my_shm)
bool Process::Private::waitWhile (CORE_COMMAND state)
{
uint32_t cnt = 0;
struct shmid_ds descriptor;
while (((shm_cmd *)my_shm)->pingpong == state)
while (SHMCMD == state)
{
if(cnt == 10000)
{
@ -80,8 +89,7 @@ bool Process::Private::waitWhile (DF_PINGPONG state)
shmctl(my_shmid, IPC_STAT, &descriptor);
if(descriptor.shm_nattch == 1)// DF crashed?
{
gcc_barrier
((shm_cmd *)my_shm)->pingpong = DFPP_RUNNING;
SHMCMD = CORE_RUNNING;
attached = suspended = false;
return false;
}
@ -93,9 +101,9 @@ bool Process::Private::waitWhile (DF_PINGPONG state)
SCHED_YIELD
cnt++;
}
if(((shm_cmd *)my_shm)->pingpong == DFPP_SV_ERROR)
if(SHMCMD == CORE_SV_ERROR)
{
((shm_cmd *)my_shm)->pingpong = DFPP_RUNNING;
SHMCMD = CORE_RUNNING;
attached = suspended = false;
cerr << "shm server error!" << endl;
assert (false);
@ -106,25 +114,25 @@ bool Process::Private::waitWhile (DF_PINGPONG state)
bool Process::Private::DF_TestBridgeVersion(bool & ret)
{
((shm_cmd *)my_shm)->pingpong = DFPP_VERSION;
SHMCMD = CORE_GET_VERSION;
gcc_barrier
if(!waitWhile(DFPP_VERSION))
if(!waitWhile(CORE_GET_VERSION))
return false;
gcc_barrier
((shm_cmd *)my_shm)->pingpong = DFPP_SUSPENDED;
ret =( ((shm_retval *)my_shm)->value == PINGPONG_VERSION );
SHMCMD = CORE_SUSPENDED;
ret =( SHMHDR->value == CORE_VERSION );
return true;
}
bool Process::Private::DF_GetPID(pid_t & ret)
{
((shm_cmd *)my_shm)->pingpong = DFPP_PID;
SHMCMD = CORE_GET_PID;
gcc_barrier
if(!waitWhile(DFPP_PID))
if(!waitWhile(CORE_GET_PID))
return false;
gcc_barrier
((shm_cmd *)my_shm)->pingpong = DFPP_SUSPENDED;
ret = ((shm_retval *)my_shm)->value;
SHMCMD = CORE_SUSPENDED;
ret = SHMHDR->value;
return true;
}
@ -200,7 +208,7 @@ Process::Process(vector <memory_info *> & known_versions)
}
gcc_barrier
// at this point, DF is stopped and waiting for commands. make it run again
((shm_cmd *)d->my_shm)->pingpong = DFPP_RUNNING;
D_SHMCMD = CORE_RUNNING;
shmdt(d->my_shm); // detach so we don't attach twice when attach() is called
}
@ -319,8 +327,8 @@ bool Process::suspend()
{
return true;
}
((shm_cmd *)d->my_shm)->pingpong = DFPP_SUSPEND;
if(!d->waitWhile(DFPP_SUSPEND))
D_SHMCMD = CORE_SUSPEND;
if(!d->waitWhile(CORE_SUSPEND))
{
return false;
}
@ -338,14 +346,14 @@ bool Process::asyncSuspend()
{
return true;
}
if(((shm_cmd *)d->my_shm)->pingpong == DFPP_SUSPENDED)
if(D_SHMCMD == CORE_SUSPENDED)
{
d->suspended = true;
return true;
}
else
{
((shm_cmd *)d->my_shm)->pingpong = DFPP_SUSPEND;
D_SHMCMD = CORE_SUSPEND;
return false;
}
}
@ -361,7 +369,7 @@ bool Process::resume()
return false;
if(!d->suspended)
return true;
((shm_cmd *)d->my_shm)->pingpong = DFPP_RUNNING;
D_SHMCMD = CORE_RUNNING;
d->suspended = false;
return true;
}
@ -425,11 +433,11 @@ void Process::read (uint32_t src_address, uint32_t size, uint8_t *target_buffer)
// normal read under 1MB
if(size <= SHM_BODY)
{
((shm_read *)d->my_shm)->address = src_address;
((shm_read *)d->my_shm)->length = size;
D_SHMHDR->address = src_address;
D_SHMHDR->length = size;
gcc_barrier
((shm_read *)d->my_shm)->pingpong = DFPP_READ;
d->waitWhile(DFPP_READ);
D_SHMCMD = CORE_DFPP_READ;
d->waitWhile(CORE_DFPP_READ);
memcpy (target_buffer, d->my_shm + SHM_HEADER,size);
}
// a big read, we pull data over the shm in iterations
@ -440,11 +448,11 @@ void Process::read (uint32_t src_address, uint32_t size, uint8_t *target_buffer)
while (size)
{
// read to_read bytes from src_cursor
((shm_read *)d->my_shm)->address = src_address;
((shm_read *)d->my_shm)->length = to_read;
D_SHMHDR->address = src_address;
D_SHMHDR->length = to_read;
gcc_barrier
((shm_read *)d->my_shm)->pingpong = DFPP_READ;
d->waitWhile(DFPP_READ);
D_SHMCMD = CORE_DFPP_READ;
d->waitWhile(CORE_DFPP_READ);
memcpy (target_buffer, d->my_shm + SHM_HEADER,size);
// decrease size by bytes read
size -= to_read;
@ -459,55 +467,55 @@ void Process::read (uint32_t src_address, uint32_t size, uint8_t *target_buffer)
uint8_t Process::readByte (const uint32_t offset)
{
((shm_read_small *)d->my_shm)->address = offset;
D_SHMHDR->address = offset;
gcc_barrier
((shm_read_small *)d->my_shm)->pingpong = DFPP_READ_BYTE;
d->waitWhile(DFPP_READ_BYTE);
return ((shm_retval *)d->my_shm)->value;
D_SHMCMD = CORE_READ_BYTE;
d->waitWhile(CORE_READ_BYTE);
return D_SHMHDR->value;
}
void Process::readByte (const uint32_t offset, uint8_t &val )
{
((shm_read_small *)d->my_shm)->address = offset;
D_SHMHDR->address = offset;
gcc_barrier
((shm_read_small *)d->my_shm)->pingpong = DFPP_READ_BYTE;
d->waitWhile(DFPP_READ_BYTE);
val = ((shm_retval *)d->my_shm)->value;
D_SHMCMD = CORE_READ_BYTE;
d->waitWhile(CORE_READ_BYTE);
val = D_SHMHDR->value;
}
uint16_t Process::readWord (const uint32_t offset)
{
((shm_read_small *)d->my_shm)->address = offset;
D_SHMHDR->address = offset;
gcc_barrier
((shm_read_small *)d->my_shm)->pingpong = DFPP_READ_WORD;
d->waitWhile(DFPP_READ_WORD);
return ((shm_retval *)d->my_shm)->value;
D_SHMCMD = CORE_READ_WORD;
d->waitWhile(CORE_READ_WORD);
return D_SHMHDR->value;
}
void Process::readWord (const uint32_t offset, uint16_t &val)
{
((shm_read_small *)d->my_shm)->address = offset;
D_SHMHDR->address = offset;
gcc_barrier
((shm_read_small *)d->my_shm)->pingpong = DFPP_READ_WORD;
d->waitWhile(DFPP_READ_WORD);
val = ((shm_retval *)d->my_shm)->value;
D_SHMCMD = CORE_READ_WORD;
d->waitWhile(CORE_READ_WORD);
val = D_SHMHDR->value;
}
uint32_t Process::readDWord (const uint32_t offset)
{
((shm_read_small *)d->my_shm)->address = offset;
D_SHMHDR->address = offset;
gcc_barrier
((shm_read_small *)d->my_shm)->pingpong = DFPP_READ_DWORD;
d->waitWhile(DFPP_READ_DWORD);
return ((shm_retval *)d->my_shm)->value;
D_SHMCMD = CORE_READ_DWORD;
d->waitWhile(CORE_READ_DWORD);
return D_SHMHDR->value;
}
void Process::readDWord (const uint32_t offset, uint32_t &val)
{
((shm_read_small *)d->my_shm)->address = offset;
D_SHMHDR->address = offset;
gcc_barrier
((shm_read_small *)d->my_shm)->pingpong = DFPP_READ_DWORD;
d->waitWhile(DFPP_READ_DWORD);
val = ((shm_retval *)d->my_shm)->value;
D_SHMCMD = CORE_READ_DWORD;
d->waitWhile(CORE_READ_DWORD);
val = D_SHMHDR->value;
}
/*
@ -516,30 +524,30 @@ void Process::readDWord (const uint32_t offset, uint32_t &val)
void Process::writeDWord (uint32_t offset, uint32_t data)
{
((shm_write_small *)d->my_shm)->address = offset;
((shm_write_small *)d->my_shm)->value = data;
D_SHMHDR->address = offset;
D_SHMHDR->value = data;
gcc_barrier
((shm_write_small *)d->my_shm)->pingpong = DFPP_WRITE_DWORD;
d->waitWhile(DFPP_WRITE_DWORD);
D_SHMCMD = CORE_WRITE_DWORD;
d->waitWhile(CORE_WRITE_DWORD);
}
// using these is expensive.
void Process::writeWord (uint32_t offset, uint16_t data)
{
((shm_write_small *)d->my_shm)->address = offset;
((shm_write_small *)d->my_shm)->value = data;
D_SHMHDR->address = offset;
D_SHMHDR->value = data;
gcc_barrier
((shm_write_small *)d->my_shm)->pingpong = DFPP_WRITE_WORD;
d->waitWhile(DFPP_WRITE_WORD);
D_SHMCMD = CORE_WRITE_WORD;
d->waitWhile(CORE_WRITE_WORD);
}
void Process::writeByte (uint32_t offset, uint8_t data)
{
((shm_write_small *)d->my_shm)->address = offset;
((shm_write_small *)d->my_shm)->value = data;
D_SHMHDR->address = offset;
D_SHMHDR->value = data;
gcc_barrier
((shm_write_small *)d->my_shm)->pingpong = DFPP_WRITE_BYTE;
d->waitWhile(DFPP_WRITE_BYTE);
D_SHMCMD = CORE_WRITE_BYTE;
d->waitWhile(CORE_WRITE_BYTE);
}
void Process::write (uint32_t dst_address, uint32_t size, uint8_t *source_buffer)
@ -547,12 +555,12 @@ void Process::write (uint32_t dst_address, uint32_t size, uint8_t *source_buffer
// normal write under 1MB
if(size <= SHM_BODY)
{
((shm_write *)d->my_shm)->address = dst_address;
((shm_write *)d->my_shm)->length = size;
D_SHMHDR->address = dst_address;
D_SHMHDR->length = size;
memcpy(d->my_shm+SHM_HEADER,source_buffer, size);
gcc_barrier
((shm_write *)d->my_shm)->pingpong = DFPP_WRITE;
d->waitWhile(DFPP_WRITE);
D_SHMCMD = CORE_WRITE;
d->waitWhile(CORE_WRITE);
}
// a big write, we push this over the shm in iterations
else
@ -562,12 +570,12 @@ void Process::write (uint32_t dst_address, uint32_t size, uint8_t *source_buffer
while (size)
{
// write to_write bytes to dst_cursor
((shm_write *)d->my_shm)->address = dst_address;
((shm_write *)d->my_shm)->length = to_write;
D_SHMHDR->address = dst_address;
D_SHMHDR->length = to_write;
memcpy(d->my_shm+SHM_HEADER,source_buffer, to_write);
gcc_barrier
((shm_write *)d->my_shm)->pingpong = DFPP_WRITE;
d->waitWhile(DFPP_WRITE);
D_SHMCMD = CORE_WRITE;
d->waitWhile(CORE_WRITE);
// decrease size by bytes written
size -= to_write;
// move the cursors
@ -615,21 +623,21 @@ DfVector Process::readVector (uint32_t offset, uint32_t item_size)
const std::string Process::readSTLString(uint32_t offset)
{
((shm_read_small *)d->my_shm)->address = offset;
D_SHMHDR->address = offset;
full_barrier
((shm_read_small *)d->my_shm)->pingpong = DFPP_READ_STL_STRING;
d->waitWhile(DFPP_READ_STL_STRING);
D_SHMCMD = CORE_READ_STL_STRING;
d->waitWhile(CORE_READ_STL_STRING);
//int length = ((shm_retval *)d->my_shm)->value;
return(string( (char *)d->my_shm+SHM_HEADER));
}
size_t Process::readSTLString (uint32_t offset, char * buffer, size_t bufcapacity)
{
((shm_read_small *)d->my_shm)->address = offset;
D_SHMHDR->address = offset;
full_barrier
((shm_read_small *)d->my_shm)->pingpong = DFPP_READ_STL_STRING;
d->waitWhile(DFPP_READ_STL_STRING);
size_t length = ((shm_retval *)d->my_shm)->value;
D_SHMCMD = CORE_READ_STL_STRING;
d->waitWhile(CORE_READ_STL_STRING);
size_t length = D_SHMHDR->value;
size_t fit = min(bufcapacity - 1, length);
strncpy(buffer,(char *)d->my_shm+SHM_HEADER,fit);
buffer[fit] = 0;
@ -638,11 +646,11 @@ size_t Process::readSTLString (uint32_t offset, char * buffer, size_t bufcapacit
void Process::writeSTLString(const uint32_t address, const std::string writeString)
{
((shm_write_small *)d->my_shm)->address = address;
D_SHMHDR->address = address;
strncpy(d->my_shm+SHM_HEADER,writeString.c_str(),writeString.length()+1); // length + 1 for the null terminator
full_barrier
((shm_write_small *)d->my_shm)->pingpong = DFPP_WRITE_STL_STRING;
d->waitWhile(DFPP_WRITE_STL_STRING);
D_SHMCMD = CORE_WRITE_STL_STRING;
d->waitWhile(CORE_WRITE_STL_STRING);
}
string Process::readClassName (uint32_t vptr)

@ -53,7 +53,7 @@ class Process::Private
bool suspended;
bool identified;
bool waitWhile (DF_PINGPONG state);
bool waitWhile (CORE_COMMAND state);
bool isValidSV();
bool DF_TestBridgeVersion(bool & ret);
bool DF_GetPID(uint32_t & ret);
@ -87,7 +87,7 @@ bool Process::Private::isValidSV()
}
}
bool Process::Private::waitWhile (DF_PINGPONG state)
bool Process::Private::waitWhile (CORE_COMMAND state)
{
uint32_t cnt = 0;
SCHED_YIELD // yield the CPU, valid only on single-core CPUs
@ -98,7 +98,7 @@ bool Process::Private::waitWhile (DF_PINGPONG state)
if(!isValidSV())// DF not there anymore?
{
full_barrier
((shm_cmd *)my_shm)->pingpong = DFPP_RUNNING;
((shm_cmd *)my_shm)->pingpong = CORE_RUNNING;
attached = suspended = false;
ReleaseMutex(DFCLMutex);
return false;
@ -110,9 +110,9 @@ bool Process::Private::waitWhile (DF_PINGPONG state)
}
cnt++;
}
if(((shm_cmd *)my_shm)->pingpong == DFPP_SV_ERROR)
if(((shm_cmd *)my_shm)->pingpong == CORE_SV_ERROR)
{
((shm_cmd *)my_shm)->pingpong = DFPP_RUNNING;
((shm_cmd *)my_shm)->pingpong = CORE_RUNNING;
attached = suspended = false;
cerr << "shm server error!" << endl;
assert (false);
@ -123,25 +123,25 @@ bool Process::Private::waitWhile (DF_PINGPONG state)
bool Process::Private::DF_TestBridgeVersion(bool & ret)
{
((shm_cmd *)my_shm)->pingpong = DFPP_VERSION;
((shm_cmd *)my_shm)->pingpong = CORE_GET_VERSION;
full_barrier
if(!waitWhile(DFPP_VERSION))
if(!waitWhile(CORE_GET_VERSION))
return false;
full_barrier
((shm_cmd *)my_shm)->pingpong = DFPP_SUSPENDED;
ret =( ((shm_retval *)my_shm)->value == PINGPONG_VERSION );
((shm_cmd *)my_shm)->pingpong = CORE_SUSPENDED;
ret =( ((shm_val *)my_shm)->value == CORE_VERSION );
return true;
}
bool Process::Private::DF_GetPID(uint32_t & ret)
{
((shm_cmd *)my_shm)->pingpong = DFPP_PID;
((shm_cmd *)my_shm)->pingpong = CORE_GET_PID;
full_barrier
if(!waitWhile(DFPP_PID))
if(!waitWhile(CORE_GET_PID))
return false;
full_barrier
((shm_cmd *)my_shm)->pingpong = DFPP_SUSPENDED;
ret = ((shm_retval *)my_shm)->value;
((shm_cmd *)my_shm)->pingpong = CORE_SUSPENDED;
ret = ((shm_val *)my_shm)->value;
return true;
}
@ -182,7 +182,7 @@ Process::Process(vector <memory_info *> & known_versions)
if(!bridgeOK)
{
fprintf(stderr,"SHM bridge version mismatch\n");
((shm_cmd *)d->my_shm)->pingpong = DFPP_RUNNING;
((shm_cmd *)d->my_shm)->pingpong = CORE_RUNNING;
UnmapViewOfFile(d->my_shm);
ReleaseMutex(d->DFCLMutex);
CloseHandle(d->DFSVMutex);
@ -258,7 +258,7 @@ Process::Process(vector <memory_info *> & known_versions)
}
else
{
((shm_cmd *)d->my_shm)->pingpong = DFPP_RUNNING;
((shm_cmd *)d->my_shm)->pingpong = CORE_RUNNING;
UnmapViewOfFile(d->my_shm);
d->my_shm = 0;
ReleaseMutex(d->DFCLMutex);
@ -375,8 +375,8 @@ bool Process::suspend()
cerr << "couldn't suspend, already suspended" << endl;
return true;
}
((shm_cmd *)d->my_shm)->pingpong = DFPP_SUSPEND;
if(!d->waitWhile(DFPP_SUSPEND))
((shm_cmd *)d->my_shm)->pingpong = CORE_SUSPEND;
if(!d->waitWhile(CORE_SUSPEND))
{
cerr << "couldn't suspend, DF not responding to commands" << endl;
return false;
@ -395,14 +395,14 @@ bool Process::asyncSuspend()
{
return true;
}
if(((shm_cmd *)d->my_shm)->pingpong == DFPP_SUSPENDED)
if(((shm_cmd *)d->my_shm)->pingpong == CORE_SUSPENDED)
{
d->suspended = true;
return true;
}
else
{
((shm_cmd *)d->my_shm)->pingpong = DFPP_SUSPEND;
((shm_cmd *)d->my_shm)->pingpong = CORE_SUSPEND;
return false;
}
}
@ -424,7 +424,7 @@ bool Process::resume()
cerr << "couldn't resume because of not being suspended" << endl;
return true;
}
((shm_cmd *)d->my_shm)->pingpong = DFPP_RUNNING;
((shm_cmd *)d->my_shm)->pingpong = CORE_RUNNING;
d->suspended = false;
return true;
}
@ -499,11 +499,11 @@ void Process::read (uint32_t src_address, uint32_t size, uint8_t *target_buffer)
// normal read under 1MB
if(size <= SHM_BODY)
{
((shm_read *)d->my_shm)->address = src_address;
((shm_read *)d->my_shm)->length = size;
((shm_addrlen *)d->my_shm)->address = src_address;
((shm_addrlen *)d->my_shm)->length = size;
full_barrier
((shm_read *)d->my_shm)->pingpong = DFPP_READ;
d->waitWhile(DFPP_READ);
((shm_cmd *)d->my_shm)->pingpong = CORE_DFPP_READ;
d->waitWhile(CORE_DFPP_READ);
memcpy (target_buffer, d->my_shm + SHM_HEADER,size);
}
// a big read, we pull data over the shm in iterations
@ -514,11 +514,11 @@ void Process::read (uint32_t src_address, uint32_t size, uint8_t *target_buffer)
while (size)
{
// read to_read bytes from src_cursor
((shm_read *)d->my_shm)->address = src_address;
((shm_read *)d->my_shm)->length = to_read;
((shm_addrlen *)d->my_shm)->address = src_address;
((shm_addrlen *)d->my_shm)->length = to_read;
full_barrier
((shm_read *)d->my_shm)->pingpong = DFPP_READ;
d->waitWhile(DFPP_READ);
((shm_cmd *)d->my_shm)->pingpong = CORE_DFPP_READ;
d->waitWhile(CORE_DFPP_READ);
memcpy (target_buffer, d->my_shm + SHM_HEADER,size);
// decrease size by bytes read
size -= to_read;
@ -533,55 +533,55 @@ void Process::read (uint32_t src_address, uint32_t size, uint8_t *target_buffer)
uint8_t Process::readByte (const uint32_t offset)
{
((shm_read_small *)d->my_shm)->address = offset;
((shm_addr *)d->my_shm)->address = offset;
full_barrier
((shm_read_small *)d->my_shm)->pingpong = DFPP_READ_BYTE;
d->waitWhile(DFPP_READ_BYTE);
return ((shm_retval *)d->my_shm)->value;
((shm_cmd *)d->my_shm)->pingpong = CORE_READ_BYTE;
d->waitWhile(CORE_READ_BYTE);
return ((shm_val *)d->my_shm)->value;
}
void Process::readByte (const uint32_t offset, uint8_t &val )
{
((shm_read_small *)d->my_shm)->address = offset;
((shm_addr *)d->my_shm)->address = offset;
full_barrier
((shm_read_small *)d->my_shm)->pingpong = DFPP_READ_BYTE;
d->waitWhile(DFPP_READ_BYTE);
val = ((shm_retval *)d->my_shm)->value;
((shm_cmd *)d->my_shm)->pingpong = CORE_READ_BYTE;
d->waitWhile(CORE_READ_BYTE);
val = ((shm_val *)d->my_shm)->value;
}
uint16_t Process::readWord (const uint32_t offset)
{
((shm_read_small *)d->my_shm)->address = offset;
((shm_addr *)d->my_shm)->address = offset;
full_barrier
((shm_read_small *)d->my_shm)->pingpong = DFPP_READ_WORD;
d->waitWhile(DFPP_READ_WORD);
return ((shm_retval *)d->my_shm)->value;
((shm_cmd *)d->my_shm)->pingpong = CORE_READ_WORD;
d->waitWhile(CORE_READ_WORD);
return ((shm_val *)d->my_shm)->value;
}
void Process::readWord (const uint32_t offset, uint16_t &val)
{
((shm_read_small *)d->my_shm)->address = offset;
((shm_addr *)d->my_shm)->address = offset;
full_barrier
((shm_read_small *)d->my_shm)->pingpong = DFPP_READ_WORD;
d->waitWhile(DFPP_READ_WORD);
val = ((shm_retval *)d->my_shm)->value;
((shm_cmd *)d->my_shm)->pingpong = CORE_READ_WORD;
d->waitWhile(CORE_READ_WORD);
val = ((shm_val *)d->my_shm)->value;
}
uint32_t Process::readDWord (const uint32_t offset)
{
((shm_read_small *)d->my_shm)->address = offset;
((shm_addr *)d->my_shm)->address = offset;
full_barrier
((shm_read_small *)d->my_shm)->pingpong = DFPP_READ_DWORD;
d->waitWhile(DFPP_READ_DWORD);
return ((shm_retval *)d->my_shm)->value;
((shm_cmd *)d->my_shm)->pingpong = CORE_READ_DWORD;
d->waitWhile(CORE_READ_DWORD);
return ((shm_val *)d->my_shm)->value;
}
void Process::readDWord (const uint32_t offset, uint32_t &val)
{
((shm_read_small *)d->my_shm)->address = offset;
((shm_addr *)d->my_shm)->address = offset;
full_barrier
((shm_read_small *)d->my_shm)->pingpong = DFPP_READ_DWORD;
d->waitWhile(DFPP_READ_DWORD);
val = ((shm_retval *)d->my_shm)->value;
((shm_cmd *)d->my_shm)->pingpong = CORE_READ_DWORD;
d->waitWhile(CORE_READ_DWORD);
val = ((shm_val *)d->my_shm)->value;
}
/*
@ -590,30 +590,30 @@ void Process::readDWord (const uint32_t offset, uint32_t &val)
void Process::writeDWord (uint32_t offset, uint32_t data)
{
((shm_write_small *)d->my_shm)->address = offset;
((shm_write_small *)d->my_shm)->value = data;
((shm_addrval *)d->my_shm)->address = offset;
((shm_addrval *)d->my_shm)->value = data;
full_barrier
((shm_write_small *)d->my_shm)->pingpong = DFPP_WRITE_DWORD;
d->waitWhile(DFPP_WRITE_DWORD);
((shm_cmd *)d->my_shm)->pingpong = CORE_WRITE_DWORD;
d->waitWhile(CORE_WRITE_DWORD);
}
// using these is expensive.
void Process::writeWord (uint32_t offset, uint16_t data)
{
((shm_write_small *)d->my_shm)->address = offset;
((shm_write_small *)d->my_shm)->value = data;
((shm_addrval *)d->my_shm)->address = offset;
((shm_addrval *)d->my_shm)->value = data;
full_barrier
((shm_write_small *)d->my_shm)->pingpong = DFPP_WRITE_WORD;
d->waitWhile(DFPP_WRITE_WORD);
((shm_cmd *)d->my_shm)->pingpong = CORE_WRITE_WORD;
d->waitWhile(CORE_WRITE_WORD);
}
void Process::writeByte (uint32_t offset, uint8_t data)
{
((shm_write_small *)d->my_shm)->address = offset;
((shm_write_small *)d->my_shm)->value = data;
((shm_addrval *)d->my_shm)->address = offset;
((shm_addrval *)d->my_shm)->value = data;
full_barrier
((shm_write_small *)d->my_shm)->pingpong = DFPP_WRITE_BYTE;
d->waitWhile(DFPP_WRITE_BYTE);
((shm_cmd *)d->my_shm)->pingpong = CORE_WRITE_BYTE;
d->waitWhile(CORE_WRITE_BYTE);
}
void Process::write (uint32_t dst_address, uint32_t size, uint8_t *source_buffer)
@ -621,12 +621,12 @@ void Process::write (uint32_t dst_address, uint32_t size, uint8_t *source_buffer
// normal write under 1MB
if(size <= SHM_BODY)
{
((shm_write *)d->my_shm)->address = dst_address;
((shm_write *)d->my_shm)->length = size;
((shm_addrlen *)d->my_shm)->address = dst_address;
((shm_addrlen *)d->my_shm)->length = size;
memcpy(d->my_shm+SHM_HEADER,source_buffer, size);
full_barrier
((shm_write *)d->my_shm)->pingpong = DFPP_WRITE;
d->waitWhile(DFPP_WRITE);
((shm_cmd *)d->my_shm)->pingpong = CORE_WRITE;
d->waitWhile(CORE_WRITE);
}
// a big write, we push this over the shm in iterations
else
@ -636,12 +636,12 @@ void Process::write (uint32_t dst_address, uint32_t size, uint8_t *source_buffer
while (size)
{
// write to_write bytes to dst_cursor
((shm_write *)d->my_shm)->address = dst_address;
((shm_write *)d->my_shm)->length = to_write;
((shm_addrlen *)d->my_shm)->address = dst_address;
((shm_addrlen *)d->my_shm)->length = to_write;
memcpy(d->my_shm+SHM_HEADER,source_buffer, to_write);
full_barrier
((shm_write *)d->my_shm)->pingpong = DFPP_WRITE;
d->waitWhile(DFPP_WRITE);
((shm_cmd *)d->my_shm)->pingpong = CORE_WRITE;
d->waitWhile(CORE_WRITE);
// decrease size by bytes written
size -= to_write;
// move the cursors
@ -692,11 +692,11 @@ DfVector Process::readVector (uint32_t offset, uint32_t item_size)
const std::string Process::readSTLString(uint32_t offset)
{
//offset -= 4; //msvc std::string pointers are 8 bytes ahead of their data, not 4
((shm_read_small *)d->my_shm)->address = offset;
((shm_addr *)d->my_shm)->address = offset;
full_barrier
((shm_read_small *)d->my_shm)->pingpong = DFPP_READ_STL_STRING;
d->waitWhile(DFPP_READ_STL_STRING);
int length = ((shm_retval *)d->my_shm)->value;
((shm_cmd *)d->my_shm)->pingpong = CORE_READ_STL_STRING;
d->waitWhile(CORE_READ_STL_STRING);
int length = ((shm_val *)d->my_shm)->value;
// char temp_c[256];
// strncpy(temp_c, d->my_shm+SHM_HEADER,length+1); // length + 1 for the null terminator
return(string(d->my_shm+SHM_HEADER));
@ -705,11 +705,11 @@ const std::string Process::readSTLString(uint32_t offset)
size_t Process::readSTLString (uint32_t offset, char * buffer, size_t bufcapacity)
{
//offset -= 4; //msvc std::string pointers are 8 bytes ahead of their data, not 4
((shm_read_small *)d->my_shm)->address = offset;
((shm_addr *)d->my_shm)->address = offset;
full_barrier
((shm_read_small *)d->my_shm)->pingpong = DFPP_READ_STL_STRING;
d->waitWhile(DFPP_READ_STL_STRING);
size_t length = ((shm_retval *)d->my_shm)->value;
((shm_cmd *)d->my_shm)->pingpong = CORE_READ_STL_STRING;
d->waitWhile(CORE_READ_STL_STRING);
size_t length = ((shm_val *)d->my_shm)->value;
size_t real = min(length, bufcapacity - 1);
strncpy(buffer, d->my_shm+SHM_HEADER,real); // length + 1 for the null terminator
buffer[real] = 0;
@ -718,11 +718,11 @@ size_t Process::readSTLString (uint32_t offset, char * buffer, size_t bufcapacit
void Process::writeSTLString(const uint32_t address, const std::string writeString)
{
((shm_write_small *)d->my_shm)->address = address/*-4*/;
((shm_addr *)d->my_shm)->address = address/*-4*/;
strncpy(d->my_shm+SHM_HEADER,writeString.c_str(),writeString.length()+1); // length + 1 for the null terminator
full_barrier
((shm_write_small *)d->my_shm)->pingpong = DFPP_WRITE_STL_STRING;
d->waitWhile(DFPP_WRITE_STL_STRING);
((shm_cmd *)d->my_shm)->pingpong = CORE_WRITE_STL_STRING;
d->waitWhile(CORE_WRITE_STL_STRING);
}
string Process::readClassName (uint32_t vptr)

File diff suppressed because it is too large Load Diff

@ -5,7 +5,7 @@ shms.h
)
SET(PROJECT_SRCS
shms-proto.cpp
shms-core.cpp
)
SET(PROJECT_HDRS_LINUX

@ -0,0 +1,274 @@
/*
www.sourceforge.net/projects/dfhack
Copyright (c) 2009 Petr Mrázek (peterix)
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any
damages arising from the use of this software.
Permission is granted to anyone to use this software for any
purpose, including commercial applications, and to alter it and
redistribute it freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must
not claim that you wrote the original software. If you use this
software in a product, an acknowledgment in the product documentation
would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and
must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source
distribution.
*/
/**
* This is the source for the DF <-> dfhack shm bridge's core module.
*/
#include <stdio.h>
#include "../library/integers.h"
#include <stdlib.h>
#include <string.h>
#include <string>
#include <vector>
#include "shms.h"
enum DFPP_CmdType
{
CANCELLATION, // we should jump out of the Act()
CLIENT_WAIT, // we are waiting for the client
FUNCTION, // we call a function as a result of the command
};
struct DFPP_command
{
DFPP_CmdType type:32; // force the enum to 32 bits for compatibility reasons
std::string name;
void (*_function)(void);
};
struct DFPP_module
{
inline void push_command(DFPP_CmdType type, const char * name, void (*_function)(void))
{
DFPP_command cmd;
cmd.type = type;
cmd.name = name;
cmd._function = _function;
commands.push_back(cmd);
}
inline void set_command(unsigned int index, DFPP_CmdType type, const char * name, void (*_function)(void))
{
DFPP_command cmd;
cmd.type = type;
cmd.name = name;
cmd._function = _function;
commands[index] = cmd;
}
inline void reserve (unsigned int numcommands)
{
commands.clear();
DFPP_command cmd = {CANCELLATION,"",0};
commands.resize(numcommands,cmd);
}
std::string name;
uint32_t version; // version
std::vector <DFPP_command> commands;
void * modulestate;
};
std::vector <DFPP_module> module_registry;
// various crud
extern int errorstate;
extern char *shm;
extern int shmid;
#define SHMHDR ((shm_header *)shm)
#define SHMCMD ((shm_cmd *)shm)->pingpong
void GetCoreVersion (void)
{
SHMHDR->value = module_registry[0].version;
full_barrier
SHMCMD = CORE_RET_VERSION;
}
void GetPID (void)
{
SHMHDR->value = OS_getPID();
full_barrier
SHMCMD = CORE_RET_PID;
}
void ReadRaw (void)
{
memcpy(shm + SHM_HEADER, (void *) SHMHDR->address,SHMHDR->length);
full_barrier
SHMCMD = CORE_RET_DATA;
}
void ReadDWord (void)
{
SHMHDR->value = *((uint32_t*) SHMHDR->address);
full_barrier
SHMCMD = CORE_RET_DWORD;
}
void ReadWord (void)
{
SHMHDR->value = *((uint16_t*) SHMHDR->address);
full_barrier
SHMCMD = CORE_RET_WORD;
}
void ReadByte (void)
{
SHMHDR->value = *((uint8_t*) SHMHDR->address);
full_barrier
SHMCMD = CORE_RET_BYTE;
}
void WriteRaw (void)
{
memcpy((void *)SHMHDR->address, shm + SHM_HEADER,SHMHDR->length);
full_barrier
SHMCMD = CORE_SUSPENDED;
}
void WriteDWord (void)
{
(*(uint32_t*)SHMHDR->address) = SHMHDR->value;
full_barrier
SHMCMD = CORE_SUSPENDED;
}
void WriteWord (void)
{
(*(uint16_t*)SHMHDR->address) = SHMHDR->value;
full_barrier
SHMCMD = CORE_SUSPENDED;
}
void WriteByte (void)
{
(*(uint8_t*)SHMHDR->address) = SHMHDR->value;
full_barrier
SHMCMD = CORE_SUSPENDED;
}
void ReadSTLString (void)
{
std::string * myStringPtr = (std::string *) SHMHDR->address;
unsigned int l = myStringPtr->length();
SHMHDR->value = l;
// there doesn't have to be a null terminator!
strncpy(shm+SHM_HEADER,myStringPtr->c_str(),l+1);
full_barrier
SHMCMD = CORE_RET_STRING;
}
void WriteSTLString (void)
{
std::string * myStringPtr = (std::string *) SHMHDR->address;
// here we DO expect a 0 terminator
myStringPtr->assign((const char *) (shm + SHM_HEADER));
full_barrier
SHMCMD = CORE_SUSPENDED;
}
void Suspend (void)
{
SHMCMD = CORE_SUSPENDED;
}
void InitCore(void)
{
DFPP_module core;
core.name = "Core";
core.version = CORE_VERSION;
core.modulestate = 0; // this one is dumb and has no real state
core.reserve(NUM_CORE_CMDS);
core.set_command(CORE_RUNNING, CANCELLATION, "Running", NULL);
core.set_command(CORE_GET_VERSION, FUNCTION,"Get core version",GetCoreVersion);
core.set_command(CORE_RET_VERSION, CLIENT_WAIT,"Core version return",0);
core.set_command(CORE_GET_PID, FUNCTION, "Get PID", GetPID);
core.set_command(CORE_RET_PID, CLIENT_WAIT, "PID return", 0);
core.set_command(CORE_DFPP_READ, FUNCTION,"Raw read",ReadRaw);
core.set_command(CORE_RET_DATA, CLIENT_WAIT,"Raw read return",0);
core.set_command(CORE_READ_DWORD, FUNCTION,"Read DWORD",ReadDWord);
core.set_command(CORE_RET_DWORD, CLIENT_WAIT,"Read DWORD return",0);
core.set_command(CORE_READ_WORD, FUNCTION,"Read WORD",ReadWord);
core.set_command(CORE_RET_WORD, CLIENT_WAIT,"Read WORD return",0);
core.set_command(CORE_READ_BYTE, FUNCTION,"Read BYTE",ReadByte);
core.set_command(CORE_RET_BYTE, CLIENT_WAIT,"Read BYTE return",0);
core.set_command(CORE_SV_ERROR, CANCELLATION, "Server error", 0);
core.set_command(CORE_CL_ERROR, CANCELLATION, "Client error", 0);
core.set_command(CORE_WRITE, FUNCTION, "Raw write", WriteRaw);
core.set_command(CORE_WRITE_DWORD, FUNCTION, "Write DWORD", WriteDWord);
core.set_command(CORE_WRITE_WORD, FUNCTION, "Write WORD", WriteWord);
core.set_command(CORE_WRITE_BYTE, FUNCTION, "Write BYTE", WriteByte);
core.set_command(CORE_SUSPEND, FUNCTION, "Suspend", Suspend);
core.set_command(CORE_SUSPENDED, CLIENT_WAIT, "Suspended", 0);
core.set_command(CORE_READ_STL_STRING, FUNCTION, "Read STL string", ReadSTLString);
core.set_command(CORE_READ_C_STRING, CLIENT_WAIT, "RESERVED", 0);
core.set_command(CORE_RET_STRING, CLIENT_WAIT, "Return string", 0);
core.set_command(CORE_WRITE_STL_STRING, FUNCTION, "Write STL string", WriteSTLString);
module_registry.push_back(core);
}
void InitModules (void)
{
// create the core module
InitCore();
}
void SHM_Act (void)
{
if(errorstate)
{
return;
}
uint32_t numwaits = 0;
check_again: // goto target!!!
if(numwaits == 10000)
{
// this tests if there's a process on the other side
if(isValidSHM())
{
numwaits = 0;
}
else
{
full_barrier
SHMCMD = CORE_RUNNING;
fprintf(stderr,"dfhack: Broke out of loop, other process disappeared.\n");
}
}
DFPP_module & mod = module_registry[((shm_cmd *)shm)->parts.module];
DFPP_command & cmd = mod.commands[((shm_cmd *)shm)->parts.command];
//fprintf(stderr, "Client invoked %s\n", cmd.name.c_str() );
if(cmd._function)
{
cmd._function();
}
if(cmd.type != CANCELLATION)
{
SCHED_YIELD
numwaits ++; // watchdog timeout
goto check_again;
}
}

@ -34,6 +34,8 @@ distribution.
#include <sys/types.h>
#include <sys/ipc.h>
#include <unistd.h>
#include <vector>
#include <string>
#include "shms.h"
#include <sys/time.h>
#include <time.h>
@ -62,7 +64,7 @@ bool isValidSHM()
//fprintf(stderr,"ID %d, attached: %d\n",shmid, descriptor.shm_nattch);
return (descriptor.shm_nattch == 2);
}
uint32_t getPID()
uint32_t OS_getPID()
{
return getpid();
}
@ -109,7 +111,8 @@ void SHM_Init ( void )
}
full_barrier
// make sure we don't stall or do crazy stuff
((shm_cmd *)shm)->pingpong = DFPP_RUNNING;
((shm_cmd *)shm)->pingpong = CORE_RUNNING;
InitModules();
}
void SHM_Destroy ( void )
@ -144,7 +147,7 @@ DFhackCExport void SDL_GL_SwapBuffers(void)
{
if(_SDL_GL_SwapBuffers)
{
if(!errorstate && ((shm_cmd *)shm)->pingpong != DFPP_RUNNING)
if(!errorstate && ((shm_cmd *)shm)->pingpong != CORE_RUNNING)
{
SHM_Act();
}
@ -158,7 +161,7 @@ DFhackCExport int SDL_Flip(void * some_ptr)
{
if(_SDL_Flip)
{
if(!errorstate && ((shm_cmd *)shm)->pingpong != DFPP_RUNNING)
if(!errorstate && ((shm_cmd *)shm)->pingpong != CORE_RUNNING)
{
SHM_Act();
}
@ -216,7 +219,7 @@ DFhackCExport int refresh (void)
{
if(_refresh)
{
if(!errorstate && ((shm_cmd *)shm)->pingpong != DFPP_RUNNING)
if(!errorstate && ((shm_cmd *)shm)->pingpong != CORE_RUNNING)
{
SHM_Act();
}

@ -1,187 +0,0 @@
/*
www.sourceforge.net/projects/dfhack
Copyright (c) 2009 Petr Mrázek (peterix)
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any
damages arising from the use of this software.
Permission is granted to anyone to use this software for any
purpose, including commercial applications, and to alter it and
redistribute it freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must
not claim that you wrote the original software. If you use this
software in a product, an acknowledgment in the product documentation
would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and
must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source
distribution.
*/
/**
* This is the source for the DF <-> dfhack shm bridge, server protocol part
*/
#include <stdio.h>
#include "../library/integers.h"
#include <stdlib.h>
#include <string.h>
#include <string>
//#include <unistd.h>
#include "shms.h"
// various crud
extern int errorstate;
extern char *shm;
extern int shmid;
void SHM_Act (void)
{
if(errorstate)
{
return;
}
uint32_t numwaits = 0;
uint32_t length;
uint32_t address;
std::string * myStringPtr;
check_again: // goto target!!!
SCHED_YIELD // yield the CPU, valid only on single-core CPUs
if(numwaits == 10000)
{
// this tests if there's a process on the other side
if(isValidSHM())
{
numwaits = 0;
}
else
{
full_barrier
((shm_cmd *)shm)->pingpong = DFPP_RUNNING;
fprintf(stderr,"dfhack: Broke out of loop, other process disappeared.\n");
//MessageBox(0,"Broke out of loop, other process disappeared.","FUN", MB_OK);
}
}
switch (((shm_cmd *)shm)->pingpong)
{
case DFPP_RET_VERSION:
case DFPP_RET_DATA:
case DFPP_RET_DWORD:
case DFPP_RET_WORD:
case DFPP_RET_BYTE:
case DFPP_RET_STRING:
case DFPP_SUSPENDED:
case DFPP_RET_PID:
case DFPP_SV_ERROR:
numwaits++;
goto check_again;
case DFPP_SUSPEND:
full_barrier
((shm_cmd *)shm)->pingpong = DFPP_SUSPENDED;
goto check_again;
/*
case DFPP_BOUNCE:
length = ((shm_bounce *)shm)->length;
memcpy(BigFat,shm + SHM_HEADER,length);
memcpy(shm + SHM_HEADER,BigFat,length);
((shm_cmd *)shm)->pingpong = DFPP_RET_DATA;
goto check_again;
*/
case DFPP_PID:
((shm_retval *)shm)->value = getPID();
full_barrier
((shm_retval *)shm)->pingpong = DFPP_RET_PID;
goto check_again;
case DFPP_VERSION:
((shm_retval *)shm)->value = PINGPONG_VERSION;
full_barrier
((shm_retval *)shm)->pingpong = DFPP_RET_VERSION;
goto check_again;
case DFPP_READ:
length = ((shm_read *)shm)->length;
address = ((shm_read *)shm)->address;
memcpy(shm + SHM_HEADER, (void *) address,length);
full_barrier
((shm_cmd *)shm)->pingpong = DFPP_RET_DATA;
goto check_again;
case DFPP_READ_DWORD:
address = ((shm_read_small *)shm)->address;
((shm_retval *)shm)->value = *((uint32_t*) address);
full_barrier
((shm_retval *)shm)->pingpong = DFPP_RET_DWORD;
goto check_again;
case DFPP_READ_WORD:
address = ((shm_read_small *)shm)->address;
((shm_retval *)shm)->value = *((uint16_t*) address);
full_barrier
((shm_retval *)shm)->pingpong = DFPP_RET_WORD;
goto check_again;
case DFPP_READ_BYTE:
address = ((shm_read_small *)shm)->address;
((shm_retval *)shm)->value = *((uint8_t*) address);
full_barrier
((shm_retval *)shm)->pingpong = DFPP_RET_BYTE;
goto check_again;
case DFPP_WRITE:
address = ((shm_write *)shm)->address;
length = ((shm_write *)shm)->length;
memcpy((void *)address, shm + SHM_HEADER,length);
full_barrier
((shm_cmd *)shm)->pingpong = DFPP_SUSPENDED;
goto check_again;
case DFPP_WRITE_DWORD:
(*(uint32_t*)((shm_write_small *)shm)->address) = ((shm_write_small *)shm)->value;
full_barrier
((shm_cmd *)shm)->pingpong = DFPP_SUSPENDED;
goto check_again;
case DFPP_WRITE_WORD:
(*(uint16_t*)((shm_write_small *)shm)->address) = ((shm_write_small *)shm)->value;
full_barrier
((shm_cmd *)shm)->pingpong = DFPP_SUSPENDED;
goto check_again;
case DFPP_WRITE_BYTE:
(*(uint8_t*)((shm_write_small *)shm)->address) = ((shm_write_small *)shm)->value;
full_barrier
((shm_cmd *)shm)->pingpong = DFPP_SUSPENDED;
goto check_again;
case DFPP_CL_ERROR:
case DFPP_RUNNING:
//fprintf(stderr, "no. of waits: %d\n", numwaits);
//MessageBox(0,"Broke out of loop properly","FUN", MB_OK);
break;
case DFPP_READ_STL_STRING:
myStringPtr = (std::string *) ((shm_read_small *)shm)->address;
((shm_retval *)shm)->value = myStringPtr->length();
strncpy(shm+SHM_HEADER,myStringPtr->c_str(),myStringPtr->length()+1);// length + 1 for the null terminator
full_barrier
((shm_retval *)shm)->pingpong = DFPP_RET_STRING;
goto check_again;
case DFPP_WRITE_STL_STRING:
myStringPtr = (std::string *) ((shm_write *)shm)->address;
myStringPtr->assign((const char *) (shm + SHM_HEADER));
full_barrier
((shm_cmd *)shm)->pingpong = DFPP_SUSPENDED;
goto check_again;
default:
((shm_retval *)shm)->value = DFEE_INVALID_COMMAND;
full_barrier
((shm_retval *)shm)->pingpong = DFPP_SV_ERROR;
break;
}
}

@ -34,8 +34,10 @@ distribution.
#define DFhackCExport extern "C" __declspec(dllexport)
#include "../library/integers.h"
#include <vector>
#include <string>
#include "shms.h"
#include <stdio.h>
#include <cstdio>
int errorstate = 0;
char *shm = 0;
int shmid = 0;
@ -131,8 +133,7 @@ void SHM_Init ( void )
shm = (char *) MapViewOfFile(shmHandle,FILE_MAP_ALL_ACCESS, 0,0, SHM_SIZE);
if(shm)
{
((shm_cmd *)shm)->pingpong = DFPP_RUNNING;
//MessageBox(0,"Sucessfully mapped SHM","FUN", MB_OK);
((shm_cmd *)shm)->pingpong = CORE_RUNNING;
}
else
{
@ -142,6 +143,7 @@ void SHM_Init ( void )
CloseHandle(DFSVMutex);
CloseHandle(DFCLMutex);
}
InitModules();
}
void SHM_Destroy ( void )
@ -153,7 +155,7 @@ void SHM_Destroy ( void )
CloseHandle(DFCLMutex);
}
uint32_t getPID()
uint32_t OS_getPID()
{
return GetCurrentProcessId();
}
@ -665,7 +667,7 @@ DFhackCExport void SDL_Quit(void)
static void (*_SDL_GL_SwapBuffers)(void) = 0;
DFhackCExport void SDL_GL_SwapBuffers(void)
{
if(!errorstate && ((shm_cmd *)shm)->pingpong != DFPP_RUNNING)
if(!errorstate && ((shm_cmd *)shm)->pingpong != CORE_RUNNING)
{
SHM_Act();
}
@ -678,7 +680,7 @@ DFhackCExport int SDL_Flip(void * some_ptr)
{
if(_SDL_Flip)
{
if(!errorstate && ((shm_cmd *)shm)->pingpong != DFPP_RUNNING)
if(!errorstate && ((shm_cmd *)shm)->pingpong != CORE_RUNNING)
{
SHM_Act();
}

@ -1,10 +1,10 @@
#ifndef DFCONNECT_H
#define DFCONNECT_H
#define PINGPONG_VERSION 2
#define CORE_VERSION 3
#define SHM_KEY 123466
#define SHM_HEADER 1024
#define SHM_BODY 1024*1024
#define SHM_HEADER 1024 // 1kB reserved for a header
#define SHM_BODY 1024*1024 // 1MB reserved for bulk data transfer
#define SHM_SIZE SHM_HEADER+SHM_BODY
@ -32,14 +32,6 @@
#endif
#endif
/*
* read - parameters are address and length
* write - parameters are address, length and the actual data to write
* wait - sent to DF so that it waits for more commands
* end - sent to DF for breaking out of the wait
*/
enum DF_SHM_ERRORSTATE
{
SHM_OK, // all OK
@ -48,51 +40,51 @@ enum DF_SHM_ERRORSTATE
SHM_SECOND_DF // we are a second DF process, can't use SHM at all
};
enum DF_PINGPONG
enum CORE_COMMAND
{
DFPP_RUNNING = 0, // no command, normal server execution
CORE_RUNNING = 0, // no command, normal server execution
DFPP_VERSION, // protocol version query
DFPP_RET_VERSION, // return the protocol version
CORE_GET_VERSION, // protocol version query
CORE_RET_VERSION, // return the protocol version
DFPP_PID, // query for the process ID
DFPP_RET_PID, // return process ID
CORE_GET_PID, // query for the process ID
CORE_RET_PID, // return process ID
// version 1 stuff below
DFPP_READ, // cl -> sv, read some data
DFPP_RET_DATA, // sv -> cl, returned data
CORE_DFPP_READ, // cl -> sv, read some data
CORE_RET_DATA, // sv -> cl, returned data
DFPP_READ_DWORD, // cl -> sv, read a dword
DFPP_RET_DWORD, // sv -> cl, returned dword
CORE_READ_DWORD, // cl -> sv, read a dword
CORE_RET_DWORD, // sv -> cl, returned dword
DFPP_READ_WORD, // cl -> sv, read a word
DFPP_RET_WORD, // sv -> cl, returned word
CORE_READ_WORD, // cl -> sv, read a word
CORE_RET_WORD, // sv -> cl, returned word
DFPP_READ_BYTE, // cl -> sv, read a byte
DFPP_RET_BYTE, // sv -> cl, returned byte
CORE_READ_BYTE, // cl -> sv, read a byte
CORE_RET_BYTE, // sv -> cl, returned byte
DFPP_SV_ERROR, // there was a server error
DFPP_CL_ERROR, // there was a client error
CORE_SV_ERROR, // there was a server error
CORE_CL_ERROR, // there was a client error
DFPP_WRITE,// client writes to server
DFPP_WRITE_DWORD,// client writes a DWORD to server
DFPP_WRITE_WORD,// client writes a WORD to server
DFPP_WRITE_BYTE,// client writes a BYTE to server
CORE_WRITE,// client writes to server
CORE_WRITE_DWORD,// client writes a DWORD to server
CORE_WRITE_WORD,// client writes a WORD to server
CORE_WRITE_BYTE,// client writes a BYTE to server
DFPP_SUSPEND, // client notifies server to wait for commands (server is stalled in busy wait)
DFPP_SUSPENDED, // response to WAIT, server is stalled in busy wait
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
// all strings capped at 1MB
DFPP_READ_STL_STRING,// client requests contents of STL string at address
DFPP_READ_C_STRING,// client requests contents of a C string at address, max length (0 means zero terminated)
DFPP_RET_STRING, // sv -> cl length + string contents
DFPP_WRITE_STL_STRING,// client wants to set STL string at address to something
CORE_READ_STL_STRING,// client requests contents of STL string at address
CORE_READ_C_STRING,// client requests contents of a C string at address, max length (0 means zero terminated)
CORE_RET_STRING, // sv -> cl length + string contents
CORE_WRITE_STL_STRING,// client wants to set STL string at address to something
// vector elements > 1MB are not supported because they don't fit into the shared memory
DFPP_READ_ENTIRE_VECTOR, // read an entire vector (parameters are address of vector object and size of items)
DFPP_RET_VECTOR_BODY, // a part of a vector is returned - no. of elements returned, no. of elements total, elements
// compare affinity and determine if using yield is required
CORE_SYNC_YIELD,// cl sends affinity to sv, sv sets yield
CORE_SYNC_YIELD_RET,// sv returns yield bool
NUM_DFPP
NUM_CORE_CMDS
};
@ -102,54 +94,31 @@ enum DF_ERROR
DFEE_BUFFER_OVERFLOW
};
typedef struct
{
volatile uint32_t pingpong; // = 0
} shm_cmd;
typedef struct
{
volatile uint32_t pingpong;
uint32_t address;
uint32_t length;
} shm_read;
typedef shm_read shm_write;
typedef shm_read shm_bounce;
typedef struct
typedef union
{
struct
{
volatile uint16_t command;
volatile uint16_t module;
} parts;
volatile uint32_t pingpong;
} shm_ret_data;
typedef struct
{
volatile uint32_t pingpong;
uint32_t address;
} shm_read_small;
inline void set(uint16_t module, uint16_t command)
{
pingpong = module + command << 16;
}
} shm_cmd;
typedef struct
{
volatile uint32_t pingpong;
shm_cmd cmd;
uint32_t address;
uint32_t value;
} shm_write_small;
typedef struct
{
volatile uint32_t pingpong;
uint32_t value;
} shm_retval;
typedef struct
{
volatile uint32_t pingpong;
uint32_t length;
} shm_retstr;
} shm_header;
void SHM_Act (void);
void InitModules (void);
bool isValidSHM();
uint32_t getPID();
uint32_t OS_getPID();
#endif