UNIVERSITÉ BORDEAUX I U.F.R. Mathématiques et Informatique
7 septembre 1998 J.Bétréma
Durée: 2 heures
Tous documents interdits.
On rappelle que l'environnement d'un programme Unix est un tableau de chaî nes de caractères, chacune de la forme nom=valeur, et que la fonction getenv (char *nom) retourne un pointeur sur la valeur de la variable d'environnement, ou 0 si aucune variable de ce nom n'est définie.
Voici le code source d'un programme nommé machin : certaines lignes comportent une étiquette : dans les questions qui suivent, l'expression ligne i désigne la ligne d'étiquette /* i */.
char *e[2]; main (int argc, char **argv) { int f; char *s = getenv ("DES"); if (s == 0) { f = open (argv[1], O_RDWR | O_CREAT | O_TRUNC, 0644); /* 1 */ write (f, "bonjour\n", 8); /* 2 */ e[0] = malloc (15); /* 3 */ sprintf (e[0], "DES=%d", f); /* 4 */ e[1] = 0; /* 5 */ execle (argv[0], argv[0], 0, e); /* 6 */ } sscanf (s, "%d", &f); /* 7 */ write (f, "bonsoir\n", 8); /* 8 */ }
On exécute la commande machin truc dans un environnement où la variable DES n'est pas définie.
On considère plusieurs processus Unix qui partagent une même région de la mémoire. Plusieurs processus peuvent lire simultanément cette mémoire partagée, mais l'écriture dans cette mémoire est exclusive : c'est le problème classique lecteurs/rédacteurs. Le nombre des lecteurs simultanés est borné par une constante MAX.
Voici l'essentiel du code utilisé par un processus pour écrire dans cette mémoire ; ce code utilise les primitives IPC classiques. On rappelle qu'on peut manipuler plusieurs sémaphores à la fois avec la primitive semop, dont le deuxième argument est un tableau d'opérations (le troisième argument est la taille de ce tableau) ; chaque opération est une structure sembuf comportant trois champs : le numéro du sémaphore (en partant de zéro, comme d'habitude), l'incrémentation (ou la décrémentation) demandée pour sa valeur, et une option (non spécifiée dans le code qui suit).
char *partage; int semid; void init_ecriture (void) { short init_sem[] = {1, MAX}; int shmid = shmget (CLEF_PARTAGE, 1024, IPC_CREAT | IPC_EXCL | 0644); partage = shmat (shmid, 0, 0); /* creation et initialisation de deux semaphores */ semid = semget (CLEF_SEMAPHORE, 2, IPC_CREAT | IPC_EXCL | 0666); semctl (semid, 2, SETALL, init_sem); } void ecrire (char *source, int n) { int i; struct sembuf demande_ecriture[] = {{0, -1, option}, {1, -MAX, option}}, fin_ecriture[] = {{0, 1, option}, {1, MAX, option}}; semop (semid, demande_ecriture, 2); for (i = 0; i < n; i++) partage[i] = source [i]; semop (semid, fin_ecriture, 2); }
Note : le candidat n'est absolument pas censé connaî tre par coeur les définitions des primitives IPC ; on demande seulement de reconstituer tout ce qui peut l'être raisonnablement.
Décrire l'état des sémaphores et des processus à cet instant, puis la suite de l'exécution simultanée de ces processus.