! ! Copyright (C) 1999 by Fortran Library ! ! This source may be freely copied, modified, or distributed so long as the original ! copyright statement remains intact. ! ! Suggestions for improvment to the original posted version are welcome. Comments ! should be sent to mailto:webmaster@fortranlib.com ! ! ! Library Type: Static ! ! Library Name: ShareBufferWin32 ! ! Library Version: 1.0, 23 July 1999, 19:52:00 ! ! Purpose: Easy Inter-Process Shared Memory Communication Utilities for Win32 using ! a simple FORTRAN 77-style interface. ! ! System Requirements: Written for Digital (Compaq) Visual Fortran (x86) ! ! Limitations: For Windows 95 compatibility buffer size maximum is limited to 2GB. ! Typical intercommunication latency measured under WinNT 4.0 ! on an IBM 300PL, 128MB, 450Mhz: 21 nanosec. Of course this is ! not a guaranteed result. ! ! Requires INTEGER POINTER extension as implemented by Compaq Visual ! Fortran and related DEC/Compaq Fortran products. Also assumes ! Win32 declarations ala CVF in the "DFWIN" module. ! ! ! Routine Name: CreateShareBuffer ! ! Purpose: Create a shared memory buffer for IPC via WIN32 File Mapping ! ! ! Arguments: ! ! buffername: character(*) name of the share buffer (any character except "\") ! numbytes: 1-2GB = number of bytes in the share area in 4096 byte increments ! Note: For example, specifying any value from 1-4096 will produce a buffer ! size of 4096. The true size of the buffer will initially be stored ! in the first 4 bytes (word 1) of the share buffer. ! It will provide the true size of the buffer in 4096 byte ! increments (4096, 8192, 12288, etc.). ! bufferaddress: returned address of the shared buffer ! iretcode: -1 = creation faile ! other = return code from WIN32 CreateFileMapping ! ! Example programming sequence (additional examples at the end): ! ! 1. Program 1 (master process) creates a shared object by calling CreateShareBuffer ! 2. Program 2 (and 3 and ...) gains access to the same shared object by calling OpenShareBuffer ! 3. Programs 1 and 2 (and 3 ...) communicate as required. ! Synchronization is the responsibility of the application(s). ! 4. At completion, programs 2 (and up) terminate by calling CloseShareBuffer ! 5. Program 1 terminates by calling DeleteShareBuffer ! Note: Process 2-x MUST call CloseShareBuffer at termination, else ! DeleteShareBuffer will fail in the master process, resulting in memory leaks. ! ! Synchronization Recommendations: It is recommended that a portion of the share buffer ! be reserved for interprocess communication control and synchronization. At a minimum, ! it is recommended that the master process (program 1 above) be able to signal the ! slave processes when to terminate. A simple flag value should be sufficient. ! One simple method is to reserve the first several words for interprocess communication purposes. ! Word 1 is by default set initially to the buffer size for use by slave processes to determine ! the size ofthe allocated buffer. Word 2 might be defined as a "kill-flag". The master process might ! set the "kill-flag" to 1 (for example) to cause each subordinate process to terminate themselves. ! There is a minor timing issue here in that the master process will need to give the subordinate ! processes time to finish terminating (they will no longer be able to communicate once the share ! buffer access is removed). ! subroutine CreateShareBuffer(bufferName,numBytes,bufferAddress,iRetcode) use dfwin implicit none common /LocalShare/ idMap integer :: idMap character(*), intent(in) :: bufferName integer, intent(in) :: numBytes integer, intent(out) :: iRetcode, bufferAddress integer :: iTemp, mapAddress pointer (mapAddress,iTemp) type (T_SECURITY_ATTRIBUTES) :: nullAttributes ! ! initialize return code ! iretcode = -1 ! ! create shared memory mapping with default/typical values ! nullAttributes % nLength = 0 nullAttributes % lpSecurityDescriptor = 0 nullAttributes % bInheritHandle = .TRUE. idmap = CreateFileMapping (16#FFFFFFFF,& !Use swap file nullAttributes,& !Default security PAGE_READWRITE,& !read/write access 0,& !size less than 2gb numbytes,& !low order size in bytes (multiple of 4096) bufferName // char(0)) !user supplied share name iRetcode = GetLastError() !Return the creation status if (idmap .eq. 0) then !Allocation failed iretcode = -1 return end if mapAddress = MapViewOfFile(idMap, & FILE_MAP_ALL_ACCESS, & 0, & !Map entire file 0, & numBytes) bufferAddress = mapAddress iTemp = (int(numBytes / 4096) + 1) * 4096 !Insert the number of bytes in word 1 return end ! ! Routine: OpenShareBuffer ! ! Purpose: Allow a client process to gain access to a previously created shared memory buffer. ! ! Arguments: ! ! buffername: character(*) name of the share buffer (any character except "\") ! bufferaddress: returned local address map of the shared process ! iretcode: -1 = open failed ! other = return code from WIN32 MapViewOfFile ! subroutine OpenShareBuffer(bufferName,bufferAddress,iRetcode) use dfwin implicit none character(*), intent(in) :: bufferName integer, intent(out) :: bufferAddress integer, intent(out) :: iRetcode integer :: idMap, iTemp, mapAddress pointer (mapAddress,iTemp) ! ! initialize return code ! iretcode = 0 ! ! Map previously created share name to local address space ! idmap = OpenFileMapping(FILE_MAP_WRITE, & !read/write access .true., & !inherit name bufferName // char(0)) !the share name mapAddress = MapViewOfFile(idMap,FILE_MAP_ALL_ACCESS,0,0,0) !Map entire file if (mapAddress .eq. 0) then iRetcode = -1 return end if iRetcode = GetLastError() bufferAddress = mapAddress return end subroutine ! ! Routine: CloseShareBuffer ! ! Purpose: To close the local mapping to the share buffer. ! ! Note: Each process MUST close it's mapping at ! termination in order to allow full cleanup. ! ! Arguments: ! ! bufferaddress = the address of the share buffer ! iretcode = return code result from WIN32 UnmapViewOfFile ! subroutine CloseShareBuffer(bufferAddress,iRetcode) use dfwin implicit none integer, intent(in) :: bufferAddress integer, intent(out) :: iRetcode integer :: idMap, iTemp, mapAddress logical :: status pointer (mapAddress,iTemp) ! ! Map previously created share name to local address space ! mapAddress = bufferAddress status = UnmapViewOfFile(mapAddress) iRetcode = GetLastError() return end subroutine ! ! Routine: DeleteShareBuffer ! ! Purpose: To delete te map id (handle) associated with the share buffer. ! ! Arguments: ! ! bufferaddress = the address of the share buffer ! iretcode = return code result from WIN32 CloseHandle ! subroutine DeleteShareBuffer(bufferAddress,iRetcode) use dfwin implicit none common /LocalShare/ idMap integer :: idMap integer, intent(in) :: bufferAddress integer, intent(out) :: iRetcode integer :: iStatus logical :: status ! ! Close the mapping ! call CloseShareBuffer(bufferAddress,iStatus) ! ! Close the handle ! status = CloseHandle(idMap) iRetcode = GetLastError() return end subroutine ! ! Example Main Program 1 ! ! integer :: iretcode, bufptr, buffer(1024) ! ! pointer (bufptr,buffer) ! ! ! call CreateShareBuffer('TestBuf',4096,bufptr,iretcode) ! ! ! ...code using BUFFER goes here. ! ! ...when finished... ! ! ! call DeleteShareBuffer(bufptr,iretcode) ! ! end ! ! ! ! Example Main Program 2 (3, 4, etc.) ! ! integer :: iretcode, bufptr, buffer(1024) ! ! pointer (bufptr,buffer) ! ! ! call OpenShareBuffer('TestBuf',bufptr,iretcode) ! ! ! ...code using BUFFER goes here. ! ! ...when finished... ! ! ! call CloseShareBuffer(bufptr,iretcode) ! ! end