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 depuis une extension les noyaux de la machine virtuelle.

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 noyaux.svm_plugin en utilisant ce code :

PLUGIN kernel

DEFINE

Création et récupération

Création

Modifiez le code de l'extension :

PLUGIN kernel

DEFINE

TYPE kernel.instance
%{
	SVM_Kernel _kernel;
%}
delete default:
%{
	VARIABLE_LOCAL(object->_kernel);
%}

INSTRUCTION kernel.new_code LIB BLN : transmit_interruptions BLN : last_return_is_shutdown BLN : protected_mode -> kernel.instance
%{
	SVM_Value_Library l = ::svm_parameter_value_get(svm,argv[0]);
	SVM_Boolean ti = ARGV_VALUE(1,boolean);
	SVM_Boolean lris = ARGV_VALUE(2,boolean);
	SVM_Boolean pm = ARGV_VALUE(3,boolean);
	SVM_Code c = ::svm_value_library_get_code(svm,l);
	SVM_Kernel k = ::svm_kernel_new_code(svm,ti,lris,pm,nullptr/* no accesscontrol */,c);
	VARIABLE_GLOBAL(k);
	auto tk = new type_instance;
	tk->_kernel = k;
	return NEW_PLUGIN(kernel,instance,tk);
%}

INSTRUCTION kernel.new_symbol SYM BLN : transmit_interruptions BLN : last_return_is_shutdown BLN : protected_mode -> kernel.instance
%{
	SVM_Value_Symbol s = ::svm_parameter_value_get(svm,argv[0]);
	SVM_Boolean ti = ARGV_VALUE(1,boolean);
	SVM_Boolean lris = ARGV_VALUE(2,boolean);
	SVM_Boolean pm = ARGV_VALUE(3,boolean);
	SVM_Kernel k = ::svm_kernel_new_symbol(svm,ti,lris,pm,nullptr/* no accesscontrol */,s);
	VARIABLE_GLOBAL(k);
	auto tk = new type_instance;
	tk->_kernel = k;
	return NEW_PLUGIN(kernel,instance,tk);
%}

Générez l'extension et compilez la. Vous pouvez créer une petite application appellant ces deux instructions pour tester, mais le résultat n'est pour le moment pas spectaculaire.

Les deux fonctions de l'interface à noter ici sont svm_kernel_new_code et svm_kernel_new_symbol. Ces deux fonctions créent un nouveau noyau en initialisant le processeur sur un code ou un symbole, avec une mémoire vide et des drapeaux altérant le comportement du noyau dans l'exécution du code.

Noyau courant

Modifiez le code de l'extension :

PLUGIN kernel

DEFINE

TYPE kernel.instance
%{
	SVM_Kernel _kernel;
%}
delete default:
%{
	VARIABLE_LOCAL(object->_kernel);
%}

INSTRUCTION kernel.new_code LIB BLN : transmit_interruptions BLN : last_return_is_shutdown BLN : protected_mode -> kernel.instance
%{
	SVM_Value_Library l = ::svm_parameter_value_get(svm,argv[0]);
	SVM_Boolean ti = ARGV_VALUE(1,boolean);
	SVM_Boolean lris = ARGV_VALUE(2,boolean);
	SVM_Boolean pm = ARGV_VALUE(3,boolean);
	SVM_Code c = ::svm_value_library_get_code(svm,l);
	SVM_Kernel k = ::svm_kernel_new_code(svm,ti,lris,pm,nullptr/* no accesscontrol */,c);
	VARIABLE_GLOBAL(k);
	auto tk = new type_instance;
	tk->_kernel = k;
	return NEW_PLUGIN(kernel,instance,tk);
%}

INSTRUCTION kernel.new_symbol SYM BLN : transmit_interruptions BLN : last_return_is_shutdown BLN : protected_mode -> kernel.instance
%{
	SVM_Value_Symbol s = ::svm_parameter_value_get(svm,argv[0]);
	SVM_Boolean ti = ARGV_VALUE(1,boolean);
	SVM_Boolean lris = ARGV_VALUE(2,boolean);
	SVM_Boolean pm = ARGV_VALUE(3,boolean);
	SVM_Kernel k = ::svm_kernel_new_symbol(svm,ti,lris,pm,nullptr/* no accesscontrol */,s);
	VARIABLE_GLOBAL(k);
	auto tk = new type_instance;
	tk->_kernel = k;
	return NEW_PLUGIN(kernel,instance,tk);
%}

