Preguntes curtes

  1. ¿En quins casos, a més de bloqueig o final del procés, pot produir-se un canvi de procés en un sistema amb planificador basat en la política “Completely Fair Scheduling” (CFS)? I en Round-Robin (RR)?

    Resposta
    • CFS: el procés deixa la CPU quan acaba, es bloqueja o el seu temps de CPU assoleix el teòric que li pertoca (el quocient entre el temps que porta en execució i el nombre de processos al sistema)

    • RR: el procés deixa la CPU quan acaba, es bloqueixa o consumeix el seu quantum

  2. Donada la següent jerarquia de processos:

    p2 jerarquia

    1. Indica per a cada procés quins pids poden conèixer de la resta de la jerarquia.

      Resposta
      1. El procés pare coneix el pid dels seus fills, és el valor de retorn de la syscall fork(). Tanmateix, tot procés pot conèixer el seu pid (crida getpid()) i el pid del seu pare (crida getppid()).

    2. Quin codi implementaries perquè cadascun mostri aquests pids per pantalla?

      Resposta
       1int main(int argc, char *argv[]) {
       2  char buffer[128];
       3  int res, pid, status, i;
       4  for (i = 0; i < 3; i++) {
       5    res = fork();
       6    switch(res) {
       7    case -1:
       8      perror("Error en fork");
       9      exit(1);
      10      break;
      11    case  0:
      12      sprintf(buffer,"proc %d, pare %d\n",getpid(),getppid());
      13      write(1,buffer,strlen(buffer));
      14      exit(0);
      15    }
      16  }
      17  for (i = 0; i < 3; i++) {
      18      pid = waitpid(-1,&status,0);
      19  }
      20}
    3. ¿És possible garantir que l’ordre dels missatges sigui sempre el mateix?

      Resposta

      No es pot garantir l’ordre dels missatges, car tots els processos competeixen per la CPU.

