                  Memory Mapped Files Emulation Layer v1.77
               (c) 1998, 1999 Maurilio Longo - md2520@mclink.it

                                   - * -

This is a brief document about mmap.dll, if you don't know what memory mapped
files are then this .dll is not for you :-)

This .dll is freeware (you can use and redistribute it whitout any charge) but
I retain all rights upon it. Standard disclaimer applies :-) i.e. I'm not
responsible for any damages arising from its use or misuse.

                           USE IT AT YOUR OWN RISK.

This .dll provides mmap() services to OS/2 processes. It is intended as a tool
for programmers porting unix software to OS/2 and / or for programmers 
developing native OS/2 programs.

It is already used on mSLQ/2 (actually it was developed for mSQL/2). You can find
more info about mSQL at this address: http://blnet.com/msqlpc/


In this package you'll find several files:

mmap.dll    :  the emulation layer, it should go on a directory listed on your
               LIBPATH;
mmap.lib    :  import library for OMF linker (like link386.exe);
mmap.a      :  import library for EMX/GCC ld.exe (a.out format);
mman.h      :  include file for C programmers;
mmap.txt    :  this text file you're already reading :-)
history.txt :  list of changes.
ealib.h	    :  Extended Attribute Library include file, added since this version
	       uses it and copyright requires its presence.


Since it is an *emulation* of mmap() services it has a few restrictions/limits
that you should be aware of and care:

1) You can have only one mapped region per file, this is a limit which will be
   raised on a future release.

2) You cannot share a mapped region between processes (or address spaces), this
   is a permanent restriction arising from the fact that mmap.dll runs with
   user privileges and needs to be able to commit / decommit memory pages.

2b)Starting with version 1.75 MAP_SHARED is supported inside same address space, 
   ie you  can have, for example, more than one thread which issues a mmap() call 
   with MAP_SHARED for the same file descriptor.

3) On Warp Server Advanced SMP and Aurora HighMemory is used so you can map up 
   to 2Gb of address space. 
   On Warp 3 and 4 you cannot mmap() more than 300 / 350 Mb per process, this is 
   a limit of OS/2.
   On WSA SMP and Aurora you can have VIRTUALADDRESSLIMIT=3072 in your config.sys, 
   but be aware of the fact that mmap.dll can handle a maximum of 2Gb of addresses. 
   So if OS/2 returns an address > 2Gb behaviour is unpredictable.

4) All standard flags of mman.h are defined but only a few are used. You cannot 
   protect or lock memory regions and you should not rely on access flags. 
   All mapped pages are read only until a write access occurs. 
   This is a permanent restriction.

5) Starting with version 1.77 msync() can be synchronous or asynchronous and should be 
   called from time to time to sync modified pages to disk. 
   If you never call it syncing will be done at the time of munmap() call. 
   MS_INVALIDATE is supported and causes all pages to be discarded without writing
   modified ones to disk.
   
6) There is a non-standard constant MS_MUNMAP (0x10) which is used by munmap()
   to signal to msync() that it has been called by munmap(). This makes msync()
   faster.

7) There is a non-standard function merror() which returns last error of calling
   thread (and resets it).

8) Starting with version 1.75 there are two functions to register/deregister mmap()
   services on a per thread basis. 
   To succeed in registering mmap() you should define a variable of type mmap_reg_t
   on the stack of the calling thread.

   ie, in C pseudo code :-)

   void main() 
   {
   ...
   mmap_reg_t mmap_reg
   ...
   if (mregister(&mmap_reg) == 0) {
	...
	... mmap(....)
	... munmap(...)
	...
	mderegister(&mmap_reg)
   }
   ...
   return 0
   }

8b) mmap() works using an exception handler, so if you register your own exception handler
    mregister() should be called AFTER your call to register your own exception handler
    or mmap() could never be called to handle access to mmapped pages. mmap() gives
    control back to OS/2 exceptions handling chain if the exception is not an access 
    violation and the address is not inside a mmapped object.

9) MAP_SHARED support uses EAs to keep track of mappings. Every effort has been made to
   try to clean mmapped files from EA used by mmap(). If, nonetheless, the process using
   mmap() is killed or the PC running it is reset EAs may remain. 
   The EA used is MMAP.HFILE and is of type ASCII. Every time a file is mmapped with 
   MAP_SHARED this EA is added to it and the value is a string of the form NNNNN:FFFF 
   were NNNNN: is the number of milliseconds since last reboot at the time of mmap.dll 
   initialization and FFFF is the file handle of first mmapping.
   Since EAs are used the filesystem holding mmapped files has to support them 
   (ext2, for example, has no support for them, while JFS is OK). 
   Mmap.dll makes no test to ensure that EAs are supported. So you (the programmer 
   using this .dll) have to make this test and complain if something is wrong.

