Introduction

Ce didacticiel est destiné aux utilisateurs maîtrisant la programmation en C ou C++, ainsi que l'architecture de la Simple Virtual Machine.

Dans ce didacticiel, vous allez manipuler la mémoire depuis une extension.

Le temps de lecture de ce didacticiel est estimé à 25 minutes.

Mise en place

Pour commencer, créez le canevas de l'extension dans le fichier memoire.svm_plugin en utilisant ce code :

PLUGIN ram

DEFINE

Lecture et écriture

Lecture

Modifiez le code de l'extension :

PLUGIN ram

DEFINE

INSTRUCTION ram.read INT:address -> VALUE
%{
	auto a = ARGV_VALUE(0,integer);
	return ::svm_memory_read_address(svm,CURRENT(kernel),a);
%}

INSTRUCTION ram.read_internal INT:address INT:type -> VALUE
%{
	auto a = ARGV_VALUE(0,integer);
	auto t = ARGV_VALUE(1,integer);
	if((t<0) or (t>=PLUGIN_TYPE))
	{
		ERROR_INTERNAL(FAILURE,"Wrong type");
	}
	return ::svm_memory_read_address_typeinternal(svm,CURRENT(kernel),a,static_cast<SVM_Type>(t));
%}

INSTRUCTION ram.read_external INT:address PEP:type -> VALUE
%{
	auto a = ARGV_VALUE(0,integer);
	SVM_Value_PluginEntryPoint t = ::svm_parameter_value_get(svm,argv[1]);
	return ::svm_memory_read_address_typeexternal(svm,CURRENT(kernel),a,t);
%}

Générez et compilez l'extension. Puis écrivez une petite application de test qui utilise ces trois instructions.

Vous pouvez constater que la première instruction permet de réaliser une lecture sans test de type. Les deux autres instructions vérifient le type en même temps.

Ecriture

Par copie

Modifiez le code de l'extension :

PLUGIN ram

DEFINE

INSTRUCTION ram.write INT:address VALUE
%{
	auto a = ARGV_VALUE(0,integer);
	SVM_Value v = ::svm_parameter_value_get(svm,argv[1]);
	::svm_memory_write_address(svm,CURRENT(kernel),a,v);
%}

Générez et compilez l'extension. Puis écrivez une petite application de test qui utilise cette instruction pour écrire une valeur en mémoire.

Ici, la valeur réellement écrite en mémoire n'est pas celle donnée en paramètre de la fonction svm_memory_write_address, mais une copie de cette valeur.

Par déplacement

La copie peut ne pas être voulue lors d'une écriture en mémoire. Soit parce que la valeur ne peut pas être copiée, soit parce que cette copie est inutile.

Modifiez le code de l'extension :

PLUGIN ram

DEFINE

INSTRUCTION ram.write INT:address VALUE
%{
	auto a = ARGV_VALUE(0,integer);
	SVM_Value v = ::svm_parameter_value_get(svm,argv[1]);
	SVM_String s = ::svm_value_print(svm,v);
	SVM_Value_String vs = ::svm_value_string_new(svm,s);
	::svm_value_state_set_movable(svm,vs);
	::svm_memory_write_address(svm,CURRENT(kernel),a,vs);
%}

Générez et compilez l'extension. Puis écrivez une petite application de test qui utilise cette instruction. Ici, la représentation textuelle de la valeur est écrite en mémoire.

Cette représentation textuelle, créée dans le code de l'instruction, peut être déplacée en mémoire pour éviter une copie. La valeur est marquée comme déplaçable juste avant d'être écrite en mémoire.

Pour vous en convaincre, modifiez le code de l'extension :

PLUGIN ram

code:
%{
	SVM_Value_String _s;
%}

DEFINE

INSTRUCTION ram.write INT:address VALUE
%{
	auto a = ARGV_VALUE(0,integer);
	SVM_Value v = ::svm_parameter_value_get(svm,argv[1]);
	SVM_String s = ::svm_value_print(svm,v);
	_s = ::svm_value_string_new(svm,s);
	::svm_variable_scope_set_global(svm,_s);
	::svm_value_state_set_movable(svm,_s);
	::svm_memory_write_address(svm,CURRENT(kernel),a,_s);
%}

INSTRUCTION ram.test
%{
	::svm_value_string_set__raw(svm,_s,"");
	::svm_variable_scope_set_local(svm,_s);
%}

Générez et compilez l'extension. Puis écrivez une application contenant ce code :

