sisoputnfrba / foro

Foro de consultas para el trabajo práctico
151 stars 7 forks source link

Posible problema con RR #3775

Closed rood8592 closed 5 months ago

rood8592 commented 5 months ago

Buenas noches, Tenemos una duda con respecto a RoundRobin y es que a veces creemos que se ejecutan más instrucciones "de lo debido". Por ej, en la imagen de la consola que les paso, normalmente se ejecutan dos instrucciones con un quantum=1000 y un retardo en memoria de 500, por lo que tiene sentido que sean dos instrucciones. Lo que sucede es que a veces parecería ser como que llega tarde la interrupción, entonces se ejecuta una instrucción más. Aclaraciones:

1-El log de "INTERRUPCIÓN ACEPTADA" se hace cuando el hilo en CPU que maneja el interrupt comprueba que llegó una interrupcion y que corresponde con el PID que se está ejecutando y setea una variable global de HUBO_INTERRUPCIÓN en 1. 2-El log de "fue interrumpido" se hace cuando en el ciclo de instrucción se hace el check interrupt que verifica el valor de la variable global HUBO_INTERRUPCION y en base a eso devuelve o no el contexto.

Código del hilo RR en Kernel:

    void planificacion_rr(){
        while (1)
        {
            sem_wait(&proceso_en_cola_ready);
            sem_wait(&pasar_a_ejecucion);
            sem_wait(&planificacion_ready_iniciada);

            t_pcb* pcb_auxiliar = squeue_pop(lista_procesos_ready);
            pcb_auxiliar->estado = EXEC;
            squeue_push(lista_procesos_exec, pcb_auxiliar);
            log_info(logger, "PID: %d - Estado Anterior: READY - Estado Actual: EXEC", pcb_auxiliar->pid);

            enviar_pcb(pcb_auxiliar, fd_dispatch);

            interrupcion_quantum(pcb_auxiliar);

            recibir_contexto_actualizado(fd_dispatch);

            sem_post(&pasar_a_ejecucion);
            sem_post(&planificacion_ready_iniciada);

        }

    }

    void interrupcion_quantum(t_pcb* pcb_auxiliar){
        usleep(quantum * 1000);
        int pid_a_enviar = 0;
        pid_a_enviar = pcb_auxiliar->pid;
        send(fd_interrupt, &pid_a_enviar, sizeof(int), 0);
    }

Código hilo interrupt:

    void manejarConexionInterrupt(void* fd_interrupt)
    {
        info_fd_conexion* fd_recibido = fd_interrupt;
        int fd_kernel_interrupt = fd_recibido->fd;
        free(fd_recibido);

        int pid;
        int coincide_pid = 0;

        while(1)
        {
            int todo_ok = recv(fd_kernel_interrupt,&pid,sizeof(int),MSG_WAITALL); 

            if(todo_ok == 0){
                log_error(logger, "ME DESCONECTE AYUDAME POR FAVOR");
                break;
            }

            pthread_mutex_lock(&mutex_pid);
            coincide_pid = pid==PID_ACTUAL;
            pthread_mutex_unlock(&mutex_pid);

            if(coincide_pid)
            {
                log_debug(logger,"INTERRUPCION ACEPTADA");
                pthread_mutex_lock(&mutex_interrupcion);
                HAY_INTERRUPCION = 1;
                pthread_mutex_unlock(&mutex_interrupcion);

                coincide_pid = 0;
            }
            else
            {
                log_debug(logger,"INTERRUPCION IGNORADA");
            }                                                

        }
    }

