|

Shared Memory
A Unix SVR4 Shared Heap. Handle based and able to expand on demand, unfortunately never used.
Unix shared memory
The multi-user game I was writing back in '94 had come along way since its horrible beginnings in '89 but it was never to see the light of day. The shared heap manager was the last piece that I wrote before I got a job where I could program all day, every day, rather than just after work. Once I started writing code during the day I had less inclination to code after dark. I also bought a flat and (over the course of a few years) ripped it apart and put it back together again (in the evenings...).
The original plan was that the game would would be stored in a dynamic network of "facts" which each client program could access and adjust. This avoided the "all client access to the world going through the server" bottleneck (and added a whole host of locking and race condition problems...). The heart of the system was a shared heap that could overcome the limitations of normal SVR4 shared memory segments... It could grow! Since the whole world was a network of interconnected memory blobs, references to these blobs needed to be valid in all processes. SVR4 shared memory segments couldn't guarantee that for me so I added a level of indirection, and made it all handle based...
Vaguely remembered highlights...
The code worked in DOS or Unix mode. The DOS option was for testing the compile and the non shared-memory side of things. I had a dual boot DOS/Linux box at the time but editing was easier on DOS since I had the Borland IDE, on Linux I had vi or "Joe"? The DOS version used a mono debug monitor for debug output. Cool stuff to be able to pretend to be such a techy - with two screens scrolling gibberish the whole time...
The DOS version sat atop a debugging memory allocation wrapper library which helped track down memory problems pretty fast. The test programs were designed to all be run at once on a Unix box. They worked pretty well...
The locking is quite complex. Standard multiple readers, single writer rules apply but if you try to get a lock of a kind that's not allowed at that time you're request is placed in a FIFO queue and you go to sleep. When a lock is released the queue is walked and processes waiting on locks are signaled to wake them up. If the first lock in the queue is a write lock then only that process is signalled, if there are lots of read locks queued then all will be released. Each process registers an exit handler which will release any locks that the process has if it dies... Obviously there shouldn't be any, and it's dangerous to release a write lock if the process has died whilst scribbling to the memory that it has locked, but at least it prevents deadlocks due to dead processes...
When one shared memory segment became full another would be allocated and used without the user needing to be aware at all. That was pretty cool. The shared memory areas were named too, so the manager could manage multiple different segments for different processes...
It all worked pretty well, I finished it and never did any more with the game. I somehow feel that the design wouldn't have worked, the locking granularity was too fine. I expected clients to lock out just the part of the world they were fiddling with, allowing everyone else to fiddle with their own bits at the same time... It would probably have been faster to have routed all requests through a central source and avoided the handle indirection and complex locking all together. Still, we'll never know now...
Download
The source for the line wrapper was originally DOS or Unix and built with either Borland C++ v3.1 or GNU C on Linux. Like the line wrapper code, I just stuffed it through VC++ v5.0 and commented out any horrible DOSisms. Can't say I tested this "port" very hard though and it certainly hasn't been run on Linux in a while... I put the original Linux makefile in the zip too, just in case...
Download Sheap.zip
|