#!/usr/bin/env svm
LOG
LOCAL PLUGIN "svmpluginram/libsvmram.so"
PLUGIN "svmcom.so"
PROCESS "ram"
	CODE "main" INLINE
		:memory STR/s
		:ram.write 0 17
		:com.message "[" @&s "]"
		:ram.test
		:com.message "[" @&s "]"
	END
END

Lancez l'application :

./memoire.svm
[17]
[]

La deuxième ligne montre une chaine vide ! Cela est dû au fait que la fonction svm_value_string_set__raw a agit sur la valeur qui avait été déplacée en mémoire et conservée comme variable Simple Virtual Machine globale.

Enlevez l'appel de la fonction svm_value_state_set_movable puis regénérez et compilez l'extension. Relancez l'application :

./memoire.svm
[17]
[17]

Cette fois, la modification de la chaine n'a pas altéré la mémoire, car la valeur y a été copiée durant l'écriture en mémoire.

Allocation et libération

Allocation

Modifiez le code de l'extension :

PLUGIN ram

DEFINE

INSTRUCTION ram.new INT:size INT:address ? -> PTR ?
%{
	SVM_Value_Integer s = ::svm_parameter_value_get(svm,argv[0]);
	SVM_Memory_Zone z = ::svm_memory_zone_new(svm);
	::svm_memory_zone_append_internal(svm,z,AUTOMATIC,s);
	if(argc==1)
	{
		return ::svm_memory_allocate(svm,CURRENT(kernel),z);
	}
	else
	{
		auto a = ARGV_VALUE(1,integer);
		return ::svm_memory_allocate_address(svm,CURRENT(kernel),z,a);
	}
%}

Générez et compilez l'extension. Puis écrivez une application utilisant cette instruction pour créer un tableau.

Vous pouvez noter que :

Libération

En plus des retours de fonctions, l'interface programmatique permet de libérer la mémoire explicitement.

Modifiez le code de l'extension :

PLUGIN ram

DEFINE

INSTRUCTION ram.delete PTR
%{
	SVM_Value_Pointer p = ::svm_parameter_value_get(svm,argv[0]);
	::svm_memory_free(svm,CURRENT(kernel),p);
%}

Générez et compilez l'extension. Puis écrivez une application avec ce code :

#!/usr/bin/env svm
LOG
LOCAL PLUGIN "svmpluginram/libsvmram.so"
PLUGIN "svmcom.so"
PROCESS "ram"
	CODE "main" INLINE
		:debug BREAK
		:memory INT*10
		:ram.delete &2*5
	END
END

Lancez cette application dans le débugueur. Après l'exécution de l'instruction :ram.delete, vous pouvez constater que :

Alias

Modifiez le code de l'extension :

PLUGIN ram

DEFINE

INSTRUCTION ram.new STR PTR
%{
	SVM_Value_String n = ::svm_parameter_value_get(svm,argv[0]);
	SVM_Value_Pointer p = ::svm_parameter_value_get(svm,argv[1]);
	::svm_memory_add_alias(svm,CURRENT(kernel),n,p);
%}

INSTRUCTION ram.delete STR
%{
	SVM_Value_String n = ::svm_parameter_value_get(svm,argv[0]);
	::svm_memory_remove_alias(svm,CURRENT(kernel),n);
%}

INSTRUCTION ram.get STR -> PTR ?
%{
	SVM_Value_String n = ::svm_parameter_value_get(svm,argv[0]);
	if(::svm_memory_has_alias(svm,CURRENT(kernel),n))
	{
		return ::svm_memory_alias_get_pointer(svm,CURRENT(kernel),n);
	}
	return NEW_NULL_VALUE(pointer);
%}

Générez et compilez l'extension. Puis écrivez une application manipulant les alias. Notez que l'instruction permettant de retourner le pointeur associé à un alias ne lève pas d'interruption quand l'alias n'existe pas.

Portée

Mémoire

Modifiez le code de l'extension :

PLUGIN ram

DEFINE

INSTRUCTION ram.local PTR
%{
	SVM_Value_Pointer p = ::svm_parameter_value_get(svm,argv[0]);
	::svm_memory_scope_set_local(svm,CURRENT(kernel),p);
%}

INSTRUCTION ram.global PTR
%{
	SVM_Value_Pointer p = ::svm_parameter_value_get(svm,argv[0]);
	::svm_memory_scope_set_global(svm,CURRENT(kernel),p);
%}

Générez et compilez l'extension. Puis écrivez une application manipulant la portée de la mémoire, et lancez la dans le débugueur.

