UNIVERSITÉ BORDEAUX I U.F.R. Mathématiques et Informatique

7 septembre 1998 J.Bétréma


Maîtrise d'Informatique
Architecture Unix

Durée: 2 heures
Tous documents interdits.

1  Analyse de programme

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.

  1. Expliquer en détail, ligne par ligne, chaque étape de l'exécution de ce processus.

  2. Que se passe-t-il précisément si l'on omet la ligne 3 ? Idem pour la ligne 5.

  3. Lors de l'exécution de la ligne 8, le fichier f est-il ouvert ? Pourquoi ?

2  Sémaphores

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);  
}

  1. Expliquer en détail, ligne par ligne, ce que vous comprenez de ce code.

    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.

  2. Ecrire le code analogue pour un lecteur.

  3. On suppose que deux processus P1, P2 sont en cours de lecture, que P3 souhaite écrire, puis que P4 demande à son tour une lecture.

    Décrire l'état des sémaphores et des processus à cet instant, puis la suite de l'exécution simultanée de ces processus.


File translated from TEX by TTH, version 1.96.
On 18 Dec 1998, 19:58.