versiones ultima sistema operativo descargar como linux-kernel context-switch

linux kernel - ultima - ¿Cómo funcionan realmente las funciones schedule()+switch_to() del kernel de Linux?



ultima version de linux (1)

  1. Después de llamar a switch_to() , la pila del kernel cambia a la de la tarea nombrada a next . El cambio del espacio de direcciones, etc., se maneja, por ejemplo, en context_switch().
  2. schedule() no se puede llamar en un contexto atómico, incluso desde una interrupción (consulte la verificación en schedule_debug() ). Si se necesita una reprogramación, se establece el indicador de tarea TIF_NEED_RESCHED, que se verifica en la ruta de retorno de interrupción .
  3. Ver 2
  4. Creo que, con las pilas de 8K predeterminadas, las interrupciones se manejan con cualquier pila de kernel que se esté ejecutando actualmente. Si se usan pilas 4K, creo que hay una pila de interrupciones separada (cargada automáticamente gracias a un poco de magia x86), pero no estoy completamente seguro de eso.

Para ser un poco más detallado, aquí hay un ejemplo práctico:

  1. Se produce una interrupción. La CPU cambia a una rutina de trampolín de interrupción, que empuja el número de interrupción a la pila, luego jmps a common_interrupt
  2. common_interrupt llama a do_IRQ , que deshabilita la preferencia y luego maneja la IRQ
  3. En algún momento, se toma la decisión de cambiar de tarea. Esto puede ser desde la interrupción del temporizador o desde una llamada de activación. En cualquier caso, se invoca set_task_need_resched , configurando el indicador de tarea TIF_NEED_RESCHED.
  4. Finalmente, la CPU regresa de do_IRQ en la interrupción original y continúa con la ruta de salida de IRQ. Si se invocó este IRQ desde dentro del kernel, comprueba si TIF_NEED_RESCHED está establecido , y si es así, llama a preempt_schedule_irq , que habilita brevemente las interrupciones mientras realiza una schedule() .
  5. Si se invocó el IRQ desde el espacio de usuario, primero verificamos si hay algo que deba hacer antes de regresar. Si es así, vamos a retint_careful , que comprueba si hay una reprogramación pendiente (e invoca directamente a schedule() si es necesario), así como a la retint_check señales pendientes, y luego regresa por otra ronda en retint_check hasta que no haya más indicadores establecidos.
  6. Finalmente, restauramos GS y regresamos del manejador de interrupciones .

En cuanto a switch_to() ; Lo que hace switch_to() (en x86-32) es:

  1. Guarde los valores actuales de EIP (puntero de instrucción) y ESP (puntero de pila) para cuando volvamos a esta tarea en algún momento posterior.
  2. Cambia el valor de current_task . En este punto, la current ahora apunta a la nueva tarea.
  3. Cambie a la nueva pila, luego presione el EIP guardado por la tarea a la que estamos cambiando en la pila. Más tarde, se realizará una devolución, utilizando este EIP como la dirección de devolución; esta es la forma en que vuelve al código antiguo que anteriormente se llamaba switch_to()
  4. Llame a __switch_to() . En este punto, la current apunta a la nueva tarea, y estamos en la pila de la nueva tarea, pero varios otros estados de la CPU no se han actualizado. __switch_to() maneja cambiar el estado de cosas como la FPU, los descriptores de segmento, los registros de depuración, etc.
  5. Al regresar de __switch_to() , se devuelve la dirección de retorno que switch_to() empujó manualmente en la pila, colocando la ejecución nuevamente donde estaba antes del switch_to() en la nueva tarea. La ejecución ahora se ha reanudado completamente en la tarea conmutada.

x86-64 es muy similar, pero tiene que hacer un poco más de ahorro / restauración de estado debido a los diferentes ABI.

Estoy tratando de entender cómo funciona realmente el proceso de programación en el kernel de Linux. Mi pregunta no es sobre el algoritmo de programación. Se trata de cómo funcionan las funciones schedule() y switch_to() .

Voy a tratar de explicar. Vi eso:

Cuando un proceso se queda sin intervalo de tiempo, la need_resched se establece mediante scheduler_tick() . El kernel comprueba el indicador, ve que está establecido y llama a schedule() (pertinente a la pregunta 1) para cambiar a un nuevo proceso. Este indicador es un mensaje que debe invocarse la programación tan pronto como sea posible porque otro proceso merece ejecutarse. Al regresar al espacio de usuario o regresar de una interrupción, se need_resched indicador need_resched . Si está configurado, el kernel invoca al programador antes de continuar.

Al analizar la fuente del kernel (linux-2.6.10 - versión en la que se basa el libro "Desarrollo del kernel de Linux, segunda edición"), también vi que algunos códigos pueden llamar a la función schedule() voluntariamente, otorgando a otro proceso el derecho a correr. Vi que la función switch_to() es la que realmente hace el cambio de contexto. Busqué en algunos códigos dependientes de la arquitectura, tratando de entender lo que realmente hacía switch_to() .

Ese comportamiento planteó algunas preguntas que no pude encontrar las respuestas para:

  1. Cuando finaliza switch_to() , ¿cuál es el proceso en ejecución actual? El proceso que se llama schedule() ? ¿O el siguiente proceso, el que fue escogido para correr?

  2. Cuando se llama a schedule() por una interrupción, el proceso seleccionado para ejecutarse comienza a ejecutarse cuando finaliza la gestión de interrupciones (después de algún tipo de RTE)? ¿O antes de eso?

  3. Si no se puede llamar a la función schedule() desde una interrupción, ¿cuándo se establece need_resched ?

  4. Cuando el controlador de interrupción del temporizador está funcionando, ¿qué pila se está utilizando?

No sé si podría aclararme. Si no pudiera, espero poder hacer esto después de algunas respuestas (o preguntas). Ya miré varias fuentes tratando de entender ese proceso. Tengo el libro "Linux Kernel Development, sec ed", y lo estoy usando también. Sé un poco sobre MIPs y la arquitectura H8300, si eso ayuda a explicar.