update nucleo descargar compilar como linux-kernel

linux-kernel - nucleo - linux kernel version



¿Por qué el código/subproceso del kernel que se ejecuta en el contexto de interrupción no puede dormir? (11)

Entonces, ¿qué impide que scehduler ponga en pausa el contexto de interrupción y tome el siguiente proceso programable y le pase el control?

El problema es que el contexto de interrupción no es un proceso y, por lo tanto, no se puede poner en suspensión.

Cuando ocurre una interrupción, el procesador guarda los registros en la pila y salta al inicio de la rutina de servicio de interrupción. Esto significa que cuando el controlador de interrupciones se está ejecutando, se está ejecutando en el contexto del proceso que se estaba ejecutando cuando ocurrió la interrupción. La interrupción se está ejecutando en la pila de ese proceso, y cuando el controlador de interrupciones se completa, ese proceso continuará ejecutándose.

Si intentara dormir o bloquear dentro de un controlador de interrupciones, terminaría no solo deteniendo el controlador de interrupciones, sino también el proceso que interrumpió. Esto podría ser peligroso, ya que el controlador de interrupciones no tiene forma de saber qué estaba haciendo el proceso interrumpido, o incluso si es seguro que ese proceso se suspenda.

Un escenario simple donde las cosas podrían salir mal sería un punto muerto entre el manejador de interrupciones y el proceso que interrumpe.

  1. Process1 entra en modo kernel.
  2. Process1 adquiere LockA .
  3. Se produce la interrupción.
  4. ISR comienza a ejecutarse utilizando la pila de Process1 .
  5. ISR intenta adquirir LockA .
  6. ISR llama a sleep para esperar a que LockA sea ​​liberado.

En este punto, tienes un punto muerto. Process1 no puede reanudar la ejecución hasta que el ISR haya terminado con su pila. Pero el ISR está bloqueado a la espera de que Process1 libere LockA .

Estoy leyendo el siguiente artículo de Robert Love

http://www.linuxjournal.com/article/6916

que dice

"... Discutamos el hecho de que las colas de trabajo se ejecutan en un contexto de proceso. Esto contrasta con los otros mecanismos de la mitad inferior, que se ejecutan en un contexto de interrupción. El código que se ejecuta en un contexto de interrupción no se puede suspender, o bloquear, porque el contexto no tiene un proceso de respaldo con el que reprogramar. Por lo tanto, como los controladores de interrupción no están asociados con un proceso, no hay nada que el programador pueda poner en suspensión y, lo que es más importante, no hay nada que pueda activar el programador ... "

No lo entiendo AFAIK, el programador en el kernel es O (1), que se implementa a través del mapa de bits. Entonces, ¿qué impide que scehduler ponga en pausa el contexto de interrupción y tome el siguiente proceso programable y le pase el control?


Entonces, ¿qué impide que scehduler ponga en pausa el contexto de interrupción y tome el siguiente proceso programable y le pase el control?

La programación ocurre en las interrupciones del temporizador. La regla básica es que solo se puede abrir una interrupción a la vez, por lo que si va a dormir en la interrupción de "datos obtenidos del dispositivo X", la interrupción del temporizador no se puede ejecutar para programarla.

Las interrupciones también ocurren muchas veces y se superponen. Si pone la interrupción de "datos conseguidos" en suspensión y luego obtiene más datos, ¿qué sucede? Es tan confuso (y frágil) que la regla general es: no dormir en interrupciones. Lo harás mal.


Creo que es una idea de diseño.

Claro, puede diseñar un sistema que pueda dormir en modo interrumpido, pero excepto para hacer que el sistema sea difícil de comprender y complicado (hay muchas situaciones que debe tener en cuenta), eso no ayuda en nada. Por lo tanto, desde una vista de diseño, declarar el controlador de interrupciones ya que no se puede dormir es muy claro y fácil de implementar.

De Robert Love (un hacker del kernel): http://permalink.gmane.org/gmane.linux.kernel.kernelnewbies/1791

No puede dormir en un controlador de interrupciones porque las interrupciones no tienen un contexto de proceso de respaldo y, por lo tanto, no hay nada que reprogramar. En otras palabras, los controladores de interrupción no están asociados con una tarea, por lo que no hay nada que "ponga en reposo" y (lo que es más importante) "nada que despertar". Deben correr atómicamente.