INSTRUCTION kernel.get_current -> kernel.instance
%{
	SVM_Kernel k = ::svm_kernel_get_current(svm);
	VARIABLE_GLOBAL(k);
	auto tk = new type_instance;
	tk->_kernel = k;
	return NEW_PLUGIN(kernel,instance,tk);
%}

Générez l'extension et compilez la. Vous pouvez créer une petite application appellant cette nouvelle instruction.

Ici, le noyau renvoyé par la fonction svm_kernel_get_current est celui dans lequel l'instruction s'exécute.

Notez que le générateur d'extension définit une macro C/C++ pouvant être utilisée ainsi CURRENT(kernel) pour obtenir le noyau courant.

Opérations

Modifiez le code de l'extension :

PLUGIN kernel

DEFINE

TYPE kernel.instance
%{
	SVM_Kernel _kernel;
%}
delete default:
%{
	VARIABLE_LOCAL(object->_kernel);
%}

INSTRUCTION kernel.new_code LIB BLN : transmit_interruptions BLN : last_return_is_shutdown BLN : protected_mode -> kernel.instance
%{
	SVM_Value_Library l = ::svm_parameter_value_get(svm,argv[0]);
	SVM_Boolean ti = ARGV_VALUE(1,boolean);
	SVM_Boolean lris = ARGV_VALUE(2,boolean);
	SVM_Boolean pm = ARGV_VALUE(3,boolean);
	SVM_Code c = ::svm_value_library_get_code(svm,l);
	SVM_Kernel k = ::svm_kernel_new_code(svm,ti,lris,pm,nullptr/* no accesscontrol */,c);
	VARIABLE_GLOBAL(k);
	auto tk = new type_instance;
	tk->_kernel = k;
	return NEW_PLUGIN(kernel,instance,tk);
%}

INSTRUCTION kernel.new_symbol SYM BLN : transmit_interruptions BLN : last_return_is_shutdown BLN : protected_mode -> kernel.instance
%{
	SVM_Value_Symbol s = ::svm_parameter_value_get(svm,argv[0]);
	SVM_Boolean ti = ARGV_VALUE(1,boolean);
	SVM_Boolean lris = ARGV_VALUE(2,boolean);
	SVM_Boolean pm = ARGV_VALUE(3,boolean);
	SVM_Kernel k = ::svm_kernel_new_symbol(svm,ti,lris,pm,nullptr/* no accesscontrol */,s);
	VARIABLE_GLOBAL(k);
	auto tk = new type_instance;
	tk->_kernel = k;
	return NEW_PLUGIN(kernel,instance,tk);
%}

INSTRUCTION kernel.get_current -> kernel.instance
%{
	SVM_Kernel k = ::svm_kernel_get_current(svm);
	VARIABLE_GLOBAL(k);
	auto tk = new type_instance;
	tk->_kernel = k;
	return NEW_PLUGIN(kernel,instance,tk);
%}

INSTRUCTION kernel.suspend kernel.instance
%{
	auto tk = ARGV_PLUGIN(0,kernel,instance);
	::svm_kernel_suspend(svm,tk->_kernel);
%}

INSTRUCTION kernel.terminate kernel.instance
%{
	auto tk = ARGV_PLUGIN(0,kernel,instance);
	::svm_kernel_terminate(svm,tk->_kernel);
%}

Générez l'extension puis compilez la. Ecrivez une petite application de test appellant ces instructions sur le noyau courant.

Vous pourrez constater que :

Introspection

Affichage

Modifiez le code de l'extension :

PLUGIN kernel

DEFINE

TYPE kernel.instance
%{
	SVM_Kernel _kernel;
%}
delete default:
%{
	VARIABLE_LOCAL(object->_kernel);
%}