Notez que ces fonctions, même si elles sont placées dans le module de mémoire de l'interface programmatique, modifient le processeur et non la mémoire elle-même. En effet, elles indiquent au processeur comment gérer la mémoire lors d'un retour de fonction.

Alias

Modifiez le code de l'extension :

PLUGIN ram

DEFINE

INSTRUCTION ram.local STR
%{
	SVM_Value_String n = ::svm_parameter_value_get(svm,argv[0]);
	::svm_memory_scope_set_local_alias(svm,CURRENT(kernel),n);
%}

INSTRUCTION ram.global STR
%{
	SVM_Value_String n = ::svm_parameter_value_get(svm,argv[0]);
	::svm_memory_scope_set_global_alias(svm,CURRENT(kernel),n);
%}

Générez et compilez l'extension. Puis écrivez une application manipulant la portée de la mémoire, et lancez la dans le débugueur. Cette fois encore, ces fonctions modifient le processeur.

Etats

Définie et initialisée

Modifiez le code de l'extension :

PLUGIN ram

DEFINE

INSTRUCTION ram.defined INT -> BLN
%{
	auto a = ARGV_VALUE(0,integer);
	return NEW_VALUE(boolean,::svm_memory_address_is_defined(svm,CURRENT(kernel),a));
%}

INSTRUCTION ram.initialised INT -> BLN
%{
	auto a = ARGV_VALUE(0,integer);
	return NEW_VALUE(boolean,::svm_memory_address_is_initialised(svm,CURRENT(kernel),a));
%}

Générez et compilez l'extension. Puis écrivez une application utilisant ces deux instructions.

Types

Modifiez le code de l'extension :

PLUGIN ram

DEFINE

INSTRUCTION ram.type INT -> INT
%{
	auto a = ARGV_VALUE(0,integer);
	SVM_Type t = ::svm_memory_address_get_type(svm,CURRENT(kernel),a);
	return NEW_VALUE(integer,static_cast<long long int>(t));
%}

INSTRUCTION ram.type_name INT -> PEP ?
%{
	auto a = ARGV_VALUE(0,integer);
	if(::svm_memory_address_get_type(svm,CURRENT(kernel),a)==PLUGIN_TYPE)
	{
		return ::svm_memory_address_get_type_name(svm,CURRENT(kernel),a);
	}
	return NEW_NULL_VALUE(pluginentrypoint);
%}

Générez et compilez l'extension. Puis écrivez une application utilisant ces deux instructions.

Un raccourci

Lorsqu'une écriture doit être faite en mémoire, il peut être utile de vérifier que cette écriture ne va pas échouer. Avec les fonctions de l'interface programmatique que nous venons de voir, il faut s'assurer que :

  1. l'adresse mémoire est bien définie avec svm_memory_address_is_defined,
  2. le type de l'adresse est compatible avec celui de la valeur avec svm_memory_address_get_type et svm_memory_address_get_type_name.

Ce test peut devenir rapidement fastidieux à écrire. Pour éviter ce code fastidieux, il est possible d'utiliser la fonction svm_memory_address_is_writable avec les mêmes paramètres que la fonction d'écriture. Cette fonction réalise tous les tests nécessaires, et indique si l'écriture est réalisable.

Tableaux

Lecture

Les instructions, par exemple, peuvent admettre un nombre quelconque d'arguments, en fonction d'expression rationnelle de ses arguments. Parfois, ces arguments peuvent être considérés comme un tableau d'argument. Cependant, il est parfois plus pratique d'utiliser un tableau en mémoire, et de le lire depuis un pointeur passé en argument.

Modifiez le code de l'extension :

PLUGIN ram

DEFINE

INSTRUCTION ram.read_array PTR -> STR
%{
	SVM_Value_Pointer p = ::svm_parameter_value_get(svm,argv[0]);
	SVM_Address a = ::svm_value_pointer_get_address(svm,p);
	SVM_Size s = ::svm_value_pointer_get_size(svm,p);
	std::ostringstream oss;
	oss << "[";
	for(SVM_Address i=a; i<(a+s) ; ++i)
	{
		SVM_Value v = ::svm_memory_read_address(svm,CURRENT(kernel),i);
		SVM_String vs = ::svm_value_print(svm,v);
		oss << " " << RAW_STRING(vs);
	}
	oss << " ]";
	return NEW_VALUE(string,NEW_STRING(oss.str()));
%}

