x86 - operativos - multihilos pdf
¿De qué manera SMT multihilo comparte memoria e interrumpe? (3)
Estoy trabajando en los búferes de entrada para mi kernel, y tenía algunas preguntas. En máquinas Dual Core, sé que más de un "proceso" puede ejecutarse simultáneamente. Lo que no sé es cómo funcionan el sistema operativo y los programas individuales para proteger las colisiones en los datos.
Hay dos cosas que me gustaría saber sobre este tema:
(1) ¿Dónde ocurren las interrupciones? ¿Se garantiza que ocurran en un núcleo y no en el otro, y podría usarse para asegurarse de que las operaciones en tiempo real en un núcleo no fueran interrumpidas por, por ejemplo, un archivo IO que podría manejarse en el otro núcleo? (Lógicamente asumiría que las interrupciones ocurrirían en el 1er núcleo, pero ¿es eso cierto, y cómo lo diría? ¿O quizás cada núcleo tiene su propia configuración para las interrupciones? ¿No sería eso un escenario en el que cada uno núcleo podría reaccionar simultáneamente a la misma interrupción, posiblemente de diferentes maneras?)
(2) ¿Cómo maneja el procesador de doble núcleo la colisión de la memoria del código de operación? Si un núcleo está leyendo una dirección en la memoria exactamente al mismo tiempo que otro núcleo está escribiendo en la misma dirección en la memoria, ¿qué ocurre? ¿Se lanza una excepción o se lee un valor? (Asumo que la escritura funcionaría de cualquier manera.) Si se lee un valor, ¿se garantiza que sea el valor anterior o el nuevo en el momento de la colisión?
Entiendo que lo ideal sería que los programas se escriban para evitar este tipo de complicaciones, pero el sistema operativo ciertamente no puede esperar eso, y deberá ser capaz de manejar dichos eventos sin ahogarse.
En procesadores x86, esto es manejado por el APIC. Puede ver detalles en el Manual del desarrollador de software Intel® 64 e IA-32 Architectures , específicamente en el volumen 3 , capítulo 9 y en la especificación x2APIC .
Solo daré un resumen rápido en caso de que no quiera entrar en todos los detalles.
Las interrupciones pueden provenir de tres fuentes diferentes:
- Pines externos (en los procesadores Intel hasta Core i7 tiene LINT0, LINT1, SMI, INIT. No sé cómo se llaman en los procesadores Core i7 o AMD o Vía).
- Transacciones de autobús. Esta es la forma principal en que un hilo envía una interrupción a otro hilo en un sistema moderno. Se los conoce como IPI. I nter- P rocessor I nterrupts.
- Eventos internos, como interrupciones térmicas, monitores de eventos o errores internos.
Cada procesador lógico (subproceso en un sistema SMT, núcleo en un sistema multi-core no SMT, procesador en un sistema no SMT no multi-núcleo) tiene un APIC. El APIC controla cómo responde el procesador lógico a tales interrupciones.
En breve:
Los pines SMI e INIT siempre se enrutan a SMI o INIT, respectivamente.
Si el APIC está deshabilitado, LINT0 se enruta a INTR, LINT1 se enruta a NMI y los IPI se ignoran.
Si está habilitado:
- LINT0, LINT1, eventos térmicos, monitores de eventos y errores tienen cada uno una entrada en el LVT ( L ogical V ector T able) que especifica si está enmascarado o no, y si no, qué tipo de interrupción será.
- Los IPI se manejan. Los IPI incluyen el tipo de interrupción (es decir, INTR, SMI, NMI, INIT, SIPI) y el destino. Cada procesador lógico tiene una APIC-ID, que es. Si el destino del IPI coincide con su ID, maneja la interrupción. De lo contrario, lo ignora.
Si desea información sobre cómo habilitar el APIC, programar el LVT, configurar el APIC-ID y enviar IPI, tendrá que consultar los manuales a los que he vinculado.
El sistema operativo se configura donde se manejan las interrupciones. Linux carga el balanceo de las interrupciones, para que puedan ser manejadas por ambas CPU. Cada controlador de interrupción necesita adquirir un bloqueo, para evitar ejecuciones simultáneas del mismo controlador en una CPU diferente, pero también para protegerse de otro código kernel que se ejecuta en un contexto sin interrupción y acceder a las mismas estructuras de datos. Sin embargo, creo que uno puede vincular la ejecución de una interrupción dada en una CPU determinada.
Acerca de la pregunta (2): las garantías son básicamente las mismas que las dadas por una máquina SMP, es decir, no se lanza ninguna excepción, y el resultado depende de quién consigue ejecutar / confirmar el valor en la memoria / comprometer primero el valor de la memoria caché compartida. De todos modos, no puede confiar en el valor leído, de hecho, las garantías otorgadas son mucho menos fuertes de lo que esperaba.
Busque en Internet (en Google o Wikipedia) sobre qué es una carrera de datos, y comience estudiando cómo escribir código multiproceso correctamente en Java. Estudiar eso me hizo mucho más fácil comprender los mecanismos de concurrencia del kernel de Linux.
O simplemente diríjase a las preguntas frecuentes sobre el modelo de memoria C / C ++ casi "oficial" , para Documentation / memory-barriers.txt del árbol fuente del kernel de Linux, o para la publicación de Jeremy Manson sobre el tema . De todos modos, me olvidé de señalar que el valor que lees no ha sido necesariamente escrito por algún procesador. Para valores de 32 bits, esto está garantizado por el hecho de que una escritura de 32 bits es atómica. Para los valores de 64 bits, esto no suele ser cierto (no estoy seguro de las plataformas de 64 bits, pero debido a razones de portabilidad, generalmente no confío en ellas).
En cualquier caso, si te haces esa pregunta, probablemente deberías mejorar el bloqueo utilizado por tu código. Trabajando en kernel, primero necesita escribir su propia biblioteca spinlock / semáforo para arreglar esto.
Cuando dice "su núcleo", no está claro a qué se refiere, pero creo que es poco probable que realmente signifique "un kernel que estoy escribiendo". De todos modos, no dejaré que nadie haga la pregunta (2) para ejecutar programas multiproceso en mi máquina :-).
Entiendo que lo ideal sería que los programas se escriban para evitar este tipo de complicaciones, pero el sistema operativo ciertamente no puede esperar eso, y deberá ser capaz de manejar dichos eventos sin ahogarse.
La respuesta a esa pregunta es algo que debe saber para escribir también programas multiproceso de espacio de usuario. Bueno, no necesitas saber la respuesta exacta a "qué valor lees", sino que simplemente porque no puedes confiar en eso, está definido por la implementación incluso si escribes el código de ensamblaje para un procesador específico. Simplemente porque no puede confiar en la velocidad relativa de dos hilos paralelos. Nunca.
El manual de referencia IA-32 responderá sus preguntas de manera definitiva.
Mi intuición es que ambos núcleos interrumpen, y el sistema operativo los soluciona. Probablemente exista un registro de configuración en cada núcleo que especifique qué núcleo obtiene qué interrupción.
Colisión. Sin garantía. Para ser más precisos, fíjate en los mecanismos de caché y cómo clasifican la coherencia.
Para otros hilos relacionados con esto:
¿Cómo funcionan las interrupciones en máquinas multinúcleo / multicpu?