INSTRUCTION kernel.new_code LIB BLN : transmit_interruptions BLN : last_return_is_shutdown BLN : protected_mode -> kernel.instance
%{
	SVM_Value_Library l = ::svm_parameter_value_get(svm,argv[0]);
	SVM_Boolean ti = ARGV_VALUE(1,boolean);
	SVM_Boolean lris = ARGV_VALUE(2,boolean);
	SVM_Boolean pm = ARGV_VALUE(3,boolean);
	SVM_Code c = ::svm_value_library_get_code(svm,l);
	SVM_Kernel k = ::svm_kernel_new_code(svm,ti,lris,pm,nullptr/* no accesscontrol */,c);
	VARIABLE_GLOBAL(k);
	auto tk = new type_instance;
	tk->_kernel = k;
	return NEW_PLUGIN(kernel,instance,tk);
%}

INSTRUCTION kernel.new_symbol SYM BLN : transmit_interruptions BLN : last_return_is_shutdown BLN : protected_mode -> kernel.instance
%{
	SVM_Value_Symbol s = ::svm_parameter_value_get(svm,argv[0]);
	SVM_Boolean ti = ARGV_VALUE(1,boolean);
	SVM_Boolean lris = ARGV_VALUE(2,boolean);
	SVM_Boolean pm = ARGV_VALUE(3,boolean);
	SVM_Kernel k = ::svm_kernel_new_symbol(svm,ti,lris,pm,nullptr/* no accesscontrol */,s);
	VARIABLE_GLOBAL(k);
	auto tk = new type_instance;
	tk->_kernel = k;
	return NEW_PLUGIN(kernel,instance,tk);
%}

INSTRUCTION kernel.get_current -> kernel.instance
%{
	SVM_Kernel k = ::svm_kernel_get_current(svm);
	VARIABLE_GLOBAL(k);
	auto tk = new type_instance;
	tk->_kernel = k;
	return NEW_PLUGIN(kernel,instance,tk);
%}

INSTRUCTION kernel.print kernel.instance -> STR
%{
	auto tk = ARGV_PLUGIN(0,kernel,instance);
	SVM_String s = ::svm_kernel_print(svm,tk->_kernel);
	return NEW_VALUE(string,s);
%}

Générez l'extension puis compilez la. Ecrivez une petite application de test appellant cette dernière instruction sur le noyau courant ainsi que sur des noyaux créés par les deux premières instructions.

La chaine générée par la fonction svm_kernel_print contient l'état d'exécution du noyau, ainsi que la liste des drapeaux activés sur ce noyau.

D'ailleurs, il peut être judicieux ici d'utiliser cette fonction directement sur le type :

PLUGIN kernel

DEFINE

TYPE kernel.instance
%{
	SVM_Kernel _kernel;
%}
delete default:
%{
	VARIABLE_LOCAL(object->_kernel);
%}
print object:
%{
	return ::svm_kernel_print(svm,object->_kernel);
%}

INSTRUCTION kernel.new_code LIB BLN : transmit_interruptions BLN : last_return_is_shutdown BLN : protected_mode -> kernel.instance
%{
	SVM_Value_Library l = ::svm_parameter_value_get(svm,argv[0]);
	SVM_Boolean ti = ARGV_VALUE(1,boolean);
	SVM_Boolean lris = ARGV_VALUE(2,boolean);
	SVM_Boolean pm = ARGV_VALUE(3,boolean);
	SVM_Code c = ::svm_value_library_get_code(svm,l);
	SVM_Kernel k = ::svm_kernel_new_code(svm,ti,lris,pm,nullptr/* no accesscontrol */,c);
	VARIABLE_GLOBAL(k);
	auto tk = new type_instance;
	tk->_kernel = k;
	return NEW_PLUGIN(kernel,instance,tk);
%}