Esto no es diferente a otros sistemas operativos. En la mayoría de los sistemas operativos, las interrupciones no se enlazan. Sin embargo, las mitades inferiores a menudo lo son.

El motivo por el que el controlador de errores de página puede estar inactivo es que solo lo invoca el código que se ejecuta en el contexto del proceso. Debido a que la propia memoria del kernel no es paginable, solo los accesos a la memoria del espacio de usuario pueden dar como resultado un error de página. Por lo tanto, solo algunos lugares determinados (como las llamadas a copy_ {to, from} _user ()) pueden causar un error de página dentro del kernel. Esos lugares deben estar todos hechos por código que pueda dormir (es decir, contexto de proceso, sin bloqueos, etc.).


Debido a que la infraestructura de conmutación de hilos es inutilizable en ese punto. Cuando se atiende una interrupción, solo se pueden ejecutar cosas de mayor prioridad: consulte el Manual del desarrollador de software Intel sobre la prioridad de interrupción, tarea y procesador . Si permitiera que se ejecutara otro subproceso (lo que implica en su pregunta que sería fácil de hacer), no sería capaz de dejar que hiciera nada. Si causara un error en la página, tendría que usar los servicios. en el kernel que no se pueden utilizar mientras se atiende la interrupción (vea más abajo por qué).

Por lo general, su único objetivo en una rutina de interrupción es hacer que el dispositivo deje de interrumpir y poner en cola algo en un nivel de interrupción más bajo (en unix, esto suele ser un nivel sin interrupción, pero para Windows, es el nivel de envío, apc o pasivo) haga el trabajo pesado en el que tenga acceso a más características del kernel / os. Ver - Implementando un manejador .

Es una propiedad de cómo deben funcionar los O / S, no algo inherente a Linux. Una rutina de interrupción puede ejecutarse en cualquier momento, por lo que el estado de lo que interrumpió es inconsistente. Si interrumpió el código de programación de hilos, su estado es inconsistente, por lo que no puede estar seguro de que puede "dormir" y cambiar de hilos. Incluso si protege el código de cambio de subprocesos para que no se interrumpa, el cambio de subprocesos es una característica de muy alto nivel de la O / S y si protege todo en lo que se basa, una interrupción se convierte en una sugerencia más que en el imperativo que implica su nombre.


Deshabilitar un controlador de interrupciones para bloquear es una opción de diseño. Cuando algunos datos están en el dispositivo, el controlador de interrupciones intercepta el proceso actual, prepara la transferencia de los datos y habilita la interrupción; Antes de que el controlador habilite la interrupción actual, el dispositivo debe colgarse. Queremos mantener nuestra E / S ocupada y nuestro sistema receptivo, entonces es mejor que no bloqueemos el controlador de interrupciones.

No creo que los "estados inestables" sean una razón esencial. Los procesos, sin importar que estén en modo usuario o modo kernel, deben ser conscientes de que pueden ser interrumpidos por interrupciones. Si tanto el controlador de interrupciones como el proceso actual accedan a una estructura de datos en modo kernel, y existe una condición de carrera, entonces el proceso actual debería deshabilitar las interrupciones locales y, además, para arquitecturas con múltiples procesadores, los bloqueos de giro deberían utilizarse durante las secciones críticas. .

Tampoco creo que si el controlador de interrupciones estuviera bloqueado, no se pueda activar. Cuando decimos "bloque", básicamente significa que el proceso bloqueado está esperando algún evento / recurso, por lo que se enlaza con alguna cola de espera para ese evento / recurso. Cada vez que se libera el recurso, el proceso de liberación es responsable de despertar los procesos de espera.

Sin embargo, lo realmente molesto es que el proceso bloqueado no puede hacer nada durante el tiempo de bloqueo; No hizo nada malo por este castigo, que es injusto. Y nadie podría predecir el tiempo de bloqueo, por lo que el proceso inocente tiene que esperar por una razón poco clara y por un tiempo ilimitado.


