2.5. Pile d'exécution
Le but de ce problème est l'étude de la pile
d'exécution d'un programme.
Un programme séquentiel est composé d'un
ensemble de procédures qui s'appellent mutuellement. A chacune de ces
procédures est associée une suite d'instructions, encore
appelée le code de la procédure. Appelons activité
le phénomène résultant de l'exécution ininterrompue
d'une procédure unique. L'exécution d'un programme est donc une
suite d'activités. Nous appelons contexte d'une activité
l'ensemble des informations accessibles au processeur au cours de cette
activité. Le contexte comprend donc un contexte du processeur (registres)
et un contexte en mémoire (code et données). Le passage d'une
activité à une autre est réalisé par des
instructions spéciales, l'appel et le retour de procédure, qui
réalisent une commutation du contexte.
Lors de l'appel d'une procédure q par une
procédure p, il faut préparer les paramètres
transmis à q par p, sauver le contexte de p pour le
retrouver au retour, et remplacer ce contexte par celui de q. Au retour,
il faut préparer les paramètres transmis par q à
p, et restaurer le contexte de p. Le contexte de q est
perdu. Cette sauvegarde et cette restauration utilisent une pile. Nous
supposerons que les paramètres sont transmis par valeur; un
résultat unique est rendu au retour. Les procédures peuvent
être appelées récursivement directement ou
indirectement.
A- Justifier l'utilisation d'une pile pour cette
sauvegarde et cette restitution.
B- Comment passer les paramètres et le
résultat.
C- Où peut-on mettre les locaux de la
procédure appelée?
D- Décrire de façon détaillée
les opérations d'appel et de retour, en précisant à chaque
fois ce qui est fait par la procédure appelante et par la
procédure appelée.
E- Pensez-vous que cette pile puisse être utile
dans un contexte de multiprogrammation? d'appels au système?
d'interruptions?
Solution de l’exercice
2.5
Remarque: S'il n'y a pas de récursivité,
on peut réserver des emplacements fixes pour les contextes et
paramètres des différentes procédures du programme. La pile
n'est pas alors nécessaire. Cependant ceci conduit à
réserver statiquement l'espace mémoire utilisé par les
différentes procédures, même lorsqu'elles ne sont pas en
cours d'exécution.
2.5.1. Question A
Le retour de procédure se fait en ordre inverse des
appels. La restauration doit donc se faire en ordre inverse des sauvegardes.
C'est bien la structure de pile qui offre cet ordre.
2.5.2. Question B
Les paramètres doivent être
mémorisés quelque part par la procédure appelante, et
pouvoir être accédés par la procédure appelée.
La pile peut servir de zone d'échange puisque les deux procédures
connaissent le sommet de pile au moment de l'appel. Par ailleurs, comme la
procédure appelée normalement les utilise pendant toute la
durée de son activité, c'est-à-dire jusqu'au retour, ils
peuvent rester dans la pile jusqu'à ce moment là.
Un raisonnement analogue pour le résultat montre que
celui-ci doit être également conservé dans la pile pendant
toute la durée de l'exécution de la procédure, pour
être transmis à l'appelante lors du retour.
2.5.3. Question C
Les locaux de la procédure doivent être
créés lors du début de l'activité correspondante, et
détruits lors de la fin de l'activité. Si on admet les appels
récursifs, ces locaux ne peuvent être à une adresse fixe en
mémoire, puisqu'une même procédure peut donner lieu à
plusieurs activités qui doivent coexister ensembles, avec chacune des
locaux différents. Leur création/destruction doit donc être
dynamique. Comme la création correspond à l'appel et la
destruction au retour, ils sont détruits en ordre inverse de leur
création, toutes procédures confondues. On peut donc utiliser la
pile pour cela.
2.5.4. Question D
L'évolution de la pile au cours d'un appel de
procédure peut être décrit par le schéma donné
ci après.
Comme les objets locaux sont à un emplacement variable
de la pile, il est nécessaire de repérer la zone où ils se
trouvent, pour une exécution donnée de la procédure. Dans
le schéma ci-dessus, ce rôle est assuré par ce que nous
avons dénoté base. En général, il s'agit d'un
registre que les compilateurs réservent à cet effet, par
convention. Nous laissons à la procédure appelée le soin de
ranger ce registre (et de le restituer à la fin); certaines
procédures n'ayant pas de locaux, peuvent ne pas s'en préoccuper,
pourvu que le registre ait, au moment du retour, la même valeur qu'au
moment de l'appel.
procédure appelante:
tant que il faut sauvegarder faire
empiler (ce qu'il faut)
fait
réserver place résultat en pile
tant que il y a des paramètres faire
empiler (valeur du paramètre)
fait
appel_proc
supprimer les paramètres de la pile, si nécessaire
dépiler (résultat)
tant que il faut restaurer faire
dépiler (ce qu'il faut)
fait
procédure
appelée:
empiler (base)
base := sommet
réservation des locaux { sommet := sommet - taille }
corps de la procédure
supprimer les locaux { sommet := sommet + taille }
dépiler (base)
retour_proc
2.5.5. Question E
Dans un contexte de multiprogrammation, lors de l'interruption
d'un programme, il faut évidemment sauvegarder le contexte en cours. Ceci
peut être fait dans la pile. Cependant, le système peut
décider de réactiver un programme différent de celui qu'il
vient d'interrompre. Dans ce cas, on ne peut plus rien dire sur l'ordre des
retours vis-à-vis des appels. Ce que l'on peut affirmer,
néanmoins, c'est que pour un programme donné, lorsqu'il sera
réactivé, il faudra restituer le contexte qu'il avait lorsqu'il
avait été suspendu. Il faut donc attribuer une pile par
programme.
Lors d'un appel système ou d'une interruption, le
système doit sauvegarder le contexte du programme dans sa pile, et
mémoriser les registres base et
sommet dans un emplacement
réservé au programme. Il peut alors prendre une pile qui lui est
propre pour continuer le travail. Lorsqu'il veut relancer un programme, il
restitue d'abord les registres base et
sommet du programme, et restaure ensuite le
contexte à partir de cette pile.