Suivez-nous sur X
|
|
|
0,
A,
B,
C,
D,
E,
F,
G,
H,
I,
J,
K,
L,
M,
N,
O,
P,
Q,
R,
S,
T,
U,
V,
W,
X,
Y,
Z,
ALL
|
|
0,
A,
B,
C,
D,
E,
F,
G,
H,
I,
J,
K,
L,
M,
N,
O,
P,
Q,
R,
S,
T,
U,
V,
W,
X,
Y,
Z
|
|
0,
A,
B,
C,
D,
E,
F,
G,
H,
I,
J,
K,
L,
M,
N,
O,
P,
Q,
R,
S,
T,
U,
V,
W,
X,
Y,
Z
|
|
A propos d'Obligement
|
|
David Brunet
|
|
|
|
Programmation : Assembleur - les gestionnaires DOS
(Article écrit par Frédéric Delacroix et extrait d'Amiga News - janvier 1998)
|
|
Tout d'abord, chers lecteurs, veuillez excuser l'interruption momentanée de la rubrique ASM de votre journal préféré, due à
des raisons professionnelles. Ce mois-ci, nous attaquons une petite série sur l'explication et la programmation du coeur
d'AmigaDOS, qui nous mènera à l'exploration du monde étrange des DosPackets.
Principe général d'AmigaDOS
Comme vous le savez peut-être (si ce n'est pas le cas je vous l'apprends), AmigaDOS est principalement un gigantesque protocole
de communication entre tâches étendues appelées processus (process). Pour cela, décomposons un accès disque, par exemple.
Tout au début de la chaîne, on trouve un programme, commandé par l'utilisateur - vous ! - qui décide par exemple d'écrire un
fichier sur le disque dur. Pour cela, il a ouvert la dos.library et ouvert un fichier par la fonction Open() en mode MODE_NEWFILE.
La fonction Open() détermine, en examinant le nom du fichier donné en paramètre, le gestionnaire concerné. Cela peut passer par
le décodage d'assignations, de liens logiciels (soft-links), la prise en compte du répertoire courant, mais je ne m'étendrai
pas là-dessus. Le but est d'arriver au début de l'arborescence : un nom de volume (par ex. "Workbench:"), il faudra alors trouver
le périphérique en charge de ce volume en traversant la liste des volumes montés ou en demandant l'insertion dans un périphérique
par une requête à l'écran, ou directement le nom du périphérique lui-même si l'accès a été fait en utilisant directement celui-ci
(comme "DF0:s/startup-sequence" par exemple).
Une fois cette recherche effectuée, la fonction Open() envoie un message au processus - appelé gestionnaire de périphérique
(device-handler) - dont le nom est celui du périphérique privé des deux points (exemple : "DF0" pour le lecteur de disquette
interne). Que dit ce message ? "Ouverture de fichier en écriture", avec les paramètres nécessaires. La fonction Open() attend
alors le retour du message, indiquant que le gestionnaire a traité la demande, et en exploite les résultats avant de rendre
la main au programme.
Le gestionnaire, de son côté, a reçu le message, décode le nom de fichier, stocke toutes les informations nécessaires dans la
structure FileHandle vierge qui lui a été passée dans le message, et entreprend toutes les actions nécessaires pour satisfaire
à la demande. Ici, nous avons pris l'exemple d'un système de fichiers. Il existe donc (la plupart du temps, mais il y a des
exceptions comme "RAM") un périphérique Exec "en dessous" (par exemple le trackdisk.device pour les lecteurs de disquette
AmigaDOS). Le rôle de ce périphérique étant la prise en charge du stockage physique des données, c'est au gestionnaire de périphérique
lui-même qu'il revient d'organiser les données, ce qui n'est pas une tâche très simple.
Ensuite, il envoie ses ordres sous forme de message IORequest à la tâche en charge du périphérique Exec concerné pour l'écriture
des données sur le disque, en attend le retour et exploite les résultats (erreurs, etc.). Tout le travail d'organisation est
fait par le gestionnaire, les ordres envoyés au périphérique Exec se bornant à "écrire ce tampon de données en piste xx,
secteur yy face zz du lecteur de disquette". Lui s'occupe alors (quelquefois par l'intermédiaire d'une ressource) de
piloter le lecteur en question.
Il peut également s'agir d'un gestionnaire de périphérique qui ne s'occupe pas d'un système de fichiers. Un des cas les plus
simples est le gestionnaire "SPEAK:" chargé de la synthèse vocale : on lui envoie des données de la même façon mais il
se contente de les traduire en phonèmes par l'intermédiaire de la translator.library, puis de les envoyer au narrator.device.
Ce périphérique s'occupe alors de piloter l'audio.device qui produit les sons correspondant aux phrases à prononcer.
Dans le cas d'un tel gestionnaire, le "nom de fichier" est souvent composé d'options indiquant par exemple (pour SPEAK:)
la vitesse de prononciation, la hauteur de la voix, etc.
Il faut également citer le cas très particulier des gestionnaires de console comme "CON:", "RAW:" et autres. Ceux-ci, lorsqu'ils
reçoivent un message de type "ouverture de fichier", créent un nouveau processus, distinct à chaque fois,
pour gérer une nouvelle fenêtre Intuition. En accédant à "CON:", on provoque donc la création d'un nouveau processus, qui ne
porte pas de nom mais auquel le CLI (par exemple) peut accéder au travers du mot réservé "CONSOLE:" ou "*".
Détails techniques
C'est ici que vont intervenir les fameux DosPackets : ils constituent le moyen d'interaction entre les différents processus
relevant d'AmigaDOS (et non d'Exec). Ce qu'il faut avant tout savoir, c'est qu'un processus est une tâche au sens Exec du
terme à laquelle on a ajouté des données (en langage C, on dirait que la structure Process commence par une structure Task).
Parmi celles-ci, il y a le champ pr_MsgPort de la structure Process, qui est une structure MsgPort telle que celles utilisées
par Exec. C'est ce port de message qui sert aux fonctions d'AmigaDOS lors de l'envoi d'un message à un gestionnaire, et
au retour de ce message.
Quels sont donc ces fameux messages ? Il s'agit de DosPackets. Cependant, les choses sont un peu plus compliquées car la
structure DosPacket est toujours reliée à une structure Message. En réalité, c'est cette structure Message qui est envoyée
au port de la structure Process. Dans cette structure Message, le champ ln Name est alors un pointeur sur une structure DosPacket.
Réciproquement, la structure DosPacket contient un pointeur sur la structure Message associée. Pourquoi faire aussi compliqué
alors qu'il aurait suffi de mettre la structure DosPacket à la suite de la structure Message (comme Process et Task) ?
Héritage BCPL probablement. En attendant, il existe une structure, nommée StandardPacket, qui réunit Message et DosPacket de
cette façon car c'est tout de même plus pratique. Cette structure n'existe que pour cela car rien n'oblige les structures
Message et DosPacket à se suivre en mémoire. Il faudra en tenir compte lors de l'écriture d'un gestionnaire. Voici la structure
DosPacket :
Le champ dp_Type contient un code (ACùTION_quelque chose) qui détermine l'action demandée par le paquet. Par exemple, l'ouverture
d'un fichier en écriture provoque l'envoi d'un paquet de type ACTION_FINDOUTPUT. La lecture de données donne ACTION_READ. Les
champs dp_Arg1 à dp_Arg7 dépendent du type de paquet, je ne vais pas tout décrire ici. Quant aux champs dp_Res1 et dp_Res2,
ils correspondent aux deux résultats du paquet : le primaire (celui retourné par la fonction qui a envoyé le paquet par exemple)
et le secondaire (fourni généralement par IoErr()).
Voilà, j'espère que cette courte introduction théorique vous ouvrira l'appétit car le mois prochain nous attaquerons la
programmation d'un gestionnaire de périphérique AmigaDOS et j'expliquerai les détails de sa programmation.
|