A!ociation
Prolog
HERITAGE
9. Interruptions
9.1. Concepts
9.2. Description des interfaces
9.3. Exemple complet
On décrit dans ce chapitre comment lier des programmes Prolog à la survenue d'événements asynchrones tels que des interruptions matérielles. Lorsqu'une interruption survient, le programme Prolog courant est automatiquement suspendu, et la fonction gérant l'interruption est activée dès que la machine Prolog se trouve dans un état où l'on peut réaliser des appels croisés (c'est à dire à la prochaine inférence). Lorsque la fonction se termine, la démonstration suspendue reprend son cours normalement. Il est possible de communiquer entre les deux environnements par l'intermédiaire des données statiques (base de faits, tableaux, assignations).
Ce mécanisme permet donc de suspendre l'exécution en cours et d'empiler l'activation d'une nouvelle machine Prolog pour traiter l'interruption.
9.1. Concepts
La machine Prolog possède un vecteur de bits d'événements externes. Les huit premiers bits (bits 0 à 7) sont réservés pour des événements définis par l'utilisateur.
A chaque bit doit être associée une fonction C pour la construction des arguments et l'appel d'un but Prolog. Cette fonction C est installée par l'utilisateur en appelant la procédure pro_signal.
L'interruption d'un programme Prolog ne peut être servie qu'en certains états précis tels que la fin d'une unification, ou à l'intérieur d'un prédicat évaluable. Cette interruption doit donc être mémorisée jusqu'à ce que la machine Prolog soit en état de la traiter. Ceci est réalisé par la procédure send_prolog_interrupt qui doit être appelée par le gestionnaire d'interruption pour signaler à Prolog cet événement.
Pour lier un programme Prolog à un événement asynchrone donné, il faut donc réaliser les opérations suivantes :
1.
Choisir un bit (0 à 7) et le représenter par un masque (par exemple myEvent =
(1 << numéro du bit)).
2.
Ecrire une fonction (par exemple myHandler) qui servira à activer le programme Prolog gérant l'interruption.
3.
Associer, dans l'environnement Prolog, l'événement myEvent avec la fonction le traitant en appelant la fonction :
pro_signal(myEvent,myHandler).
© PrologIA
R 9 - 2
Manuel de Référence
4.
Dans la routine appelée lors de l'interruption, transmettre l'événement à Prolog en appelant la fonction :
send_prolog_interrupt(myEvent ).
Un exemple de séquence d'événements et de traitements peut être représenté par le schéma suivant : pro_signal(myEvent,myHandler) myHandler()
{
new_goal();...
next_solution();
kill_goal();
}
I
O
N
R
U
P
T
I
E
R
N
T
T
I
T
R
A
E
R
Prolog machine new_goal() next_solution() kill_goal()
(*myHandler)() reset myEvent flag prolog_event_handler(myEvent) interruption asynchrone utilisateur myAsynchronousHandler()
{
send_prolog_interrupt(myEvent);
}
Prolog machine set myEvent flag
...
A!ociation
Prolog
HERITAGE
9.2. Description des interfaces
Les fonctions définies ici permettent de lier Prolog II+ à des procédures d'interruption. Les prototypes de ces fonctions sont donnés à la fin de ce chapitre.
pro_signal(event_mask,event_handler)
Permet d'associer à l'événement event_mask la fonction d'activation
event_handler. Cette fonction renvoie -1L en cas d'erreur (notamment s'il existe déjà une fonction associée à event_mask), NULL sinon. Si le deuxième argument est NULL, la fonction d'activation associée au premier argument est supprimée et sa valeur est renvoyée comme résultat de la fonction. L'argument
event_mask doit être une des valeurs parmi 1, 2, 4, 8, 16, 32, 64, 128.
© PrologIA
A!ociation
Prolog
HERITAGE
Interruptiions
R 9 - 3
Lorsque la fonction event_handler est appelée, si son résultat n est supérieur à
0, l'erreur Prolog correspondante est déclenchée.
send_prolog_interrupt(event_mask)
Déclenche le traitement associé à l'interruption event_mask dès que la machine
Prolog le permet.
Conventions pour l'appel de la fonction d'activation event_handler.
Cette fonction doit retourner un entier qui est interprété comme un code erreur
Prolog si cet entier est positif.
Lorsque plusieurs interruptions sont en attente, elles sont traitées dans l'ordre défini par les numéros des bits (bit 0 d'abord).
Il est déconseillé d'utiliser les fonctions get_strterm et put_strterm si le temps est critique, ces fonctions étant relativement longues d'exécution.
Prototypes des fonctions d'interface
long pro_signal(event_mask,event_handler)
unsigned short event_mask;
int (*event_handler)(); void send_prolog_interrupt(event_mask) unsigned short event_mask;
9.3. Exemple complet
Nous décrirons dans cette section, à titre d'exemple, un cas précis construit pour le système UNIX et utilisant la primitive système kill pour envoyer des signaux à la tâche Prolog à partir du Shell.
Pour mettre en oeuvre cet exemple, suivre les étapes suivantes :
1.
Ecrire l'extension Prolog pour réagir au signal SIGUSR1 1 : 30 et y associer la règle message dans le fichier test.c.
#include <signal.h>
#include "proext.h"
#define MYEVENT 8 extern long pro_signal(); extern void send_prolog_interrupt(); extern P_SYMBOL pro_symbol();
1
C'est un signal asynchrone que l'on peut générer hors Prolog, depuis un autre processus UNIX.
UNIX est un système multitâches, tous les programmes qui s'exécutent sont des processus.
© PrologIA
R 9 - 4
Manuel de Référence
static int my_P_Handler()
{ int err=0; new_goal(); put_strterm(1,":message",&err); if (!err) err = next_solution(); kill_goal(); return err>0 ? err : 0 ;
} static void my_C_signal_handler()
{ send_prolog_interrupt(MYEVENT);
}
/* Cet appel pourrait être mis dans le programme principal pour faire l'initialisation automatiquement.
Le tableau de descripteurs n'est alors plus nécessaire
*/ static long install_handler()
{ pro_signal(MYEVENT,my_P_Handler); signal(SIGUSR1,my_C_signal_handler); return 0;
}
EXTERNAL_DESCRIPTOR testTable[] =
{{":install_handler", C_FUNCTION, 0,
(POINTER) install_handler},
{ 0, 0, 0, 0 }};
2.
Compiler test.c et faire l'édition de lien avec Prolog 1 . Ajouter dans Prolog le programme pour traiter les interruptions.
$ cc -c test.c
2
$ prolink test.o testTable
$ prolog
...
> insert;
message -> val(counter,n) outl(n); count(N) -> val(mod(N+1,1000000),N1) assign(counter,N1) count(N1);
;
> install_handler count(0);
3.
Se connecter sur une autre console, déterminer le numéro de processus (pid) de Prolog avec la commande ps, et envoyer le signal 30 à Prolog. A chaque envoi du signal, la valeur courante du compteur s'imprime sur la console
Prolog.
A!ociation
Prolog
HERITAGE
1
Voir le manuel d'utilisation § 2.8 pour trouver les instructions de compilation et d'édition de lien avec Prolog, adaptées à votre système.
2
Commande pour créer le module objet, compilé de test.c.
© PrologIA
A!ociation
Prolog
HERITAGE shell$ ps -ax
....2525...Prolog
shell$ kill -30 2525
1 shell$ kill -30 2525
Interruptiions
R 9 - 5
> install_handler
count(0);
64790
301267
1
Cette commande envoie le signal SIGUSR1 (auquel doit réagir Prolog) au processus Prolog.
© PrologIA
R 9 - 6
Manuel de Référence
A!ociation
Prolog
HERITAGE
© PrologIA

Link pubblico aggiornato
Il link pubblico alla tua chat è stato aggiornato.