Processos i signals

  1. Donat el següent codi, contesta raonadament a les següents preguntes:

     1void f_signal(int s) {
     2  char b[128];
     3  sprintf(b,"Signal ack %d\n",s);
     4  write(1,b,strlen(b));
     5}
     6int main(int argc,char *argv[]) {
     7struct sigaction sa;
     8sigset_t m,m1;
     9sigfillset(&m);
    10sigprocmask(SIG_BLOCK,&m,NULL);
    11sa.sa_handler=f_signal;
    12sigemptyset(&sa.sa_mask);
    13sa.sa_flags=0;
    14sigaction(SIGUSR1,&sa,NULL);
    15sigdelset(&m,SIGUSR1);
    16while(1) {
    17  sigsuspend(&m);
    18}
    19}
    1. Si, des de teclat, enviem un SIGUSR1 al procés mitjançant la comanda kill, veurem el missatge "Signal ack XX"? (a on XX és el codi del SIGUSR1)

      Resposta

      Sí, perquè el tenim desbloquejat a la màscara del sigsuspend i hem fet previament un sigaction per modificar el tractament per defecte.

    2. Què passarà si enviem un SIGINT quan estem bloquejats al sigsuspend?

      Resposta

      No es tractarà ja que el tenim bloquejat al sigsuspend.

  2. Donat el següent codi (el tractament d’errors ha estat omès per claredat; cap crida al sistema retorna error), respon a les següents preguntes, justificant totes les respostes, suposant que executem el programa amb la línia de comandes:

    $ ./ejercicio_exec 4
     1        int sigchld_recibido = 0;
     2        int pid_h;
     3        void trat_sigalrm(int signum) {
     4        char buff[128];
     5           if (!sigchld_recibido) kill(pid_h, SIGKILL);
     6           strcpy(buff, Timeout!);
     7           write(1,buff,strlen(buff));
     8           exit(1);
     9        }
    10        void trat_sigchld(int signum) {
    11                sigchld_recibido = 1;
    12        }
    13        void main(int argc,char *argv[])
    14        {
    15          int ret,n;
    16          int nhijos = 0;
    17          char buff[128];
    18          struct sigaction trat;
    19          trat.sa_flags = 0;
    20          sigempty(&trat.sa_mask);
    21          trat.sa_handler = trat_sigchld;
    22          sigaction(SIGCHLD, &trat, NULL);
    23          /* linia 23 */
    24          n=atoi(argv[1]);
    25          if (n>0) {
    26                pid_h = fork();
    27                if (pid_h == 0){
    28                  n--;
    29                  trat.sa_flags = 0;
    30                  sigempty(&trat.sa_mask);
    31                  trat.sa_handler = trat_sigalrm;
    32                  sigaction(SIGALRM, &trat, NULL);
    33                  sprintf(buff, "%d", n);
    34                  execlp("./ejercicio_exec", "ejercicio_exec", buff, (char *)0);
    35                }
    36                strcpy(buff,"Voy a trabajar \n");
    37                write(1,buff,strlen(buff));
    38                    alarm (10);
    39                hago_algo_de_trabajo();/*no ejecuta nada relevante para el problema */
    40                alarm(0);
    41                while((ret=waitpid(-1,NULL,0))>0) {
    42                    nhijos++;
    43                }
    44                sprintf(buff,"Fin de ejecución. Hijos esperados: %d\n",nhijos);
    45                write(1,buff,strlen(buff));
    46          } else {
    47                strcpy(buff,"Voy a trabajar \n");
    48                write(1,buff,strlen(buff));
    49                    alarm(10);
    50                hago_algo_de_trabajo();/*no ejecuta nada relevante para el problema */
    51                    alarm(0);
    52                    strcpy(buff, Fin de ejecución\n);
    53                     write(1,buff, strlen(buff));
    54          }
    55        }
    1. Dibuixa la jerarquia de processos que crea i assigna a cada procés un identificador per poder referir-te a ells a les següents preguntes.

      Resposta

      120

    2. Suposant que l’execució de la funció hago_algo_de_trabajo() triga sempre menys de 10 segons.

      1. Per cada procés, indica quins missatges mostrarà per pantalla.

        Resposta

        Si la rutina acaba abans que passin els 10 segons, el temporitzador es desactiva i tots els processos acaben amb normalitat. Pinicial comença l’execució amb n==4, crea H1 i tot seguit passa a executar el codi de la línia 36. H1 executa la branca de l' if a la línia 27, decrementa n i muta (ie, canvia la imatge del procés) per executar una nova instància del mateix programa. En començar aquesta nova instància crea H2 i passa a executar el codi de la línia 36. El comportament d’H2 i H3 és el mateix. H4 muta amb n==0 i , en conseqüència, en mutar entra per la branca de l' else de la línia 46.

        Els missatges serien:

        Pinicial, H1, H2 i H3 mostren: “Voy a trabajar” i “Fin de ejecución. Hijos esperados: 1”. H4 mostra: “Voy a trabajar” i “Fin de ejecución."

      2. Per a cada procés, indica quins signals rebrà.

        Resposta

        Pinicial, H1, H2 i H3 reben SIGCHLD quan els seus fills acaben.

      3. Suposa que movem les sentències des de la línia 29 a la 32 a la posició de la línia 23, afectaria d’alguna manera les respostes de les dues preguntes anteriors? Com?

        Resposta

        No, perquè la reprogramació del signal només afectaria si els processos reben aquest tipus de signal, i en aquest cas cap procés rep el SIGALRM (abans que passin els 10 segons acaba la funció i es desactiva el temporitzador).

    3. Suposem ara que l’execució de la funció hago_algo_de_trabajo triga sempre més de 10 segons.

      1. Per a cada procés, indica quins missatges mostrarà per pantalla.

        Resposta

        Salten els temporitzadors programats per Pinicial, H1, H2, H3 i H4. Cap procés no té reprogramat el SIGALRM. Pinicial perquè no entra a l'`if` de la línia 27; H1, H2 i H3 el reprogramen però en executar execlp perden la reprogramació i el nou codi no el torna a reprogramar (no entren a l' if de la línia 27); i H4 perquè tampoc no executa el codi de l' if on es reprograma. Per tant el tractament és el de per defecte (matar els processos). Els missatges serien:

        Pinicial, H1, H2 ,H3 i H4 mostren: “Voy a trabajar”

      2. Per a cada procés, indica quins signals rebrà.

        Resposta

        Tots els processos reben el SIGALRM. Si cap procés fill acaba abans que son pare hagi mort, provocarà que son pare rebi el SIGCHLD.

      3. Suposa que movem les sentències des de la línia 29 a la 32 a la posició de la línia 23, afectaria d’alguna manera les respostes de les dues preguntes anteriors? Com? Es possible garantir que el resultat sigui sempre el mateix?

        Resposta

        Si es mou la reprogramació serà efectiva per a tots els processos (tot i que els fills que muten la perden, en iniciar lexecució de la nova instància tornaran a executar la reprogramació). Per tant, tots els processos que rebin el SIGALRM executaran la funció trat_sigalrm. Els missatges mostrats i els signals rebuts depenen de l’ordre en què s’executin les sentències. Pinicial sempre mostrarà "Voy a trabajar" i “Timeout!”. Rebrà el SIGALRM i si el seu fill (H1) acaba abans que passin els 10 segons rebrà el SIGCHLD. Els processos fills (H1, H2, H3 i H4) poden rebre un SIGKILL del seu pare en qualsevol moment (quan acabi el temporitzador del pare). Si no el reben escriuran tant “Voy a trabajar” com “Timeout!”. Si el reben, quan arribi, acabaran l’execució i els missatges mostrats dependran del moment en què l’hagin rebut. Pel que fa als signals rebuts, si el temporitzador del pare salta abans que el seu, rebran SIGKILL, sinó rebran SIGALRM. En el cas de H1, H2 i H3, si els fills acaben abans que ells, rebran SIGCHLD.

  3. Donat el següent codi:

     1act.sa_handler = funcio_meva;
     2act.sa_flags = SA_RESTART;
     3sigemptyset(act.sa_mask);
     4sigaction(SIG_ALRM, &act, NULL)
     5pid = fork();
     6alarm(1);
     7if (pid == 0)
     8   execlp(``./binari, ``binari, (char *)0);
     9funcio_meva();

    Suposant que cap crida al sistema dona error, que el programa binari i la funció funcio_meva triguen 10 segons cadascuna i que tot el codi que apareix abans de l' execlp i de funcio_meva triga menys d’un segon en executar-se.

    1. Quin processos rebràn un SIGALRM?

      Resposta

      El reben tots dos processos. Tots dos tenen la crida a alarm(3). La programació del temporitzador no es veu afectada per l' exec(3)

    2. Com reacciona cada procés al SIGALRM en cas de rebre’l?

      Resposta

      En el cas del pare s’executarà la funció trat_signal, en el cas del fill, en fer l' exec, es recuperarà el tractament per defecte i la seva reacció dependrà de si el codi del binari reprograma de nou el SIGALRM (si no ho fa, el tractament per defecte és terminar).

  4. Analitza el codi que et mostrem a continuació i respon a les preguntes de la manera més detallada possible dins l’espai de que disposes. Suposa que executem el programa des del terminal amb la següent línia de comandes: $ ./a.out 2

     1#define FORBYTES 32
     2int beep = 0;
     3void ras(int s) {
     4        sigset_t m;
     5        if (s == SIGALRM) {
     6                write(1, " FINAL!\n", 8);
     7                beep++;
     8        }
     9        if (beep < 1) {
    10        sigprocmask(SIG_SETMASK,NULL, &m);
    11        sigdelset(&m,SIGALRM);
    12        if (sigsuspend(&m)>0) write(1,"SO",2);
    13        }
    14}
    15int main(int argc, char *argv[]) {
    16    int i;
    17    struct sigaction sa;
    18    int n = atoi(argv[1]);
    19    sa.sa_handler = ras;
    20    sigfillset(&sa.sa_mask);
    21    sa.sa_flags = SA_RESTART;
    22    for (i = 0; i < FORBYTES; i++) {
    23           sigaction(i, &sa, NULL);
    24           alarm(FORBYTES+1-i);
    25        }
    26    for (i = 0; i < n; i++) fork();
    27    while (waitpid(-1, NULL, 0)>0);
    28    write(1,"\tEXAMEN!",8);
    29    exit(0);30.
    30}
    1. Dibuixa la jerarquia de processos creada. Etiqueta cadascun per poder referir-te a ells durant la resta de la teva resposta.

      Resposta

      120

    2. Quins signals estan bloquejats quan comencem a executar la funció ras()?

      Resposta

      Tots. A la línia 20, omplim la màscara sa.sa_mask i, a la línia 23, la fixem com a màscara de signals del procés mentre s’executi la rutina d’atenció al signal. A la línia 10, inicialitzem la m amb la màscara de signals actual del procés.

    3. Quins processos escriuen "EXAMEN!"? I "FINAL!"? I "SO"?

      Resposta

      EXAMEN ho escriuen, de seguida, els processos N i F1 (ie, les fulles de l’arbre, que no tenen fills). Això provoca que F0 i A (els pares respectius) rebin un SIGCHLD i quedin suspesos a línia 12 esperant un SIGALRM. Només A té programat un temporitzador i, passat 1 segon, el rebrà i escriurà FINAL. Llavors A queda esperant, a la línia 27, la mort de F0. Però F0 no morirà mai (llevat que rebi un SIGALRM des d’un altre procés). Cap procés escriurà SO, car sigsuspend sempre acaba amb -1.

    4. Quina o quines línies de comandes hauries d’executar perquè tots els processos arribessin a la línia 29, escrivint per pantalla?

      Resposta

      $ kill -ALRM pidF0

      Quan F0 rebi un SIGALRM, sortirà del sigsuspend i escriurà FINAL. Com el seu fill ja és mort i beep val 1, no es bloquejarà a la línia 27, ni a la 12. Escriurà EXAMEN i morirà. Llavors el seu pare, A, sortirà del waitpid de la línia 27. Tampoc entrarà en el if de la línia 9, perquè la seva variable beep val 1. Escriurà EXAMEN i morirà.