INSTRUCTION kernel.new_symbol SYM BLN : transmit_interruptions BLN : last_return_is_shutdown BLN : protected_mode -> kernel.instance
%{
	SVM_Value_Symbol s = ::svm_parameter_value_get(svm,argv[0]);
	SVM_Boolean ti = ARGV_VALUE(1,boolean);
	SVM_Boolean lris = ARGV_VALUE(2,boolean);
	SVM_Boolean pm = ARGV_VALUE(3,boolean);
	SVM_Kernel k = ::svm_kernel_new_symbol(svm,ti,lris,pm,nullptr/* no accesscontrol */,s);
	VARIABLE_GLOBAL(k);
	auto tk = new type_instance;
	tk->_kernel = k;
	return NEW_PLUGIN(kernel,instance,tk);
%}

INSTRUCTION kernel.get_current -> kernel.instance
%{
	SVM_Kernel k = ::svm_kernel_get_current(svm);
	VARIABLE_GLOBAL(k);
	auto tk = new type_instance;
	tk->_kernel = k;
	return NEW_PLUGIN(kernel,instance,tk);
%}

INSTRUCTION kernel.print kernel.instance -> STR
%{
	auto tk = ARGV_PLUGIN(0,kernel,instance);
	SVM_String s = ::svm_kernel_print(svm,tk->_kernel);
	return NEW_VALUE(string,s);
%}

Cadavre

Modifiez le code de l'extension :

PLUGIN kernel

DEFINE

TYPE kernel.instance
%{
	SVM_Kernel _kernel;
%}
delete default:
%{
	VARIABLE_LOCAL(object->_kernel);
%}

INSTRUCTION kernel.new_code LIB BLN : transmit_interruptions BLN : last_return_is_shutdown BLN : protected_mode -> kernel.instance
%{
	SVM_Value_Library l = ::svm_parameter_value_get(svm,argv[0]);
	SVM_Boolean ti = ARGV_VALUE(1,boolean);
	SVM_Boolean lris = ARGV_VALUE(2,boolean);
	SVM_Boolean pm = ARGV_VALUE(3,boolean);
	SVM_Code c = ::svm_value_library_get_code(svm,l);
	SVM_Kernel k = ::svm_kernel_new_code(svm,ti,lris,pm,nullptr/* no accesscontrol */,c);
	VARIABLE_GLOBAL(k);
	auto tk = new type_instance;
	tk->_kernel = k;
	return NEW_PLUGIN(kernel,instance,tk);
%}

INSTRUCTION kernel.new_symbol SYM BLN : transmit_interruptions BLN : last_return_is_shutdown BLN : protected_mode -> kernel.instance
%{
	SVM_Value_Symbol s = ::svm_parameter_value_get(svm,argv[0]);
	SVM_Boolean ti = ARGV_VALUE(1,boolean);
	SVM_Boolean lris = ARGV_VALUE(2,boolean);
	SVM_Boolean pm = ARGV_VALUE(3,boolean);
	SVM_Kernel k = ::svm_kernel_new_symbol(svm,ti,lris,pm,nullptr/* no accesscontrol */,s);
	VARIABLE_GLOBAL(k);
	auto tk = new type_instance;
	tk->_kernel = k;
	return NEW_PLUGIN(kernel,instance,tk);
%}

INSTRUCTION kernel.get_current -> kernel.instance
%{
	SVM_Kernel k = ::svm_kernel_get_current(svm);
	VARIABLE_GLOBAL(k);
	auto tk = new type_instance;
	tk->_kernel = k;
	return NEW_PLUGIN(kernel,instance,tk);
%}

INSTRUCTION kernel.coredump kernel.instance -> STR
%{
	auto tk = ARGV_PLUGIN(0,kernel,instance);
	SVM_String s = ::svm_kernel_get_coredump(svm,tk->_kernel);
	return NEW_VALUE(string,s);
%}

Générez l'extension puis compilez la. Ecrivez une petite application de test appellant cette dernière instruction sur le noyau courant ainsi que sur des noyaux créés par les deux premières instructions.

Cette fois, la fonction svm_kernel_get_coredump génère une chaine contenant la totalité des informations du noyau, comme en cas d'erreur !

Etat

Modifiez le code de l'extension :

PLUGIN kernel

includes:
%{
#include <iostream>
%}

DEFINE