Código del ciclo instrucción en cpu:

    void realizarCicloInstruccion(int fd_conexion_memoria, t_pcb* pcb_recibido,int cliente_fd_conexion_dispatch)
    {
        resetear_var_globales();
        establecer_contexto(pcb_recibido);                                                //CAMBIAR PID_ACTUAL POR EL DEL PCB RECIBIDO

        while(1){

        t_instruccion instruccion = fetch(registro.PC,fd_conexion_memoria,pcb_recibido->pid); //FETCH (SOLICITA Y RECIBE LA INSTRUCCION)

        decode_and_execute(instruccion,pcb_recibido,cliente_fd_conexion_dispatch);         //DECODIFICA LA INSTRUCCION Y LA EJECUTA 

        actualizar_pcb(pcb_recibido);                                                      //ACTUALIZAR PCB

        if(fue_desalojado())                                                               //CHEQUEA SI HUBO DESALOJO POR IO, EXIT, ETC
        {
            log_debug(logger,"fue desalojado");
            break;
        }

        if(check_interrupt(pcb_recibido,cliente_fd_conexion_dispatch))                     //CHEQUEA SI EN EL HILO DE INTERRUPCION LE LLEGO UNA INTERRUPCION
        {
            log_warning(logger,"fue interrumpido");
            break;
        }

        }
    }

Ejemplo en la consola:

image

PD: Agrego otra duda de RR, que pasa si setean el quantum en 30 segundos y el proceso que mandan tiene 2 instrucciones y termina al toque, se quedaría en el usleep nuestro programa, habría algun problema con eso? PD2: Otro problema con RR que pensamos es:¿ Qué deberia suceder si hay un proceso muy extenso en CPU y nosotros paramos la planificación y deseamos eliminar ese proceso, por más que le enviemos la interrupción a CPU y este nos devuelve el contexto, la función de RR va empezar a administrar su motivo de desalojo luego del usleep.

mefederico commented 5 months ago

Hola buenas!

Sobre la primera pregunta dejo un issue asociado que lo responde https://github.com/sisoputnfrba/foro/issues/3700, igualmente, en las pruebas vamos a tener contemplado estos casos

Que pasa si setean el quantum en 30 segundos... Deberían contemplar el caso y no esperar los 30 segundos restantes del quantum, esto queda mas claro si piensan como implementarían VRR

Para la ultima pregunta, la misma respuesta, el fin de quantum es el periodo máximo que puede estar un proceso en ejecución, pero recibir el proceso en dispatch y atender el contexto de ejecución es algo que tiene que poder pasar en cualquier momento anterior al fin del quantum

Saludos!

rood8592 commented 5 months ago

Ok, entonces para cerrar la primera duda ¿no debería preocuparnos tanto el tema de que cada tanto un proceso ejecute una instrucción más que el promedio en RR? ¿Hay algún margen aceptable? Por ejemplo, recién mandamos 6 procesos que tienen el mismo pseudocodigo que tiene 6 instrucciones y solo una vez un proceso ejecuto una instrucción de más.

iago64 commented 5 months ago

Buenas! Cómo va?

No, no tienen que preocuparse, porque estamos hablando de tiempos que rondan 1 o 2 segundos y una instrucción de mas o de menos no nos va a cambiar la existencia :)

Saludos.-

rood8592 commented 5 months ago

Gracias, y una ultima duda, el RR lo hicimos con usleep pero nos dimos cuenta ahora que va haber muchos casos como los que comenté más arriba en donde surgirán problemas cuando CPU nos devuelva un contexto por una razón ajena a la interrupción por FIN Q y kernel no lo pueda tratar por estar bloqueado en el usleep. Queríamos preguntar si hay alguna forma de combinar este sleep con otras herramientas (ej.hilos) para que funcione contemplando los casos anteriormente mencionados o debemos descartarla por completo e ir por otro lado.

rood8592 commented 5 months ago

Solucionado, gracias!

NazarenoLopez commented 5 months ago

Solucionado, gracias!

Hola! Podrías comentar como solucionaste este tema? Yo estoy teniendo el mismo inconveniente y no estoy encontrando la vuelta. Gracias!

rood8592 commented 5 months ago

Hola, ¿te referis a lo de que no se quede bloqueado en el usleep? Hicimos un hilo que maneje el usleep y envie la interrupción por cada proceso que se mande a execute y kernel se queda esperando el contexto. Si el proceso vuelve antes por otra razón lo detectamos y le hacemos pthread_cancel al hilo creado.