El kernel de Linux tiene dos formas de asignar la pila de interrupciones. Uno está en la pila de kernel del proceso interrumpido, el otro es una pila de interrupción dedicada por CPU. Si el contexto de interrupción se guarda en la pila de interrupciones dedicada por CPU, entonces el contexto de interrupción no está completamente asociado con ningún proceso. La macro "actual" producirá un puntero no válido al proceso en ejecución actual, ya que la macro "actual" con alguna arquitectura se computa con el puntero de pila. El puntero de pila en el contexto de interrupción puede apuntar a la pila de interrupción dedicada, no a la pila de kernel de algún proceso.


Es solo una elección de diseño / implementación en Linux OS. La ventaja de este diseño es simple, pero puede no ser bueno para los requisitos del sistema operativo en tiempo real.

Otros sistemas operativos tienen otros diseños / implementaciones.

Por ejemplo, en Solaris, las interrupciones pueden tener diferentes prioridades, lo que permite que la mayoría de las interrupciones de dispositivos se invocan en subprocesos de interrupción. Los subprocesos de interrupción permiten la suspensión porque cada uno de los subprocesos de interrupción tiene una pila separada en el contexto del subproceso. El diseño de subprocesos de interrupción es bueno para los subprocesos en tiempo real que deberían tener prioridades más altas que las interrupciones.


Incluso si pudieras poner un ISR a dormir, no querrías hacerlo. Desea que sus ISR sean lo más rápido posible para reducir el riesgo de perder interrupciones posteriores.


Los controladores de interrupciones de alto nivel enmascaran las operaciones de todas las interrupciones de prioridad más baja, incluidas las de la interrupción del temporizador del sistema. En consecuencia, el manejador de interrupciones debe evitar involucrarse en una actividad que pueda hacer que se duerma. Si el manejador duerme, entonces el sistema puede bloquearse porque el temporizador está enmascarado e incapaz de programar el hilo durmiente. ¿Esto tiene sentido?


Por naturaleza, la pregunta es si en el controlador de interrupciones puede obtener un "actual" válido (direccionado al proceso actual task_structure), si es así, es posible modificar el contenido en consecuencia para convertirlo en el estado de "suspensión", que volver por el programador más tarde si el estado se cambia de alguna manera. La respuesta puede depender del hardware.

Pero en ARM, es imposible ya que ''actual'' es irrelevante para procesar en modo de interrupción. Vea el código a continuación:

#linux/arch/arm/include/asm/thread_info.h 94 static inline struct thread_info *current_thread_info(void) 95 { 96 register unsigned long sp asm ("sp"); 97 return (struct thread_info *)(sp & ~(THREAD_SIZE - 1)); 98 }

sp en modo USUARIO y modo SVC son "iguales" ("mismo" aquí no significa que sean iguales, en cambio, el punto sp del modo de usuario a la pila de espacio de usuario, mientras que el punto r rc_svc de svc modo apunta a la pila del núcleo, donde el proceso del usuario task_structure se actualizó en el cambio de tarea anterior. Cuando se produce una llamada al sistema, el proceso ingresa nuevamente en el espacio del kernel, cuando el sp (sp_svc) aún no se modifica, estos 2 sp están asociados entre sí, en este sentido, son los mismos. ''), Así que en el modo SVC, el código del kernel puede obtener el'' actual ''válido. Pero bajo otros modos privilegiados, digamos el modo de interrupción, sp es ''diferente'', apunta a la dirección dedicada definida en cpu_init (). La "corriente" calculada en este modo será irrelevante para el proceso interrumpido, ya que acceder a él resultará en comportamientos inesperados. Por eso siempre se dice que la llamada al sistema puede estar inactiva, pero el controlador de interrupciones no puede, la llamada al sistema funciona en el contexto del proceso, pero no la interrupción.


Si una rutina de interrupción de nivel superior llega al punto donde lo siguiente que debe hacer tiene que suceder después de un período de tiempo, entonces debe colocar una solicitud en la cola del temporizador, pidiendo que se ejecute otra rutina de interrupción (con menor prioridad nivel) algún tiempo después.

Cuando esa rutina de interrupción se ejecuta, eleva el nivel de prioridad al nivel de la rutina de interrupción original y continúa la ejecución. Esto tiene el mismo efecto que un sueño.