TYPE kernel.instance
%{
	SVM_Kernel _kernel;
%}
delete default:
%{
	VARIABLE_LOCAL(object->_kernel);
%}

INSTRUCTION kernel.new_code LIB BLN : transmit_interruptions BLN : last_return_is_shutdown BLN : protected_mode -> kernel.instance
%{
	SVM_Value_Library l = ::svm_parameter_value_get(svm,argv[0]);
	SVM_Boolean ti = ARGV_VALUE(1,boolean);
	SVM_Boolean lris = ARGV_VALUE(2,boolean);
	SVM_Boolean pm = ARGV_VALUE(3,boolean);
	SVM_Code c = ::svm_value_library_get_code(svm,l);
	SVM_Kernel k = ::svm_kernel_new_code(svm,ti,lris,pm,nullptr/* no accesscontrol */,c);
	VARIABLE_GLOBAL(k);
	auto tk = new type_instance;
	tk->_kernel = k;
	return NEW_PLUGIN(kernel,instance,tk);
%}

INSTRUCTION kernel.new_symbol SYM BLN : transmit_interruptions BLN : last_return_is_shutdown BLN : protected_mode -> kernel.instance
%{
	SVM_Value_Symbol s = ::svm_parameter_value_get(svm,argv[0]);
	SVM_Boolean ti = ARGV_VALUE(1,boolean);
	SVM_Boolean lris = ARGV_VALUE(2,boolean);
	SVM_Boolean pm = ARGV_VALUE(3,boolean);
	SVM_Kernel k = ::svm_kernel_new_symbol(svm,ti,lris,pm,nullptr/* no accesscontrol */,s);
	VARIABLE_GLOBAL(k);
	auto tk = new type_instance;
	tk->_kernel = k;
	return NEW_PLUGIN(kernel,instance,tk);
%}

INSTRUCTION kernel.get_current -> kernel.instance
%{
	SVM_Kernel k = ::svm_kernel_get_current(svm);
	VARIABLE_GLOBAL(k);
	auto tk = new type_instance;
	tk->_kernel = k;
	return NEW_PLUGIN(kernel,instance,tk);
%}

INSTRUCTION kernel.state kernel.instance
%{
	auto tk = ARGV_PLUGIN(0,kernel,instance);
	std::cout << "State (raw): " << ::svm_kernel_get_state(svm,tk->_kernel) << std::endl
		<< "Interruption: ";
	SVM_Value_Interruption i = ::svm_kernel_get_interruption(svm,tk->_kernel);
	if(i==nullptr)
	{
		std::cout << "(none)";
	}
	else
	{
		SVM_String is = ::svm_value_print(svm,i);
		std::cout << RAW_STRING(is);
	}
	std::cout << std::endl
		<< "Transmit interruptions: " << ::svm_kernel_has_transmitinterruption(svm,tk->_kernel) << std::endl
		<< "Last return is shutdown: " << ::svm_kernel_has_lastreturnisshutdown(svm,tk->_kernel) << std::endl
		<< "Protected mode: " << ::svm_kernel_has_protectedmode(svm,tk->_kernel) << std::endl
		<< "Runnable: " << ::svm_kernel_is_runnable(svm,tk->_kernel) << std::endl
		<< "Terminated: " << ::svm_kernel_is_terminated(svm,tk->_kernel) << std::endl;
%}

Générez l'extension puis compilez la. Ecrivez une petite application de test appellant cette dernière instruction sur le noyau courant ainsi que sur des noyaux créés par les deux premières instructions.

Cette fois, une vue détaillée de l'état du noyau peut être extraite pour un diagnostic précis d'un noyau.

Utilisation

Modifiez le code de l'extension :

PLUGIN kernel

includes:
%{
#include <iostream>
%}

DEFINE

TYPE kernel.instance
%{
	SVM_Kernel _kernel;
%}
delete default:
%{
	VARIABLE_LOCAL(object->_kernel);
%}

