sisoputnfrba / foro

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

Atención de syscalls por parte del Kernel: propuestas de solución #4284

Closed GabrielBorre closed 2 weeks ago

GabrielBorre commented 3 weeks ago

🖋️ Descripción

¡Buenos días! ¿Cómo están?

Tenemos dos propuestas de solución para resolver la atención de syscalls en el Kernel, pero nos gustaría saber cuál recomiendan.

Propuesta 1:

1) Tenemos una API en donde encolaremos las syscalls que realizan los hilos desde la CPU. Para que esta no se bloquee cuando, por ejemplo, se deban realizar peticiones a memoria (como en el caso de la syscall process_create), tendremos una rutina en el main, la cual se encargará de atender esas peticiones, permitiendo que la API nunca se bloquee cuando aparezcan semáforos o sentencias bloqueantes y pueda seguir atendiendo otras syscalls que se vayan realizando. Esta última rutina será persistente y va a estar preguntando si hay elementos en la cola de las syscalls para atenderlas una por una, mediante un switch.

Escribo un ejemplo en pseudo-código para que se comprenda mejor

Propuesta 2:

2) En la misma API que se encarga de recibir las syscalls podemos hacer un switch del nombre de la syscall que se haya solicitado y, en pos de que la API no se quede bloqueada por peticiones bloqueantes que se puedan realizar dentro de su cuerpo (por ejemplo, una peticion a memoria), podemos implementar un mecanismo de semáforos que activen rutinas persistentes en el main (cada una de esas rutinas se encargará de atender una syscall en específico).

Escribo un ejemplo en pseudocódigo para que se entienda mejor

Desde ya, muchas gracias !!

📚 Búsqueda en documentación/foros

No response

📄 Código relevante

Pseudo Código de la propuesta 1)


var cola_syscalls []string
var mutex sync.Mutex

//Funcion que se va a encargar de recibir la syscall en la API y encolarla en una variable global
func Recibir_y_encolar_syscalls(w http.ResponseWriter, r *http.Request) {
    //  Protocolo http (recibiremos un body que incluye una syscall_recibida)
    slice.PushMutex(&cola_syscalls, syscall_recibida, &mutex)

}

///

///funcion que se encarga de desencolar las syscalls y atenderlas una por una
func atenderSyscalls(){
    mutex_cola_syscalls
    for len(cola_syscalls)>0 {
    mutex_cola_syscalls
        syscall=slice.PopMutex(&cola_syscalls,mutex_cola_syscalls)
        switch(syscall):
    case:
        PROCESS_CREATE
        crear_proceso() //funcion que tiene la logica completa de la creacion de proceso (incluye la peticion a memoria)

    }

}

