Les blocs de mémoire partagée peuvent être utilisés pour la communication inter-client ou simplement pour accéder à des tables ou des librairies de sous-routines nécessaires à plus d'un client. L'usage explicite des blocs partagés est necessaire car chaque VM a son propre espace d'adressage linéaire , et donc ne peut pas inspecter ou modifier la mémoire qui appartient à un client dans une autre machine virtuelle. La stratégie basique pour utiliser un bloc de mémoire partagée est la suivante:
Une fois le bloc partagé alloué, le client doit allouer un ou plusieurs descripteurs qui seront utilisés pour addresser le bloc avec l' Int 31H Fonction 0000H. Après que le(s) descripteur(s) aient etés alloués et initialisés pour pointer un bloc de mémoire partagée a travers d'appels separés à la gestion de la LDT, le client a la capacité physique de lire, ecrire, ou executer dans le bloc comme précisé par l'octet qui specifie les droits d'accès. Le client doit se synchroniser avec les autres clients qui pourraient avoir l'adressabilité du même bloc, pour eviter des conditions de course ou la corruption des données. Cette synchronisation est accomplie avec Int 31H Function 0D02H (Serialise la Mèmoire Partagèe)etInt 31H Fonction 0D03H (Libère la Sérialisation de la Mémoire Partagée). La sérialisation peut être vue comme la propriété ou les droits d'accés à un bloc de mémoire partagée.
Par essence,l' Int 31H Fonctions 0D02H et
0D03H traite le handle d'un bloc de
mémoire partagée comme un semaphore. Le client peut demander une sérialisation
exclusive(read/write) ou partagée(read-only) avec l'Int 31H Fonction 0D02H, et l'hôte accorde
la sérialisation si aucun autre client n'a déjà obtenu une sérialisation
sur le même bloc de mémoire. Le client peut alors continuer et manipuler
bloc de mémoire partagée, libérant la sérialisation avec l'
Int 31H Fonction 0D03H quand il a fini
d'utiliser le bloc. Si la requète de sérialisation
Le premier paragraphe (16 octets) du bloc de mémoire partagée (ou le
bloc partagé entier, si inférieur à 16 octets) doit être initialisé
à zéro à la première allocation et par les clients comme un indicateur
de "zone initialisée" . Par exemple,un bloc de mémoire partagée
peut être utilisé par une suite de programmes client pour acceder à une
table de données statiques ou une librairie de sous-routines . Le premier
client à allouer le bloc de mémoire partagée peut obtenir la propriété
exclusive du bloc avec l' Int 31H Fonction 0D02H,
charger les données necessaires ou le code en provenance du disque dans le bloc ,
mettre les 16 premiers octets du bloc à une valeur non nulle, et finallement
libérer la propriété du bloc avec l'Int 31H Fonction
0D03H. Les autres clients qui allouent le bloc de mémoire partagée peuvent
tester l'indicateur de "zone initialisée" et savoir si le code desiré ou les
données sont déjà presents en memoire.
Quand le client a fini d'utiliser le bloc de mémoire partagée, il doit
desallouer le bloc partagé avec l'Int 31H
Fonction 0D01H. Une fois le bloc desalloué, les adresses lineaires
dans le bloc ne sont plus valides pour le client courant,et provoquent
une exception si elles sont accedées. Toutefois, le bloc n'est pas détruit
tant que tous les clients qui ont alloué le bloc l'ont également desalloué.
Notez qu'un client peut lancer de multiple requêtes(imbriquées)d'allocation
sur le même bloc de mémoire partagée, et doit assumer que chaque requête
d'allocation retournera un handle distinct . Le bloc partagé restera
physiquement accessible au client jusqu'a que chacun de ses handles vers le
bloc aient été desalloués. De même, un client lancer de multiples
requêtes de sérialisation sur le same block, et conservera"la propriété"
du bloc tant qu'un nombre correspondant de requêtes de désérialisation
auront été émises. Pour finir,l'allocation de blocs de longueur nulle
est explicitement permise, ainsi les clients peuvent utiliser les handles
resultant de ces allocations comme de purs semaphores.
Exemple: Le code suivant illustre comment la mémoire partagée
peut être utilisée pour charger du code et des données qui seront utilisé par
plus d'un client. Notez que aucun appel de sérialisation n'est requis si la
mémoire est déjà initialiséee.
memreqstruc struc
length dd ? ; nombre d'octets requis
actual dd ? ; nombre d'octets alloués
handle dd ? ; handle pour bloc de mémoire partagée
base dd ? ; adresse lineaire du bloc partagé
nameptr dp ? ; pointeur sur le nom de la mémoire partagée
dw 0 ; reservé,doit être zero
dd 0 ; reservé,doit être zero
memreqstruc ends
memname db 'MYBLOCK',0
memreq memreqstruc <> ; alloue bloc requis
.
.
.
mov word ptr memreq.length,2000h ; fixe la logueur du bloc
mov word ptr memreq.length+2,0 ; à 8 Ko
; initialise nameptr
mov dword ptr memreq.nameptr, offset memname
mov word ptr memreq.nameptr+4, ds
mov di,ds ; ES:DI = adresse de la structure
mov es,di ; de requête de mémoire partagée
mov di,offset memreq
mov ax,0d00h ; DPMI fxn 0D00H = allouer
int 31h ; bloc de mémoire partagée
jc error ; branchement si allocation échoue
mov cx,1 ; alloue un descripteur LDT
mov ax,0 ; en utilisant Fonction DPMI 0000h
int 31h
jc error ; branchement , pas de descripteur disponible
mov bx,ax ; BX = nouveau sélecteur
mov dx,word ptr memreq.base ; CX:DX = adresse lineaire de base
mov cx,word ptr memreq.base+2 ; du bloc partagé
mov ax,0007h ; fixe l'adresse du descripteur
int 31h ; en utilisant Fonction DPMI 0007H
jc error ; branchement, fonction a échoué
mov dx,word ptr memreq.actual ; fixe CX:DX = longueur - 1octet
mov cx,word ptr memreq.actual+2 ; du bloc de mémoire partagée
sub dx,0
sbb cx,0 ; (BX toujours = sélecteur)
mov ax,8 ; fixe limite du descripteur utilisant
int 31h ; Fonction DPMI 0008H
jc error ; branchement, fonction a échoué
mov es,bx ; ES = sélecteur du bloc partagé
mov ax,es:[0] ; le bloc est déjà initialisé ?
or ax,ax
jnz @@1 ; branchement si oui
; non initialisé, prendre propriété
; du bloc de mémoire partagée
mov di,word ptr memreq.handle ; SI:DI = handle du
mov si,word ptr memreq.handle+2 ; bloc de mémoire partagée
mov dx,0 ; exclusive + attends la propriété
mov ax,0d02h ; DPMI Fxn 0D02H = serialise
int 31h
jc error ; branchement si la sérialisation échoue
mov ax,es: [0] ; teste encore si quelqu'un
or ax,ax ; a déjà initialisé le bloc
jnz @@2 ; branchement si oui
.
. ; chargez le code dans le
. ; bloc de mémoire ici...
.
@@2: ; on libére maintenant la propriété
; du bloc de mémoire partagée
mov di,word ptr memreq.handle ; SI:DI = handle du
mov si,word ptr memreq.hanlde+2 ; bloc de mémoire partagée
mov dx,0 ; sérialisation type = exclusive
mov ax,0d03h ; DPMI Fxn 0D03H = libère
int 31h
jc error ; branchement si la sérialisation échoue
@@1: ; on finit d'initialiser le
; bloc de mémoire partagée