INSTRUCTION kernel.new_code LIB BLN : transmit_interruptions BLN : last_return_is_shutdown BLN : protected_mode -> kernel.instance
%{
	SVM_Value_Library l = ::svm_parameter_value_get(svm,argv[0]);
	SVM_Boolean ti = ARGV_VALUE(1,boolean);
	SVM_Boolean lris = ARGV_VALUE(2,boolean);
	SVM_Boolean pm = ARGV_VALUE(3,boolean);
	SVM_Code c = ::svm_value_library_get_code(svm,l);
	SVM_Kernel k = ::svm_kernel_new_code(svm,ti,lris,pm,nullptr/* no accesscontrol */,c);
	VARIABLE_GLOBAL(k);
	auto tk = new type_instance;
	tk->_kernel = k;
	return NEW_PLUGIN(kernel,instance,tk);
%}

INSTRUCTION kernel.new_symbol SYM BLN : transmit_interruptions BLN : last_return_is_shutdown BLN : protected_mode -> kernel.instance
%{
	SVM_Value_Symbol s = ::svm_parameter_value_get(svm,argv[0]);
	SVM_Boolean ti = ARGV_VALUE(1,boolean);
	SVM_Boolean lris = ARGV_VALUE(2,boolean);
	SVM_Boolean pm = ARGV_VALUE(3,boolean);
	SVM_Kernel k = ::svm_kernel_new_symbol(svm,ti,lris,pm,nullptr/* no accesscontrol */,s);
	VARIABLE_GLOBAL(k);
	auto tk = new type_instance;
	tk->_kernel = k;
	return NEW_PLUGIN(kernel,instance,tk);
%}

INSTRUCTION kernel.get_current -> kernel.instance
%{
	SVM_Kernel k = ::svm_kernel_get_current(svm);
	VARIABLE_GLOBAL(k);
	auto tk = new type_instance;
	tk->_kernel = k;
	return NEW_PLUGIN(kernel,instance,tk);
%}

INSTRUCTION kernel.attach kernel.instance -> BLN
%{
	auto tk = ARGV_PLUGIN(0,kernel,instance);
	SVM_Boolean b = ::svm_process_kernel_attach(svm,CURRENT(process),tk->_kernel,0,nullptr);
	return NEW_VALUE(boolean,b);
%}

INSTRUCTION kernel.detach kernel.instance -> BLN
%{
	auto tk = ARGV_PLUGIN(0,kernel,instance);
	SVM_Boolean b = ::svm_process_kernel_detach(svm,CURRENT(process),tk->_kernel,0,nullptr);
	return NEW_VALUE(boolean,b);
%}

Générez l'extension puis compilez la. Créez un fichier exécutable pour tester l'instruction :kernel.attach avec ce code :

#!/usr/bin/env svm
LOG
LOCAL PLUGIN "svmpluginkernel/libsvmkernel.so"
PLUGIN "svmcom.so"
PLUGIN "svmrun.so"
PROCESS "kernel"
	CODE "main" INLINE
		:debug BREAK
		:memory LIB/l, kernel.instance/k
		:library "lib" """
		:debug BREAK "lib"
		:com.message 2
		""" -> &l
		:kernel.new_code @&l TRUE FALSE TRUE -> &k
		:com.message 1
		:kernel.attach @&k
		:com.message 3
	END
	SEQUENCER run.stack
END

Notez que :

  1. Ces deux instructions ici attachent et détachent le noyau au processus courant.
  2. La présence de la directive SEQUENCER run.stack dans le processus de l'application, indispensable pour que le noyau soit attaché au processus courant.
  3. Attacher un noyau à un processus est obligatoire pour exécuter le code à l'intérieur de ce noyau. Le moment où son exécution est effective dépend du séquenceur associé au processus.
  4. Dans cette application, le noyau courant se termine avant que le noyau attaché soit lancé par le séquenceur : pour que l'exécution passe immédiatement au noyau attaché, il faut suspendre le noyau courant :
PLUGIN kernel

includes:
%{
#include <iostream>
%}

DEFINE

TYPE kernel.instance
%{
	SVM_Kernel _kernel;
%}
delete default:
%{
	VARIABLE_LOCAL(object->_kernel);
%}

