Chapter 4. E/S As�ncrona

Esto deja la caracter�stica perdida - E/S As�ncrona. Normalmente los programas UNIX usan la llamada poll (o su forma variante select) para esperar a que ocurra un evento en uno de los m�ltiples dispositivos de entrada o salida. Este modelo trabaja bien para la mayor�a de las tareas porque las esperas poll y select para un evento no son convenientes para tareas que est�n continuamente haciendo trabajo computacional. Tales programas realmente quieren que el n�cleo les golpee cuando pasa algo en vez de mirar por los eventos.

Poll es semejante a tener una fila de luces delante de t�. Puedes ver en un instante cuales de ellas est�n encendidas. No puedes, de cualquier forma, hacer nada �til mientras las est�s mirando. La E/S as�ncrona usa se�ales que trabajan m�s bien como un timbre. Es vez de mirar, dice que algo se ha manifestado.

La E/S as�ncrona env�a la se�al SIGIO al proceso de usuario cuando ocurre el evento de E/S. En este caso esto significa cuando la gente mueve el rat�n. La se�al SIGIO causa que el proceso de usuario salga a su manejador de se�ales y ejecute el c�digo en ese manejador antes de regresar a lo que estuviera haciendo previamente. Esta es la aplicaci�n equivalente a un manejador de interrupciones.

La mayor parte del c�digo necesitado para esta operaci�n es com�n a todos los usuarios. El n�cleo suministra un conjunto simple de funciones para administrar la E/S as�ncrona.

Nuestro primer trabajo es permitir a los usuarioes establecer E/S as�ncrona en el manejadores de archivos. Para hacer esto necesitamos a�adir una nueva funci�nn a la tabla de operaciones de archivo para nuestro rat�n:


struct file_operations our_mouse_fops = {
        owner: THIS_MODULE
        read:  read_mouse,      /* Puedes leer un rat�n */
        write: write_mouse,     /* Esto no har� mucho */
        poll:  poll_mouse,      /* Encuesta */
        open:  open_mouse,      /* Llamado en open */
        release: close_mouse,   /* Llamado en close */
        fasync: fasync_mouse,   /* E/S as�ncrona */
};
  

Una vez que hemos instalado esta entrada, el n�cleo conoce que soportamos E/S as�ncrona y permitir� todas las operaciones relevantes en el dispositivo. Siempre que un usuario a�ade o quita la notificaci�n de E/S as�ncrona de un manejador de archivos, llama a nuestra rutina fasync_mouse que acabamos de a�adir. Esta rutina usa las funciones de ayuda para mantener actualizada la cola de manejadores:


static struct fasync_struct *mouse_fasync = NULL;

static int fasync_mouse(int fd, struct file *filp, int on)
{
         int retval = fasync_helper(fd, filp, on, &mouse_fasync);

         if (retval < 0)
                 return retval;
        return 0;
}
  

La fasync helper a�ade y borra entradas administrando la lista suministrada. Tambi�n necesitamos quitar entradas de esta lista cuando es cerradi el archivo. Esto requiere a�adir una l�nea a nuestra funci�n close:


static int close_mouse(struct inode *inode, struct file *file)
{
        fasync_mouse(-1, file, 0)
        if(--mouse_users)
                return 0;
        free_irq(OURMOUSE_IRQ, NULL);
        MOD_DEC_USE_COUNT;
        return 0;
}
  

Cuando cerramos el archivo podemos llamar a nuestro propio manejador fasync como si el usuario pidiera que este archivo cesara de ser usado para E/S as�ncrona. Esto aproximadamente limpia cualesquiera finales perdidos. Seguramente no esperamos por la llegada de una se�al para un archivo que no existir� m�s.

En este punto, el controlador del rat�n soporta todas las operaciones de E/S as�ncrona, y las aplicaciones us�ndolas no fallar�n. Estas de todas formas no trabajar�n todav�a. Necesitamos realmente enviar las se�ales. Otra vez el n�cleo suministra una funci�n para manejar esto.

Actualizamos un poco nuestro manejador de interrupciones:


static void ourmouse_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
        char delta_x;
        char delta_y;
        unsigned char new_buttons;

        delta_x = inb(OURMOUSE_BASE);
        delta_y = inb(OURMOUSE_BASE+1);
        new_buttons = inb(OURMOUSE_BASE+2);

        if(delta_x || delta_y || new_buttons != mouse_buttons)
        {
                /* Algo ha pasado */

                spin_lock(&mouse_lock);
                mouse_event = 1;
                mouse_dx += delta_x;
                mouse_dy += delta_y;

                if(mouse_dx < -4096)
                        mouse_dx = -4096;
                if(mouse_dx > 4096)
                        mouse_dx = 4096;

                if(mouse_dy < -4096)
                        mouse_dy = -4096;
                if(mouse_dy > 4096)
                        mouse_dy = 4096;

                mouse_buttons = new_buttons;
                spin_unlock(&mouse_lock);

                /* Ahora hacemos E/S as�ncrona */
                kill_fasync(&mouse_fasync, SIGIO); 
                
                wake_up_interruptible(&mouse_wait);
        }
}
  

El nuevo c�digo simplemente llama a la rutina kill_fasync suminstrada por el n�cleo si la cola no est� vac�a. Esto env�a la se�al requerida (SIGIO en este caso) al proceso que cada manejador de archivo dijo que quer�a ser informado sobre el excitante nuevo movimiento del rat�n que acaba de ocurrir.

Con esto en su sitio y arreglados los fallos en la versi�n original, tienes ahora un controlador de rat�n totalmente funcional usando el protocolo del bus del rat�n. El trabajar� con X window system, trabajar� con GPM y deber�a de trabajar con todas las otras aplicaciones que necesites. Doom es, por supuesto, la forma ideal para probar que tu nuevo controlador de rat�n est� funcionando de forma adecuada. Aseg�rate de probarlo de todas las formas posibles.