gestion de interrupciones
|
|
Por ridiculum
departamento toc toc, hay alguien? , Sección Diarios Puesto a las Sun May 8th, 2005 at 08:33:53 PM CET
|
 |
Primero de todo, dar las gracias por las ideas del post sobre continuidad. Ahora mismo el tema esta medio resuelto mirando cuantos puntos de esta operacion: x[n+1]-x[n] son cero. Si supera un umbral, es salto, sino, es rampa. Por ahora funciona bien, incluso en condiciones de ruido, pero vamos, se que no es la mejor solucion y debe haber otra.
Por cierto, en tiempo discreto se puede derviar, o al menos, en un principio se puede diseñar un sistema que derive, aunque no lo he probado aun. Luego lo cuento, que sino, no me centro.
Y ahora, al tema de esta entrada
|
Hace unos dias, A. Cox respondia a un correo en la lkml que opinaba que tenia un hardware con un fallo de diseño, ya que tenia las interrupciones por nivel, een lugar de por flanco. A. Cox decia algo asi a: "pero tio, si las interrupciones por nivel son lo mejor del mundo".
Yo he tenido que lidiar con interrupciones y ademas, por nivel, y aun me surge una duda, que posiblemente, en Linux este restuelta, pero en el contexto en el que yo estaba creo que no lo esta. El tema es el siguiente.
Las interrupciones se ejecutan en un contexto especial desde donde no se suele poder realizar ciertas operaciones, como un delay(), usar semaforos, o usar un printk o equivalente. Por eso (y otros motivos) es normal separalas en dos partes, una que se ejecuta en el contexto de interrupcion, y otro que se ejecuta en un contexto de proceso que en terminologia unix se ha llamado tradicionalmente bottom-half.
Una vez hecha esta ligera y necesaria introduccion para situar al personal en escena, veamos un esbozo del asunto. Adelanto que los nombres que voy a usar no existen (que yo sepa) en ningun SO, y solo prentender dar una idea.
void Interrupt8()
{
wake_up(pid)
}
void bottom_half()
{
while(1)
{
sleep();
value16=read_hardware(reg16)
if (value16 ==0x0800)
{
value32=read_hardware(reg32);
if (value32 == 1)
do_something1();
}
erase_irq()
}
}
Bueno, la idea es que Interrupt8() es el manejador, que se instalara con la pertienente funcion que nos ofrezca la plataforma. Con wake_up(pid) despertamos al proceso/tarea que tiene como identificador 'pid'. Bottom_half() es precisamente eso y se ejecutara cuando se arranque la tipica funcion de inicializacion del hardware. Para efectos del ejemplo, podemos suponer que es un proceso/tarea/llamalo_como_quieras. Tiene un bucle infinito y la funcion sleep() que manda a dormir a este proceso. read_hardware accede al hardware que ha generado la irq y erase_irq lo que hace es volver a habilitar las interrupciones. Esto es asi, por que en las irq por nivel, es necesario volver a levantar la linea para que nos puedan volver a interrupir.
El meollo del asunto es el tiempo que transcurre entre la ultima instruccion de erase_irq(), donde ya nos pueden interrumpir, y la finalizacion de sleep(), donde ya estamos dormidos y nos pueden despertar.
Que sucede si en ese fragmento de tiempo, que aunque es muy pequeño no es nulo, nos interrumpen?. Pues la secuencia seria algo asi a:
- el hardware se entera del evento,
- se lo pasa al SO,
- el saca de la CPU a lo que se este ejecutando (supongamos que es la primera instruccion de sleep() ),
- el SO llama a Interrupt8,
- Interrup8 intenta despertar al bottom_half y se termina todo.
Como el bottom_half no esta dormido, el intento de despertarlo queda en el limbo, y despues de eso, el SO le vuelve a dar la CPU para que se continue ejecutando, y ahora si termina de dormirse.
La situacion en la que nos hemos quedado es bastante comprometida: hemos perdido una interupcion, y la linea de irq se ha quedado a nivel bajo para siempre, con lo que el dispositivo que esta unido a esa linea no nos va a poder interrumpir nunca jamas. Hemos perdido la comunicacion con ese hardware.
Estoy seguro que este problema tiene solucion, pero no se cual sera, o al menos no se como escribirla. Posiblemente todo el problema venga del hecho de no ejecutar la gestion de interrupciones dentro del nucleo, pero tampoco estoy seguro. Los kernels monoliticos lo hacen asi, y los microkernels, al menos la primera parte de la gestion de irq, tambien es asi. Le he echando un vistazo rapido a la documentacion de QNX y no he salido de dudas. |
|
|