INSTRUCTION kernel.new_code LIB BLN : transmit_interruptions BLN : last_return_is_shutdown BLN : protected_mode -> kernel.instance
%{
	SVM_Value_Library l = ::svm_parameter_value_get(svm,argv[0]);
	SVM_Boolean ti = ARGV_VALUE(1,boolean);
	SVM_Boolean lris = ARGV_VALUE(2,boolean);
	SVM_Boolean pm = ARGV_VALUE(3,boolean);
	SVM_Code c = ::svm_value_library_get_code(svm,l);
	SVM_Kernel k = ::svm_kernel_new_code(svm,ti,lris,pm,nullptr/* no accesscontrol */,c);
	VARIABLE_GLOBAL(k);
	auto tk = new type_instance;
	tk->_kernel = k;
	return NEW_PLUGIN(kernel,instance,tk);
%}

INSTRUCTION kernel.new_symbol SYM BLN : transmit_interruptions BLN : last_return_is_shutdown BLN : protected_mode -> kernel.instance
%{
	SVM_Value_Symbol s = ::svm_parameter_value_get(svm,argv[0]);
	SVM_Boolean ti = ARGV_VALUE(1,boolean);
	SVM_Boolean lris = ARGV_VALUE(2,boolean);
	SVM_Boolean pm = ARGV_VALUE(3,boolean);
	SVM_Kernel k = ::svm_kernel_new_symbol(svm,ti,lris,pm,nullptr/* no accesscontrol */,s);
	VARIABLE_GLOBAL(k);
	auto tk = new type_instance;
	tk->_kernel = k;
	return NEW_PLUGIN(kernel,instance,tk);
%}

INSTRUCTION kernel.get_current -> kernel.instance
%{
	SVM_Kernel k = ::svm_kernel_get_current(svm);
	VARIABLE_GLOBAL(k);
	auto tk = new type_instance;
	tk->_kernel = k;
	return NEW_PLUGIN(kernel,instance,tk);
%}

INSTRUCTION kernel.attach kernel.instance -> BLN
%{
	auto tk = ARGV_PLUGIN(0,kernel,instance);
	SVM_Boolean b = ::svm_process_kernel_attach(svm,CURRENT(process),tk->_kernel,0,nullptr);
	return NEW_VALUE(boolean,b);
%}

INSTRUCTION kernel.detach kernel.instance -> BLN
%{
	auto tk = ARGV_PLUGIN(0,kernel,instance);
	SVM_Boolean b = ::svm_process_kernel_detach(svm,CURRENT(process),tk->_kernel,0,nullptr);
	return NEW_VALUE(boolean,b);
%}

INSTRUCTION kernel.suspend kernel.instance
%{
	auto tk = ARGV_PLUGIN(0,kernel,instance);
	::svm_kernel_suspend(svm,tk->_kernel);
%}

Ainsi que le code de l'application :

#!/usr/bin/env svm
LOG
LOCAL PLUGIN "svmpluginkernel/libsvmkernel.so"
PLUGIN "svmcom.so"
PLUGIN "svmrun.so"
PROCESS "kernel"
	CODE "main" INLINE
		:debug BREAK
		:memory LIB/l, kernel.instance/k, kernel.instance/c
		:library "lib" """
		:debug BREAK "lib"
		:com.message 2
		""" -> &l
		:kernel.new_code @&l TRUE FALSE TRUE -> &k
		:com.message 1
		:kernel.attach @&k
		:com.message 3
		:kernel.get_current -> &c
		:kernel.suspend @&c
		:com.message 4
	END
	SEQUENCER run.stack
END

Cette fois, le noyau attaché est exécuté lorsque le noyau courant est suspendu. Lorsque le noyau attaché se termine, l'exécution du noyau courant reprend là où il en était grâce au séquenceur run.stack.

Conclusion

Vous venez de voir comment manipuler les noyaux depuis une extension.

La manipulation des noyaux eux-mêmes est rare dans le code d'instructions, et il est plus fréquent de modifier le contenu de ces noyaux.

Cependant, le code des séquenceurs que nous verrons dans le prochain didacticiel fait un appel important à cette partie de l'interface pour incarner une politique de séquencement au sein d'un processus.