2012-07-04 8 views
12

Uno de los controladores del núcleo de Linux que estoy desarrollando es el uso de la comunicación en red en el kernel (sock_create(), sock->ops->bind(), y así sucesivamente).efecto Simulación de select() y poll() en el núcleo de la programación del zócalo

El problema es que habrá varios sockets para recibir los datos. Entonces necesito algo que simule un select() o poll() en el espacio del kernel. Dado que estas funciones usan descriptores de archivos, no puedo usar las llamadas al sistema a menos que use las llamadas al sistema para crear los sockets, pero eso parece innecesario ya que estoy trabajando en el kernel.

Así que estaba pensando en envolver el controlador predeterminado sock->sk_data_ready en mi propio controlador (custom_sk_data_ready()), que desbloquearía un semáforo. Luego puedo escribir mi propia función kernel_select() que intenta bloquear el semáforo y hace un bloqueo de espera hasta que esté abierto. De esta forma, la función kernel queda en reposo hasta que el semáforo se desbloquea al custom_sk_data_ready(). Una vez que kernel_select() obtiene el bloqueo, se desbloquea y llama al custom_sk_data_ready() para volverlo a bloquear. Por lo tanto, la única inicialización adicional es ejecutar custom_sk_data_ready() antes de vincular un socket, por lo que la primera llamada a custom_select() no se activa de manera falsa.

veo un posible problema. Si ocurre una recepción múltiple, múltiples llamadas al custom_sk_data_ready() intentarán desbloquear el semáforo. Para no perder las llamadas múltiples y rastrear el sock que se está utilizando, tendrá que haber una tabla o una lista de punteros a los sockets que se utilizan. Y custom_sk_data_ready() tendrá que marcar en la tabla/lista de qué socket se pasó.

¿Este método suena? ¿O debería lidiar con el problema de usuario/espacio de kernel al usar las llamadas al sistema estándar?

hallazgo inicial:

Todas las funciones de devolución de llamada en la estructura sock se llama en un contexto de interrupción. Esto significa que no pueden dormir. Para permitir que el hilo principal del kernel para dormir en una lista de tomas listos, se utilizan mutex, pero el custom_sk_data_ready() deben actuar como un spinlock sobre las exclusiones mutuas (llamadas mutex_trylock() en varias ocasiones). Esto también significa que cualquier asignación dinámica debe usar el indicador GFP_ATOMIC.


posibilidad adicional:

Por cada socket abierto, reemplace de sk_data_ready() con uno personalizado (custom_sk_data_ready()) cada toma y crear un trabajador (struct work_struct) y la cola de trabajo (struct workqueue_struct). Se usará una función process_msg() común para cada trabajador. Cree una lista global de nivel de módulo de kernel donde cada elemento de lista tenga un puntero al socket y contenga la estructura de trabajador. Cuando los datos estén listos en un socket, custom_sk_data_ready() se ejecutará y encontrará el elemento de la lista coincidente con el mismo socket, y luego llamará al queue_work() con la cola de trabajos y el trabajador del elemento de la lista. A continuación, se llamará a la función process_msg(), y se puede encontrar ya sea el elemento de lista de coincidencias a través de los contenidos del struct work_struct * parámetro (una dirección), o utilizar la macro container_of() para obtener la dirección de la estructura de la lista que mantiene la estructura del trabajador.

qué técnica es la mayor parte del sonido?

+0

¿No puede tener un programa de ayuda del espacio de usuario haciendo el 'sondeo'? La entrada de multiplexación con 'poll' o' select' está relacionada con el programador (ya que el proceso de pausa está inactivo, por lo que pueden ejecutarse otros procesos), ¡así que no haré eso dentro del kernel! –

+1

@BasileStarynkevitch: Es por eso que solo intento simular el bloqueo del sueño de 'poll()' y 'select()'. Usar esas dos llamadas al sistema desde el kernel es un último recurso. Sospecho que hay problemas con ejecutar 'poll()' y 'select()' en un espacio de ayuda del usuario. El ayudante debe tener acceso a un descriptor de archivo (que no se hace en 'sock_create()') y posiblemente permiso para acceder a un socket que resida en el espacio del kernel. Por lo tanto, ahora la creación del socket debe ocurrir en el espacio de ayuda del usuario y el módulo debe encontrar el socket en función del descriptor del archivo de espacio del usuario. Ahora se vuelve más complicado. – Joshua

+0

No debería estar haciendo nada de eso en el kernel. – mpe

Respuesta

3

Su segunda idea suena más como que va a trabajar.

El código CEPH parece que hace algo similar, consulte net/ceph/messenger.c.

Cuestiones relacionadas