Générez et compilez l'extension. Puis écrivez une application utilisant cette instruction.

La lecture du tableau se fait en deux étapes :

  1. Décomposer le pointeur en adresse et taille,
  2. Boucler sur les adresses entre l'adresse de début et de fin du pointeur. A chaque itération de la boucle, la mémoire est lue sur l'adresse indice de boucle.

Notez qu'il est également possible de lire un tableau d'un seul coup avec la fonction svm_memory_read_pointer et ses variantes. Dans ce cas, la valeur retournée est un tableau de valeurs terminé par un pointeur nul.

Ecriture

Depuis une structure de données C ou C++

Il est aussi parfois très pratique pour une instruction de retourner un tableau. Dans ce cas, les valeurs sont écrites en mémoire, puis le pointeur vers les données écrites en mémoire est retourné par l'instruction.

Modifiez le code de l'extension :

PLUGIN ram

includes:
%{
#include <vector>
%}

DEFINE

INSTRUCTION ram.write_array INT -> PTR
%{
	auto s = ARGV_VALUE(0,integer);
	std::vector<long long int> v;
	for(size_t i=0 ; i<s ; ++i)
	{
		v.push_back(i);
	}
	SVM_Memory_Zone z = ::svm_memory_zone_new(svm);
	::svm_memory_zone_append_internal__raw(svm,z,INTEGER,v.size());
	SVM_Value_Pointer p = ::svm_memory_allocate(svm,CURRENT(kernel),z);
	SVM_Address pa = ::svm_value_pointer_get_address(svm,p);
	SVM_Size ps = ::svm_value_pointer_get_size(svm,p);
	auto it = v.begin();
	for(SVM_Address i=pa ; i<(pa+ps) ; ++i)
	{
		SVM_Value_Integer vi = ::svm_value_integer_new(svm,*it);
		::svm_value_state_set_movable(svm,vi);
		::svm_memory_write_address(svm,CURRENT(kernel),i,vi);
		++it;
	}
	return p;
%}

Générez et compilez l'extension. Puis écrivez une application utilisant cette instruction.

L'instruction ici commence par construire un vecteur d'entiers, puis :

  1. Alloue une zone mémoire permettant de contenir toutes les valeurs du vecteurs,
  2. Récupère l'adresse et la taille du pointeur de la zone allouée,
  3. Ecrit chaque valeur à une adresse consécutive dans le tableau en mémoire,
  4. Retourne le pointeur où se situe les données en mémoire.

Depuis un tableau interface programmatique

Une alternative est possible lorsque le tableau à écrire en mémoire provient d'un tableau généré par l'interface programmatique.

Modifiez le code de l'extension :

PLUGIN ram

DEFINE

INSTRUCTION ram.write_array -> PTR
%{
	SVM_Value_Interruption *irq = ::svm_machine_list_interruption(svm);
	SVM_Size s = 0;
	for(SVM_Value_Interruption *i=irq ; *i ; ++i)
	{
		::svm_value_state_set_movable(svm,*i);
		++s;
	}
	SVM_Memory_Zone z = ::svm_memory_zone_new(svm);
	::svm_memory_zone_append_internal__raw(svm,z,INTERRUPTION,s);
	SVM_Value_Pointer p = ::svm_memory_allocate(svm,CURRENT(kernel),z);
	::svm_memory_write_pointer(svm,CURRENT(kernel),p,irq);
	return p;
%}

Générez et compilez l'extension. Puis écrivez une application utilisant cette instruction.

Ici, l'instruction alloue toujours la mémoire et écrit les valeurs en mémoire, mais différemment :

  1. Elle doit calculer la taille du tableau pour allouer la mémoire,
  2. Elle écrit directement le tableau entier dans le pointeur grâce à la fonction svm_memory_write_pointer. De plus, cette fonction écrit l'ensemble des valeurs de manière atomique : soit l'écriture réussit et toutes les valeurs sont écrites, soit l'écriture échoue, et aucune valeur n'est écrite en mémoire.

Opérations

Types

Modifiez le code de l'extension :

PLUGIN ram

DEFINE

INSTRUCTION ram.type_auto INT
%{
	auto a = ARGV_VALUE(0,integer);
	::svm_memory_address_set_typeinternal(svm,CURRENT(kernel),a,AUTOMATIC);
%}

INSTRUCTION ram.type_plugin INT PEP
%{
	auto a = ARGV_VALUE(0,integer);
	SVM_Value_PluginEntryPoint p = ::svm_parameter_value_get(svm,argv[1]);
	::svm_memory_address_set_typeexternal(svm,CURRENT(kernel),a,p);
%}

