PRÁCTICAS DE LABORATORIO DE SISTEMAS OPERATIVOS

PRIMERA PRÁCTICA OBLIGATORIA (2002-03)

The ring (La señal)


  1. Enunciado.

    En esta práctica, los procesos formarán un corro. Irán transmitiendo la señal SIGUSR1 alrededor del corro. Cuando la señal haya dado siete vueltas, los procesos morirán.

    La práctica constará de un único ficheros fuente y su correspondiente makefile. El nombre del fichero fuente será ring.c y del fichero ejecutable que se produzca a partir de él será ring. El programa admitirá un único argumento que será el número de procesos que forman el corro. Si se le invoca sin ningún argumento, el programa imprimirá una línea indicando su forma correcta de uso.

    El proceso original tendrá un único hijo. Dicho hijo tendrá otro hijo sólo, que a su vez tendrá otro, y así hasta que la familia tenga tantos miembros como esté especificado en la línea de órdenes.

    Una vez creados todos los hijos, el hijo más jóven manda la señal SIGUSR1 al primer proceso. Cuando este proceso reciba la señal, la transmitirá a su hijo, el cual la transmitirá al suyo, y así sucesivamente hasta que la señal retorne al hijo más joven. El hijo más joven imprimirá por la pantalla "Vuelta número 1 completada.". En ese momento, el hijo más joven volverá a mandar la señal SIGUSR1, para volverla a recibir más tarde e informar de que se ha completado la segunda vuelta. En total, debe hacer esto siete veces. Después de cada una de las tres primeras vueltas, el proceso más joven debe dormir un segundo (usad sleep para ello) antes de mandar la señal al proceso más viejo de nuevo. En el resto de vueltas, no dormirá nada.

    Cuando el hijo menor acabe con las siete vueltas, morirá y devolverá un código de retorno unidad a su padre.

    Cuando cualquier proceso detecte que su hijo ha muerto, tomará su código de retorno, le sumará uno y devolverá el resultado de la suma a su padre al morir.

    Cuando el padre de todos los procesos detecte que su hijo ha muerto, tomará su código de retorno. Si el código de retorno obtenido más uno coincide con el número de procesos totales, imprimirá por pantalla:
    Ejecución satisfactoria.
    Si no es así, imprimirá: "Fracaso".

    Comportamiento anómalo

    Si la práctica fallara en cualquier momento, el programa lo debe detectar. El error producido debe aparecer por la pantalla y no puede permanecer vivo ningún proceso , cuando el programa acabe por el fallo. No deberéis usar para ello la opción -1 de kill porque mataría a todos los procesos del usuario. Sólo deben morir los procesos que pertenezcan al programa que ejecutáis.

  2. Plazo de presentación.

    Hasta el viernes 12 de abril, inclusive.

  3. Normas de presentación.

    Acá están.

  4. LPEs.

    1. Las tareas que tiene que realizar el programa son variadas. Os recomiendo que vayáis programándolas y comprobándolas una a una. No es muy productivo hacer todo el programa de seguido y corregir los errores al final. El esquema que os recomiendo seguir para facilitaros la labor es del tipo:
      1. Construir un primer programa que admita un número por la línea de órdenes y lo imprima en la pantalla. Compilad, ejecutad, depuradlo.
      2. Ahora debe poner un mensaje de uso si no se le introduce ningún argumento. Compilad, ejecutad, depurarlo.
      3. Probad a que el programa cree un hijo y un nieto de programa principal. Para ver que el programa funciona, dejad los procesos en pause() y arrancad el programa en segundo plano con &. Haced un ps y observad que se han creado justo tres procesos y que su relación de parentesco es lineal (Hay un padre, un hijo y un nieto). No os olvidéis de matarlos.
      4. A continuación, haced que cree tantos hijos como el número que se pase por la línea de órdenes. Los hijos deben formar una cadena lineal de parentesco. Debéis depurar el punto actual como hicisteis con el punto anterior.
      5. Continuad añadiendo requisitos de la práctica hasta llegar al resultado final. Después de añadir un requisito, depurad antes de proseguir.
    2. Evitad, en lo posible, el uso de variables globales. Tenéis la posibilidad de declarar variables estáticas.
    3. ¿Qué hago cuando mi programa se desboca para no perjudicar el funcionamiento de la máquina?
      Solución.
    4. El programa que he hecho se para a veces. O en mi casa se para, pero en clase, no. O en clase sí, pero en casa, no. Normalmente da una vuelta pero ya no da más.
      Solución.
    5. He seguido los consejos del LPE anterior. Sin embargo, ahora me ocurre una situación un tanto extraña. ¡Hay una variable que no funciona! El programa en esquema es como sigue:
           [[Código de iniciación, registro de SIGUSR1, etc.]]
           mi_hijo=fork();
           ...
           if (mi_hijo==0) /* Si soy el hijo menor */
               {kill(padre_de_todos, SIGUSR1);
                }
           for (;;) pause();
           [...]
           void manejadora(int seNal)
              {
               printf("Soy %d y voy a mandar la señal a %d.\n",
                      getpid(),mi_hijo); fflush(stdout);
               /* kill(mi_hijo,SIGUSR1); */
               }
      
      El hijo manda bien la señal al padre de todos porque se imprime el mensaje de la manejadora del padre, pero he tenido que comentar el kill porque mi_hijo vale 0. Su valor tiene que ser el pid del hijo del padre (lo que devolvió fork) pero vale 0. Es como si la variable global no funcionara. Además, en mi casa sí que funciona. Me estoy volviendo loco.
      Solución.


  5. Prácticas propuestas años anteriores.


© 2003 Guillermo González Talaván.