Shared memory blocks can be used for inter-client communication or simply to hold tables or subroutine libraries that are needed by more than one client. Explicit use of shared blocks is necessary because each VM has its own linear address space, and thus cannot inspect or modify the memory owned by a client in another virtual machine. The basic strategy for use of a shared memory block is as follows:
After the shared block is allocated, the client must allocate one or more descriptors that will be used to address the block with Int 31H Function 0000H. Once descriptor(s) have been allocated and initialized to point to a shared memory block through separate LDT management calls, the client has the physical capability to read, write, or execute addresses within the block as allowed by the access rights/type byte. The client should synchronize with any other clients which might have addressability to the same block, to avoid race conditions or corruption of data. This synchronization is accomplished with Int 31H Function 0D02H (Serialize on Shared Memory) and Int 31H Function 0D03H (Free Serialization on Shared Memory). Serialization can be thought of as representing ownership or right of access to a shared memory block.
In essence, Int 31H Functions 0D02H and 0D03H treat the handle of a shared memory block as a semaphore. The client can request exclusive (read/write) or shared (read-only) serialization with Int 31H Function 0D02H, and the host will grant the serialization if no other client has already obtained a conflicting serialization on the same memory block. The client can then go ahead and manipulate the shared memory block, releasing the serialization with Int 31H Function 0D03H when it is finished using the block. If the Int 31H Function 0D02H serialization request fails, the client will either be suspended until the serialization is available, or the function will return with an error code, depending on the parameters supplied by the client.
The first paragraph (16 bytes) of the shared memory block (or the entire shared block, if smaller than 16 bytes) will always be initialized to zero on the first allocation and can be used by clients as an "area initialized" indicator. For example, a shared memory block might be used by a suite of cooperating client programs to hold a table of static data or a subroutine library. The first client to allocate the shared memory block can obtain exclusive ownership of the block with Int 31H Function 0D02H, load the necessary data or code into the block from disk, set the first 16 bytes of the block to a nonzero value, and finally release its ownership of the block with Int 31H Function 0D03H. Other clients that allocate the shared memory block can check the "area initialized" indicator and know that the desired code or data is already present in memory.
When a client has finished using the shared memory block, it should deallocate the shared block with Int 31H Function 0D01H. After the block is deallocated, the linear addresses within the block are no longer valid for the current client, and may cause an exception if accessed. However, the block is not actually destroyed until all clients which have allocated the block have also deallocated it.
Note that a client can make multiple (nested) allocation requests for the same shared memory block, and should assume that each allocation request will return a distinct handle. The shared block will remain physically accessible to the client until each of its handles to the block have been deallocated. Similarly, a client can make multiple serialization requests for the same block, and will retain "ownership" of the block until a corresponding number of deserialization requests have been issued. Lastly, allocation of zero-length shared memory blocks is explicitly allowed, so that clients can use the handles resulting from such allocations as pure semaphores.
Example: The following code illustrates how shared memory can be used to load code and data that can be used by more than one DPMI client. Note that no serialization calls are required if the memory is already initialized.
memreqstruc struc length dd ? ; number of bytes requested actual dd ? ; number of bytes allocated handle dd ? ; handle for shared memory block base dd ? ; linear address of shared block nameptr dp ? ; pointer to shared memory name dw 0 ; reserved, must be zero dd 0 ; reserved, must be zero memreqstruc ends memname db 'MYBLOCK',0 memreq memreqstruc <> ; allocate request block . . . mov word ptr memreq.length,2000h ; set reqeusted length mov word ptr memreq.length+2,0 ; of shared block to 8 KB ; initialize nameptr mov dword ptr memreq.nameptr, offset memname mov word ptr memreq.nameptr+4, ds mov di,ds ; ES:DI = address of shared mov es,di ; memory request structure mov di,offset memreq mov ax,0d00h ; DPMI fxn 0D00H = allocate int 31h ; shared memory block jc error ; jump if allocation failed mov cx,1 ; allocate one LDT descriptor mov ax,0 ; using DPMI Function 0000h int 31h jc error ; jump, no descriptor available mov bx,ax ; let BX = new selector mov dx,word ptr memreq.base ; let CX:DX = linear base mov cx,word ptr memreq.base+2 ; address of shared block mov ax,0007h ; set descriptor base address int 31h ; using DPMI Function 0007H jc error ; jump, function failed mov dx,word ptr memreq.actual ; set CX:DX = length-1 mov cx,word ptr memreq.actual+2 ; of shared memory block sub dx,0 sbb cx,0 ; (BX still = selector) mov ax,8 ; set descriptor limit using int 31h ; DPMI Function 0008H jc error ; jump, function failed mov es,bx ; ES = selector for shared block mov ax,es:[0] ; is block already initialized or ax,ax jnz @@1 ; jump if it's initialized ; not initialized, get ownership ; of the shared memory block mov di,word ptr memreq.handle ; SI:DI = handle for mov si,word ptr memreq.handle+2 ; shared memory block mov dx,0 ; exclusive + wait for ownership mov ax,0d02h ; DPMI Fxn 0D02H = serialize int 31h jc error ; jump if serialization failed mov ax,es: [0] ; check again if someone else or ax,ax ; already initialized block jnz @@2 ; jump if it's initialized . . ; load code into the shared . ; memory block here... . @@2: ; now release ownership of ; the shared memory block mov di,word ptr memreq.handle ; SI:DI = handle for mov si,word ptr memreq.hanlde+2 ; shared memory block mov dx,0 ; serialization type = exclusive mov ax,0d03h ; DPMI Fxn 0D03H = release int 31h jc error ; jump if serialization failed @@1: ; finished initializing the ; shared memory block