Générez et compilez l'extension. Puis écrivez une application utilisant ces instructions.

Notez qu'en plus de changer le type associé à une adresse, ces deux fonctions retirent la valeur éventuelle associée à l'adresse modifiée.

Modification

Modifiez le code de l'extension :

PLUGIN ram

DEFINE

INSTRUCTION ram.shift INT INT
%{
	auto a = ARGV_VALUE(0,integer);
	SVM_Value_Integer i = ::svm_parameter_value_get(svm,argv[1]);
	::svm_memory_address_shift(svm,CURRENT(kernel),a,i);
%}

Générez et compilez l'extension. Puis écrivez une application utilisant cette instruction.

La fonction svm_memory_address_shift ne fonctionne que sur des adresses ayant le type entier, et modifie la valeur associée à une adresse.

Accessibilité

Mémoire

Il est parfois utile de réaliser un traitement sur toute la mémoire qui peut être accédée depuis un pointeur, en suivant récursivement tous les pointeurs.

Modifiez le code de l'extension :

PLUGIN ram

DEFINE

INSTRUCTION ram.expand PTR -> PTR
%{
	SVM_Value_Pointer p = ::svm_parameter_value_get(svm,argv[0]);
	SVM_Value_Pointer *t = ::svm_memory_pointer_list_accessible(svm,CURRENT(kernel),p);
	SVM_Size s = 0;
	for(SVM_Value_Pointer *it=t ; *it ; ++it)
	{
		::svm_value_state_set_movable(svm,*it);
		++s;
	}
	SVM_Memory_Zone z = ::svm_memory_zone_new(svm);
	::svm_memory_zone_append_internal__raw(svm,z,POINTER,s);
	SVM_Value_Pointer r = ::svm_memory_allocate(svm,CURRENT(kernel),z);
	::svm_memory_write_pointer(svm,CURRENT(kernel),r,t);
	return r;
%}

Générez et compilez l'extension. Puis écrivez une application utilisant cette instruction.

La fonction svm_memory_pointer_list_accessible renverra toujours en premier le pointeur passé en paramètre. Ensuite, elle renvoie une liste de pointeurs qui ne tient pas compte de la topologie réelle de la mémoire, mais une représentation à plat où chaque adresse accessible n'est présente qu'une fois.

Alias

De la même manière, il est parfois important de récupérer la liste des alias définis sur une zone mémoire.

Modifiez le code de l'extension :

PLUGIN ram

DEFINE

INSTRUCTION ram.names PTR -> PTR
%{
	SVM_Value_Pointer p = ::svm_parameter_value_get(svm,argv[0]);
	SVM_Value_String *t = ::svm_memory_pointer_list_alias(svm,CURRENT(kernel),p);
	SVM_Size s = 0;
	for(SVM_Value_Pointer *it=t ; *it ; ++it)
	{
		::svm_value_state_set_movable(svm,*it);
		++s;
	}
	SVM_Memory_Zone z = ::svm_memory_zone_new(svm);
	::svm_memory_zone_append_internal__raw(svm,z,STRING,s);
	SVM_Value_Pointer r = ::svm_memory_allocate(svm,CURRENT(kernel),z);
	::svm_memory_write_pointer(svm,CURRENT(kernel),r,t);
	return r;
%}

Générez et compilez l'extension. Puis écrivez une application utilisant cette instruction.

Si vous tentez de fournir un pointeur à cheval sur un alias, cet alias ne sera pas retourné : la fonction svm_memory_pointer_list_alias ne retourne que les alias inclus entièrement dans le pointeur fourni en paramètre.

Copie

Copier un tableau entier depuis une zone mémoire vers une autre peut être une tâche fastidieuse. Heureusement, l'interface programmatique propose une fonction pour réaliser cette opération.

Modifiez le code de l'extension :

PLUGIN ram

DEFINE

INSTRUCTION ram.copy PTR PTR
%{
	SVM_Value_Pointer s = ::svm_parameter_value_get(svm,argv[0]);
	SVM_Value_Pointer d = ::svm_parameter_value_get(svm,argv[1]);
	::svm_memory_copy(svm,CURRENT(kernel),s,CURRENT(kernel),d);
%}

Générez et compilez l'extension. Puis écrivez une application utilisant cette instruction.

Vous pouvez remarquer que :

Déplacement

De la même manière, il est possible de déplacer des valeurs.