The mmap() emulation dll exports the following functions (here listed using 
pascal notation since this library has been developed with VirtualPascal/2 v1.1):

Type
   caddr_t  	=  Pointer;             // C types for mmap functions
   off_t    	=  longint;
   size_t   	=  longint;
   int      	=  longint;
   mmap_reg_t	=  ExceptionRegistrationRecord;

// Returns size in bytes of a memory page
function getpagesize: int;

// Stub function, returns -1 and sets merror to EAGAIN
function mprotect(pAddr: caddr_t;  cbLen, fProtection: int): int;

// Stub function, returns -1 and sets merror to EAGAIN
function mlockall(fFlags: int): int;

// Maps a file to a range of addresses in memory.
// pAddr must be 0, otherwise call fails
// cbLen is dimension of region of file to map
// fProtection is here only for compatibility, all pages are readonly and become read/write after a
//             write access to them
// hFile is the handle of mapping file; only one mapping region is available as of version 1.0 of mmap.dll
// cbOffest position in file from which mapping starts
// if something goes wrong it returns -1 and sets merror to appropriate error code
function mmap(pAddr: caddr_t; cbLen: size_t; fProtection, fFlags, hFile: int; cbOffset: off_t): caddr_t;

// Synchronizes pages accessed with a write operation to file, after synchronization pages are converted to
// readonly access; pages with readonly access are decomitted.
// It accepts starting address and len of a mapped region. fFlags is not used but for value
// MS_UNMAP which tells msync that is being called by munmap and so decommitting of readonly pages
// is not necessary.
function msync(pAddr: caddr_t; cbLen: size_t; fFlags: int): int;

// Stub function, always returns 0
function munlockall: int;

// Unmaps a previously mapped region and syncs it to file if necessary
function munmap(pAddr: caddr_t; cbLen: size_t): int;

// Returns, and clears, last error of calling thread
function merror: int;

// Registers mmap services on a per thread basis
function mregister(var Reg: mmap_reg_t): int;

// Deregisters them
function mderegister(var Reg: mmap_reg_t): int;


merror() returns last error occurred to calling thread and clears it; defined
errors are as follows:

EPERM          =     1;              // Operation not permitted
EIO            =     5;              // Input/output error
ENXIO          =     6;              // Device not configured
EBADF          =     9;              // Bad file descriptor
ENOMEM         =     12;             // Cannot allocate memory
EACCES         =     13;             // Permission denied
EBUSY          =     16;             // Device busy
ENODEV         =     19;             // Operation not supported by device
EINVAL         =     22;             // Invalid argument
EMFILE         =     24;             // Too many open files
EAGAIN         =     35;             // Resource temporarily unavailable


This library defines standard flags for mmap(), msync() and munmap() but does
use only a few; so you should not rely on them but at the same time they are
reserved for future use.

HAVE_MSYNC     =     $1;         // msync available
PROT_READ      =     $0001;      // read only access - not used
PROT_WRITE     =     $0002;      // write access     - not used
PROT_EXEC      =     $0004;      // execute access   - not used
PROT_NONE      =     $0000;      // no access        - not used

MAP_SHARED     =     $1;         // shared mapping   - supported inside same address space
MAP_PRIVATE    =     $2;         // private mapping  
MAP_FIXED      =     $10;        // fixed address    - not supported

MCL_CURRENT    =     $1;         // locking options are not supported
MCL_FUTURE     =     $2;

MS_ASYNC       =     $1;         // asynchronous syncing
MS_INVALIDATE  =     $2;         // invalidate pages
MS_SYNC	       =     $4;	 // synchronous syncing

MS_MUNMAP      =     $10;        // Used by munmap() when calling msync()


It's possible to set an environment variable to force the mmap.dll to show infos 
about its inner workings. To enable this capability use

SET MMAPDLL=DEBUG

before starting any process which will use mmap() services.

It's possible to find a more detailed documentation about memory mapped files
at this address http://hoth.stsci.edu/man/man2/mmap.html but please bear in
mind that those are pages about linux / freebsd memory mapped services so they
list capabilities and functions not available with my emulation.

I would like to thank Yuri Dario (mc6530@mclink.it) for his help and tests 
of my .dll. 

Ok, that's all. Please bear with my poor english and happy mmapping :-)) 
I'd like to be informed if you decide to use my library in a program of yours.
