Tras mucho tiempo inactivo doi por finalizada esta práctica poniendo las claves que la desarrollan aunque algunos ya la hayan entegregado.
Los cambios han de realizarse en los ficheros:
proc.h
main.c
do_fork.c
proc.c
Yo opino que el orden de los ficheros a modificar debe ser ese para poder comprender el resultado de las pruebas.
Antes de comenzar a desarrollar la prácita se me pasaron por la cabeza una solución así que os la voy a contar para que veais porque no la he utilizado.
SOLUCIÓN 1 (NO APTA)
Se nos pide asignar a cada proceso una antiguedad, y a mi se ocurrió después de observar el fichero PROC.H que podía añadir un campo al registro que identificaba a cada descriptor de proceso.
Mi idea era "idealmente" correcta pero tenía 1 defecto: NO EREA VIABLE.
Pensando, pensando se me ocurrió que podría no funcionar por 2 motivos:
PRIMER MOTIVO:
Que en algún sitio se compruebe el tamaño de la estructura con el que TANENBAUM espera que tenga por ejemplo con la sentencia
sizeof.
sizeof ( struct proc );
Este primer dilema no he podido demostrarlo ya que no me puesto a buscarlo, así que vamos por el siguiente.
SEGUNDO MOTIVO:
Minix es un Sistema Operativos por lo tanto a veces las estructuras que nosotros vemos como tales, él no las interpreta como estructuras, sino que no siempre se accede a un registro de la siguiente forma:
REGISTRO.CAMPO
Como parte del código de MINIX está escrito en ensamblador, y éste no conoce de registros y campos, para acceder a ellos se hace lo siguiente BASE + DESPLAZAMIENTO y así obtiene el campo que está buscando, logicamente BASE es la dirección de la estructura y desplazamiento hace referencia al campo que está buscando.
La BASE será la dirección del puntero struct proc y el desplazamiento para acceder al primer campo será 0 al segundo el tamaño del campo 1 ... y así sucesivamente. Espero no haberme equivocado.
Como esto es en realidad lo que ocurre, no podemos añadir un campo a STRUCT PROC cuando a nosotros nos de la gana ya que el código ensamblador no está informado de esos cambios y accede de la forma BASE + DESPLAZAMIENTO y entonces se hace la picha un lío.
Como ya sabemos por que falla la solución 1, vamos a redarctar la solución 2.
SOLUCIÓN 2 (LA CORRECTA):
En esta solución vamos a dividirla en varios pasos:
1.- Modificar proc.h
2.- Modificar main.c
3.- Modificar do_fork.c
4.- Modificar proc.c
5.- Prueba 1
6.- Prueba 2
7.- Prueba 3
8.- Conclusiones
1.- Modificar proc.h
En este caso debemos crearnos la estructura que nos indique como guardar la antiguedad. Digamos que el dibujo podría ser un array y la flecha una variable que nos indique cual ha sido la última antiguedad que hemos asignado.
2.- Modificar main.c
Aquí debemos solamente hacer 2 cosas inicializar procesos de la imagen de memoria, y establecer cual va a ser la antiguedad del siguiente proceso que se ejecute.
Vamos por pasos, en la imagen se ve el bucle que recorre los 12 procesos que tiene MINIX en memoria, y vosotros os preguntareis porque 12 y no 345432 procesos, pues muy facil, utilizamos el script de siempre:
find . -name '*.[ch]' -exec grep 'NR_BOOT_PROC' \; -print
Se obtiene como resultado:
Como vemos está formado por
NR_TASKS + INIT_PROC_NR + 1
Otra vez seguimos sin saber el valor de INIT_PROC_NR pues a lo mismo:
find . -name '*.[ch]' -exec grep 'INIT_PROC_NR' \; -print
Dando como resultado:
4 + 7 + 1 = 12
Si queremos estar seguros de que hay 12 procesos en memoria y que el resto ya son procesos de usuario nos aseguramos de que estamos en el primer tty, por lo que pulsamos ALT+F1, ahora pulsamos F1 y vemos la tabla de procesos:
Como vemos en la siguiente imagen los procesos residentes en memoria estan marcados del -4 al 17 (12 procesos)
El proceso IDLE aparece entre paréntesis, las tareas entre corches y el resto son valores del 0 a ..., como vemos esto nos ayuda bastante a la realización de la práctica. Además si pulsamos F3 vemos con más exactitud los procesos de la imagen de memoria.
Ahora que ya sabemos lo que hay que hacer en main.c podemos continuar, pero sin antes hacer un pequeño resumen. Primero debemos recorrer los procesos de la imagen de memoria y darles su prioridad y por último indicarle a nuestra variable cual es la última prioridad que hemos indicado.
Esta forma de hacerla no es la ideal tambien podemos guardar en nuestra variable la prioridad siguiente o lo que queramos. Además debemos saber que no es necesario inicializar todo el array a 0 es decir los 104 elementos.
3.- Modificar do_fork.c
En este apartado que es el más sencillo debemos decirle al array que el proceso que se acaba de crear (RPC) tiene una prioridad de ....
Aquí teneis que tener en cuenta el desplazamiento que se produce con los procesos. Los procesos empiezan a numerarse por el -4 y nuestro array comienza a numerarse por 0, por lo que debemos ser cuidadosos de no hacer los siguiente:
ARRAY[ -4 ] = PRIORIDAD
Como vemos esto es absurdo y hay que tenerlo en cuenta, para solucionarlos sabed que la constante del kernel NR_TASKS tiene valor 4.
4.- Modificar proc.c
En el proc.c también la modificacion es muy sencilla pero debemos acordarnos de ESTRUCTURA DE DATOS I y II y de los punteritos, aquí debemos hacer un algoritmo que ordene elementos en una lista con cabecera y final pero teniendo en cuenta que el ultimo proceso de la lista no a punta a FINAL sino a NIL_PROC.
Mi recomendación es que os aprovecheis del código de MINIX y hagais solo la parte complicada dejando por ejemplo el código original para rellenar la lista cuando está vacia. En el siguiente código de MINIX que se muestra he dejado la función ENQUEUE peladita para que vosotros solo toqueis la parte que está en rojo y creeis el código necesario para insertar de forma ordenada.
5.- Prueba 1
Para realizar la primera prueba:
cc -o p1.out prueba-1.c
Para ejecutarla:
./p1.out
El resultado que debe dar es:
1.....................2........................
Porque pues basicamente ya que lo que hace el código es dado un proceso padre con número 1 crear un proceso hijo con índice 2 y logicamente el padre se debe mostrar antes que el hijo ya que nuestra prioridad es por orden de creación, el que antes se cree antes se debe ejecutar y el padre ha sido creado antes que el hijo.
6.- Prueba 2
cc -o p2.out prueba-2.c
Para ejecutarla:
./p2.out
El resultado que debe dar es:
Se crea el proceso padre.
Se crea el proceso hijo.
Se ejecuta antes el padre que el hijo.
El padre espera un segundo.
Se ejecuta el hijo e imprime 11111111...
Se ejecuta el padre e imprime 222222222.....
Temina de ejecutar se el hijo con 111111....
7.- Prueba 3
cc -o p3.out prueba-3.c
Para ejecutarla:
./p3.out
El resultado que debe dar es:
El proceso padre crea un total de n hijos por los que el resulado debe ser:
Primero el padre, luego el primer hijo, despues el segundo, .... es decir:
111...222...333...444...555...666...777...nnn
Sabía que se me olvidaba algo, en la función ENQUEUE hay que hacer una cosita con la llamada a la función SCHED, dicha función lo que hacía era modificar la prioridad de un proceso, es decir mover a un proceso de su cola, por lo que hay que acordarse de eso si vemos que hace cosas raras, ya que solo debe existir una cola. ESPERO ESTAR SEGURO DE TODO ESTO LO QUE DIGO.
8.- Conclusiones
Esto es todo amigos hasta nuestra siguiente entrega.
Sau2.