func main() {
        ///rutina persistente en el main
    go atenderSyscalls()

PseudoCódigo de la propuesta 2


//API que recibe y atiende syscalls
func Recibir_y_atender_syscalls(w http.ResponseWriter, r *http.Request) {
    //  Protocolo http (recibiremos un body que incluye una syscall_recibida)
    switch(syscall_recibida){
    case:
        Process_Create
        sem_iniciar_proceso <- pcb //(simplemente creamos un pcb con los parametros pasados por CPU)
    }

}

func crear_Proceso(){
for{
    pcb:=<-sem_iniciar_proceso
    //logica de la creacion de proceso
       sem_pedir_memoria_iniciar_proceso<-pcb //avisamos a una rutina persistente en el main que se active para que esta rutina no se bloquee por la peticion
}
}

func pedir_a_memoria_iniciar_proceso(){
for{
     <-sem_pedi_memoria_iniciar_proceso
       //logica del pedido a memoria

}
}

func main() {

    go crearProceso //permite crear el proceso en si
        go pedir_a_memoria_iniciar_proceso ////permite que la creacion de proceso no se bloquee por un pedido a memoria

🐛 Cómo reproducir el error

No response

💻 Logs

No response

📝 Normas del foro

iago64 commented 3 weeks ago

Buenas! Cómo va?

Por suerte ambas alternativas que planteas funcionarían, ahora, te hago unas preguntas, las syscalls, ¿Van a ser peticiones de la CPU verdad? Si son peticiones de la CPU y solo tenes una CPU, ¿Cuantas syscalls pensas que te pueden llegar a la vez?, esta bueno esto de que puedas delegarlas a otra rutina, ahora lo importante es que te asegures de que por ej en las syscall que no tienen ese componente asincrónico como pueden ser MUTEX_CREATE o MUTEX_UNLOCK, tiene sentido que las atiendas de manera asincrónica? No hay una alternativa intermedia donde las syscalls que si tienen cosas asincrónicas como DUMP_MEMORY si las delegas y las que no, simplemente atendes y seguis.

Saludos.-

GabrielBorre commented 3 weeks ago

Buenos días Dami! Cómo va?

En primer lugar, muchísimas gracias por tu respuesta y por todo el tiempo que te tomaste en atender la consulta. Nos es de gran ayuda!

En segundo lugar, respondo las preguntas que nos hacés para pensar la solución:

La cantidad de syscalls que nos pueden llegar a la vez es una porque, como vos decís, tenemos una única CPU y esta envía en un momento determinado una sola petición al Kernel (la syscall), siendo el único módulo que realiza este tipo de pedidos.

Por lo tanto, la alternativa 1 sería viable, pero entiendo que implicaría un poco más de costo computacional, porque, como vos dijiste, cuando queramos atender syscalls de manera sincrónica no haría falta activar desde la API otra rutina para que esta sea la encargada de atender la syscall; como alternativa, podríamos en la misma API hacer un switch del nombre de la syscall y devolver al hilo que la realizó a ejecutar en CPU (en caso de que la syscall sea sincrónica y no implique replanificar).

Asimismo, sería ocioso tener una cola de syscalls pendientes si las peticiones llegan de una en una.

Lo que sí me parece importante destacar (por si a otro grupo le sirve el issue) es que hay que tener cuidado con hacer un switch de la syscall y en la API desarrollar una lógica secuencial que involucre llamadas bloqueantes, porque si un hilo A está ejecutando y realiza una syscall, la API puede quedar bloqueada y, en consecuencia, cuando se replanifique (entiendo que la atención a la syscall y la replanificación son procesos concurrentes), el hilo B que entra a ejecutar en la CPU puede solicitar una syscall y, como la API podría estar bloqueada por una petición bloqueante, no se podría atender la syscall de este último hilo.

La alternativa más viable supongo que sería la 2: activar semáforos desde la API para que rutinas en el main ejecuten las syscalls asincrónicas y que dentro de la misma API se atiendan las syscalls sincrónicas.

¿Estoy en lo correcto?

Esa es mi última consulta y cierro el issue

Desde ya, muchísimas gracias por todo el tiempo y la ayuda!

iago64 commented 2 weeks ago

Buenas! Cómo va?

Como te comentaba, la idea del punto intermedio entre ambas alternativas es la implementación que me parece mas simple, donde te llega el request, atendes las syscall que tengan la posibilidad de ser sincrónicas y las que no, ahi si las delegas en una nueva Go Rutine para que se encargue de hacer toda la lógica que corresponde.

Tene en cuenta que las peticiones a la memoria no tienen que encolarse en el Kernel, vos le vas disparando las peticiones y la memoria te las va a ir contestando a medida que pueda, entonces vos desde Kernel podes atender la syscall, si corresponde mandarle a memoria para que haga algo y si es una syscall pura de Kernel (crear hilo, crear un mutex, etc) la resolves ahi en el momento y seguis ejecutando.

Saludos.-

GabrielBorre commented 2 weeks ago

Clarísimo Damián! Muchísimas gracias por toda la ayuda, nos sirve mucho!

Cierro el issue. Buen finde