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.
Pour commencer, créez le canevas de l'extension dans le fichier noyaux.svm_plugin en utilisant ce code :
PLUGIN kernel
DEFINE
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.
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.
svm_kernel_new_code
et svm_kernel_new_symbol
.svm_kernel_get_current
ou l'appel de macro CURRENT(kernel)
.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 :
svm_kernel_suspend
en l'état semble avoir peu d'effet sur l'exécution du noyau courant. Pourtant, elle met littéralement en pause le noyau : en fonction du séquenceur, un autre noyau peut prendre le relais lorsque l'instruction contenant cette fonction rend la main à la machine virtuelle.svm_kernel_terminate
conclut brutalement l'exécution du code. Appliqué à un autre noyau, il requiert l'arrêt de l'exécution du code entre deux instructions au sein d'un noyau.svm_kernel_suspend
de l'interface programmatique met en pause l'exécution du code dans un noyau.svm_kernel_terminate
de l'interface programmatique met fin à l'exécution du code dans un noyau.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);
%}
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 !
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.
svm_kernel_print
de l'interface programmatique permet d'obtenir une chaine courte représentant l'état du noyau.svm_kernel_get_coredump
de l'interface programmatique permet quant à elle d'obtenir une chaine longue détaillant l'ensemble du noyau.svm_kernel_get_state
permet de récupérer l'état général d'exécution d'un noyau,svm_kernel_get_interruption
permet de récupérer l'éventuelle interruption d'un noyau,svm_kernel_has_transmitinterruption
, svm_kernel_has_lastreturnisshutdown
, svm_kernel_has_protectedmode
permettent de récupérer l'état des drapeaux d'un noyau,svm_kernel_is_runnable
permet de savoir si un noyau peut être exécuté,svm_kernel_is_terminated
permet de savoir si un noyau a terminé son exécution.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 :
SEQUENCER run.stack
dans le processus de l'application, indispensable pour que le noyau soit attaché au processus 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
.
svm_process_kernel_attach
de l'interface programmatique permet d'attacher un noyau à un processus.svm_process_kernel_detach
de l'interface programmatique permet de' détacher un noyau d'un processus.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.