Análisis del principio del mecanismo de la cola de espera del kernel de Linux

  
1.
Estructura de datos de la cola de espera

La cola de espera se implementa mediante una lista con un enlace doble cuyos elementos incluyen punteros para procesar los descriptores. Cada cola de espera tiene una cabecera de cola de espera, que es una estructura de datos de tipo wait_queque_head_t:
struct __wait_queue_head {
spinlock_t lock;
struct list_head task_list;
};
typedef struct __wait_queue_head wait_queue_head_t;
donde se usa el bloqueo para evitar el acceso simultáneo, y el campo task_list es el encabezado de la lista de espera.
colas de tipo de elemento en espera de la lista wait_queue_t, podemos llamar a esperar entrada de cola:
struct {__wait_queue
banderas unsigned int;
#define WQ_FLAG_EXCLUSIVE 0x01
void * Privado;
wait_queue_func_t func;
struct list_head task_list;
};
typedef struct __wait_queue wait_queue_t;
Cada elemento de la cola de espera representa un proceso de suspensión que espera a que ocurra un evento. Su dirección del descriptor se coloca generalmente en el campo privado. El campo Lista de tareas contiene un puntero que vincula un elemento a la lista de procesos que espera el mismo evento.
El campo de función del elemento de la cola de espera se utiliza para indicar cómo debe despertarse el proceso de suspensión en la cola de espera (mutuamente excluyentes y no mutuamente).
toda
estructura de cola como se muestra a continuación:
Ver abajo la cola de espera funciona. .
2
durante la cola de sueño antes de la cola de espera
normalmente se utiliza para definir una cabecera de la cola de espera: WQ wait_queue_head_t estática, y luego llama a la función wait_event_ * El proceso actual en espera de una condición de condición se inserta en la cola de espera wq y duerme, y espera hasta que se cumpla la condición de condición, y el kernel se activa un cierto proceso o todos los procesos durmiendo en la cola de espera wq.
definición de cabecera de la cola de espera nada de que hablar, a raíz de las llamadas de wait_event_ * análisis inicio: Read Aquí damos la wait_event_interruptible más comunes:
/** *
wait_event_interruptible - el sueño hasta que una condición Obtiene verdadero
* @wq: la cola de espera para esperar en * * condición: una expresión en C para que el evento espere
*
* El proceso se pone en suspensión (TASK_INTERRUPTIBLE) hasta que << Br> * @condition se evalúa como verdadero o se recibe una señal.
* La condición @ se comprueba cada vez que se despierta la cola de espera @wq.
*
* Se debe llamar a wake_up () después de cambiar Cualquier variable que pueda
* cambiar el resultado de la condición de espera.
*
* La función devolverá -ERESTARTSYS si fue interrumpida por una señal de * * y 0 si @condition se evaluó como verdadera.
* /
#define wait_event_interruptible (wq, condition) \\
({\\
int __ret = 0; \\
if (! (condition)) \\
__wait_event_interruptible (wq, Condición, __ret); \\
__ret; \\
})
Esto es muy simple, juzgue la condición Si está satisfecho, si no está satisfecho, llame a la función __wait_event_interruptible.
#define __wait_event_interruptible (WQ, condición, ret) \\
do {\\
DEFINE_WAIT (__ espera); \\
\\ Opiniones de (;;) {\\
Prepare_To_Wait (&wq, &__ espera, TASK_INTERRUPTIBLE); \\
if (condición) \\
break; \\
if (! signal_pending (current)) {\\
schedule (); \\
continue; \\
} \\
ret = -ERESTARTSYS; \\
break; \\
} \\
finish_wait (&wq, &__ wait); \\
} while ( 0)
__wait_event_interruptible wait_queue_t primero define un tipo de cola de entradas __wait:
#define DEFINE_WAIT (nombre) \\
wait_queue_t name = {\\
.private = corriente, \\ < Br> .func = autoremove_wake_function, \\
.task_list = LIST_HEAD_INIT ((name) .task_list), \\
}
Puede encontrar el miembro privado de __wait (generalmente se usa para almacenar el descriptor de proceso) Se ha inicializado a actual, lo que indica que la entrada de la cola de espera corresponde al proceso actual. El miembro de la función es la función de activación correspondiente a la entrada de la cola de espera. Una vez que el proceso se ha activado, se ejecutará y se habrá inicializado a la función predeterminada autoremove_wake_function.
Prepare_To_Wait continuación, llama a la función en un for (;;) ciclo:
anular fastcall Prepare_To_Wait (wait_queue_head_t * q, wait_queue_t * espera, estatales int)
{banderas largas
sin firmar; < Br>
wait- > flags &= ~ WQ_FLAG_EXCLUSIVE;
spin_lock_irqsave (&q- > lock, flags);
if (list_empty (&wait- > task_list))
__ add_wait_queue (q, wait);
/*
* no altera el estado de la tarea si solo va a ir a la cola de espera * * una devolución de llamada de cola de espera asíncrona
* /
if ( Is_sync_wait (espera))
set_current_state (estado);
spin_unlock_irqrestore (&q- > lock, flags);
}
prepare_to_wait hace dos cosas, será la entrada de cola de espera definida previamente __wait se inserta en el encabezado de la cola de espera wq, y luego el proceso actual se establece en el estado TASK_INTERRUPTIBLE. Después de que se ejecuta el preparation_to_wait, compruebe si se cumple la condición. Si se cumple en este momento, no es necesario dormir. Si no te has conocido, estás listo para dormir.
sueño se hace llamando a la función de programación (), como ya se ha establecido en el estado TASK_INTERRUPTIBLE proceso actual, por lo tanto aquí a continuación, ejecutar schedule (), y luego llevar a cabo el proceso de cambio, y entonces nunca será enviado de nuevo al proceso de Se ejecuta hasta que el proceso se reactiva (es decir, se cambia al estado TASK_RUNNING).
Esto determinará si hay alguna señal antes de ejecutar el proceso de cambio de programación (). Si lo hay, devolverá ERESTARTSYS inmediatamente. Si no, ejecute el programa () para dormir.
para (;;) efecto de bucle es permitir que el proceso para ser despertado una vez más para comprobar si se cumple la condición. El motivo principal es evitar que los procesos múltiples en la cola de espera se activen al mismo tiempo. Es posible que otros procesos hayan adelantado los recursos para ocupar los recursos en el pasado y no estén disponibles. Por lo tanto, es mejor juzgar.
(Por supuesto, el núcleo también ofrece un despertador sólo uno o más procesos (espera exclusiva para el proceso) la forma, está interesado puede referirse a la información pertinente)
proceso se despierta después del último paso es llamar finish_wait (&WQ, La función &__ wait) realiza la limpieza. Finish_wait establece el estado del proceso en TASK_RUNNING de nuevo y elimina el proceso de la cola de espera.
vacío fastcall finish_wait (wait_queue_head_t * q, wait_queue_t * espera)
{
sin firmar banderas largas;
__set_current_state (TASK_RUNNING);
si (list_empty_careful (& !; espera- > task_list)) {
spin_lock_irqsave (&q- > de bloqueo, banderas);
list_del_init (&espera- > task_list);
spin_unlock_irqrestore (&q- > de bloqueo , banderas);
}}

nuevo
se devuelve después de su wait_event_interruptible llamada anterior (WQ, condición) está bloqueado en su lugar de continuar hacia abajo.
Copyright © Conocimiento de Windows All Rights Reserved