- ¿Cuál es la diferencia entre la pila del kernel y la pila del usuario?
En resumen, nada, aparte de usar una ubicación diferente en la memoria (y, por lo tanto, un valor diferente para el registro de puntero de pila) y, por lo general, diferentes protecciones de acceso a la memoria. Es decir, cuando se ejecuta en modo de usuario, la memoria del kernel (parte de la cual es la pila del kernel) no será accesible incluso si está mapeada. Viceversa, sin ser solicitado explícitamente por el código del kernel (en Linux, a través de funciones como copy_from_user()
), la memoria del usuario (incluida la pila de usuarios) no suele ser directamente accesible.
- ¿Por qué se usa [una pila de kernel separada]?
Separación de privilegios y seguridad. Por un lado, los programas del espacio de usuario pueden hacer que su pila (puntero) sea lo que quieran y, por lo general, no hay ningún requisito arquitectónico para tener uno válido. Por lo tanto, el kernel no puede confiar en que el stackpointer del espacio de usuario sea válido o utilizable y, por lo tanto, requerirá un conjunto bajo su propio control. Las diferentes arquitecturas de CPU implementan esto de diferentes maneras; Las CPU x86 cambian automáticamente los punteros de pila cuando ocurren los cambios de modo de privilegio, y los valores que se utilizarán para los diferentes niveles de privilegio se pueden configurar mediante código privilegiado (es decir, solo el kernel).
- Si se declara una variable local en un ISR, ¿dónde se almacenará?
En la pila de kernel. El kernel (es decir, el kernel de Linux) no engancha los ISR directamente a las puertas de interrupción de la arquitectura x86, sino que delega el envío de interrupciones a un mecanismo común de entrada / salida de interrupciones del kernel que guarda el estado de registro previo a la interrupción antes de llamar a los controladores registrados . La CPU misma al enviar una interrupción puede ejecutar un privilegio y / o cambio de pila, y esto es usado / configurado por el kernel para que el código de entrada de interrupción común ya pueda depender de una pila del kernel presente.
Dicho esto, las interrupciones que ocurren mientras se ejecuta el código del kernel simplemente (continuarán) usarán la pila del kernel en su lugar en ese momento. Esto puede, si los manejadores de interrupciones tienen rutas de llamadas profundamente anidadas, provocar desbordamientos de pila (si se interrumpe una ruta de llamada profunda del kernel y el manejador causa otra ruta profunda; en Linux, el código RAID del sistema de archivos / software es interrumpido por el código de red con iptables activo es conocido por desencadenarlo en kernels antiguos no optimizados ... la solución es aumentar el tamaño de la pila del kernel para tales cargas de trabajo).
- ¿Cada proceso tiene su propia pila de kernel?
No solo cada proceso, cada hilo tiene su propia pila de kernel (y, de hecho, también su propia pila de usuario). Recuerde que la única diferencia entre procesos y subprocesos (para Linux) es el hecho de que varios subprocesos pueden compartir un espacio de direcciones (formando un proceso).
- ¿Cómo se coordina el proceso entre ambas pilas?
En absoluto, no es necesario. La programación (cómo / cuándo se ejecutan diferentes subprocesos, cómo se guarda y se restaura su estado) es la tarea del sistema operativo y los procesos no necesitan preocuparse por esto. A medida que se crean los subprocesos (y cada proceso debe tener al menos un subproceso), el kernel crea pilas de kernel para ellos, mientras que las pilas de espacio de usuario se crean / proporcionan explícitamente mediante cualquier mecanismo que se utilice para crear un subproceso (funciones como makecontext()
o pthread_create()
permiten que el llamador especificar una región de memoria que se utilizará para la pila de subprocesos "secundarios"), o heredada (mediante clonación de memoria en el acceso, generalmente llamada "copia en escritura" / COW, cuando se crea un nuevo proceso).
Dicho eso(estado, entre eso está el puntero de pila del hilo). Hay varias formas para esto: las señales de UNIX, setcontext()
, pthread_yield()
/ pthread_cancel()
, ... - pero esto es disgressing un poco de la pregunta original.
Mi respuesta se recopila de otras preguntas SO con mis productos.
Como programador del núcleo, sabe que el núcleo debe estar restringido a programas de usuario erróneos. Suponga que mantiene la misma pila tanto para el kernel como para el espacio de usuario, luego una simple falla de segmentación en la aplicación del usuario bloquea el kernel y necesita reiniciarse.
Hay una "pila de kernel" por CPU como ISR Stack y una "pila de kernel" por proceso. Hay una "pila de usuarios" para cada proceso, aunque cada subproceso tiene su propia pila, incluidos los subprocesos de usuario y del kernel.
http://linux.derkeiler.com/Mailing-Lists/Kernel/2004-10/3194.html
Entonces, cuando estamos en modo kernel, es necesario un tipo de mecanismo de pila para tratar con llamadas a funciones, variables locales similares al espacio de usuario.
http://www.kernel.org/doc/Documentation/x86/kernel-stacks
Se almacenará en la pila ISR (IRQSTACKSIZE). El ISR se ejecuta en una pila de interrupciones separada solo si el hardware lo admite. De lo contrario, los marcos de la pila ISR se insertan en la pila del hilo interrumpido.
El espacio de usuario no sabe y, francamente, no le importa si la interrupción se sirve en la pila del núcleo del proceso actual o en una pila ISR separada. Como las interrupciones vienen por cpu, la pila de ISR debe ser por cpu.
Si. Cada proceso tiene su propia pila de kernel.
La respuesta de @ FrankH me parece genial.
fuente
Tomando como referencia el desarrollo del kernel de Linux de Robert Love, la principal diferencia es el tamaño:
Además, la pila del kernel contiene un puntero a la estructura thread_info que contiene información sobre el hilo.
fuente