Modifiez le code de l'extension :

PLUGIN ram

DEFINE

INSTRUCTION ram.move PTR PTR
%{
	SVM_Value_Pointer s = ::svm_parameter_value_get(svm,argv[0]);
	SVM_Value_Pointer d = ::svm_parameter_value_get(svm,argv[1]);
	::svm_memory_move(svm,CURRENT(kernel),s,CURRENT(kernel),d);
%}

Générez et compilez l'extension. Puis écrivez une application utilisant cette instruction.

Les mêmes remarques vues pour la copie s'appliquent au déplacement de valeurs.

Partage

Enfin, il est également possible de partager les valeurs entre plusieurs adresses. Cela est intéressant dans certains cas, notamment lorsqu'une partie des paramètres d'une fonction peut provenir d'une structure de données, et que la fonction peut intervenir dessus : cela donne une vue supplémentaire sur les valeurs.

Modifiez le code de l'extension :

PLUGIN ram

DEFINE

INSTRUCTION ram.share PTR PTR
%{
	SVM_Value_Pointer s = ::svm_parameter_value_get(svm,argv[0]);
	SVM_Value_Pointer d = ::svm_parameter_value_get(svm,argv[1]);
	::svm_memory_share(svm,CURRENT(kernel),s,CURRENT(kernel),d);
%}

Générez et compilez l'extension. Puis écrivez une application avec ce code :

#!/usr/bin/env svm
LOG
LOCAL PLUGIN "svmpluginram/libsvmram.so"
PLUGIN "svmcom.so"
PROCESS "ram"
	CODE "main" INLINE
		:debug BREAK
		:memory INT*10/t
		[ 2, 3, 5, 7, 11, 13, 17, 19, 23, 29 ] -> t
		:memory (PTR, INT*3)/p
		:ram.share (&t+3)*3 (&p+1)*3
		:call decrease p
		:memory INT/i
		0 -> &i
	:label display
		:com.message @(t/@&i)
		:shift &i
		:goto display :when @&i IN t
		:shutdown
	:label decrease
		:memory INT -> &P
		1 -> &@&P
	:label decrease_loop
		:shift -1 (P/@&@&P)
		:shift &@&P
		:goto decrease_loop :when @&@&P IN P
		:return
	END
END

Lancez cette application dans le débugueur. Ouvrez les fenêtres de la mémoire, du processeur et du code, puis exécutez l'application instruction par instruction.

Notez que lorsque l'instruction :ram.share s'exécute, rien de visible ne se produit. En revanche, lorsque la fonction "decrease" modifie un de ses paramètres entiers, le tableau d'entiers est également modifié : et pour cause, les valeurs sont physiquement les mêmes grâce à l'instruction :ram.share !

Synchronisation

Les adresses mémoires, lorsqu'elles sont partagées entre différentes mémoires, peuvent être accédées de manière concurente. Pour protéger la mémoire de tels accès concurents, chaque adresse peut être synchronisée : dans ce cas, les accès en lecture sont toujours possibles en parallèle, mais sont exclusifs avec les écritures, qui sont mutuellement exclusives entre elles.

Notez que seul les accès à la mémoire sont synchronisés. Les valeurs doivent à leur tour être synchronisées si elles sont modifiées.

Les adresses sont naturellement synchronisées lorsqu'elles sont partagées entre deux mémoires par la fonction svm_memory_share, mais cette synchronisation peut être activée ou désactivée à volonté.

Modifiez le code de l'extension :

PLUGIN ram

DEFINE

INSTRUCTION ram.sync PTR
%{
	SVM_Value_Pointer p = ::svm_parameter_value_get(svm,argv[0]);
	::svm_memory_synchronisation_enable(svm,CURRENT(kernel),p);
%}

INSTRUCTION ram.free PTR
%{
	SVM_Value_Pointer p = ::svm_parameter_value_get(svm,argv[0]);
	::svm_memory_synchronisation_disable(svm,CURRENT(kernel),p);
%}

La synchronisation des adresses n'étant pas particulièrement visible, il n'est pas nécessaire de tester ces instructions. Ce code est donné pour illustrer comment la synchronisation se manipule.

Conclusion

Vous venez de voir comment manipuler les mémoires de la machine virtuelle depuis les extensions.

La mémoire de la machine virtuelle est riche en opérations possibles. Cependant, il convient de maîtriser en particulier la lecture, l'écriture, l'allocation et la portée de la mémoire pour un usage courant dans les instructions.