En el anterior post hablé un poco de tasklets, y aun que hoy no dire todo hacerca de este tema,
ya que es muy complejo y grande, si me expandire con algunos conceptos...

Es necesario entender el contexto de interrupciónes, ya que sin el, el kernel no podría "ceder"
eventos en el hardware y por consecuencia en el espacio de usuario.
Hay un esquema que hice y quiero mostrar, es acerca de la planificación de tareas y ejecución
por parte del kernel:

Imagen


Entonces si comprendemos ésta formula, logramos entender por que es necesario el programar una tarea
para que se ejecute más tarde...
El procesador realiza la planificación de esa tarea en el controlador de interrupciones(contexto de
interrupcion y mitad superior) y posteriormente la ejecuta (contexto del kernel, mitad inferior).


Ahora bien, esto tiene grandes ventajas en multiprocesamiento, ya que un tasklet SOLO se ejecutara en una
CPU(en la cual se programo), evitando la propagación simultanea en más unidades de control de proceso.
Sin embargo tasklets diferentes pueden ser ejecutadas en CPU distintos al mismo tiempo, esto en resumidas
cuentas quiere decir que solo programaremos un tasklet por CPU.

mi algoritmo carga el tasklet de forma estatica, y por defecto iniciado.
Aca el la función:
static void __attribute__((__section__(".text.init") )) 
 pb_static_tl(void(*callback_function))
{
  #ifndef __INIT_ATOMIC_TL__
    struct tasklet_struct _tl = {NULL, 0, ATOMIC_INIT(0), 
				callback_function, (unsigned long) NULL};
    #define __INIT_ATOMIC_TL__
  #endif
  if(!test_and_set_bit(TASKLET_STATE_SCHED, &_tl.state ) ) {
    __tasklet_schedule(&_tl);
    tasklet_kill(&_tl);
  }
}
y aca el código completo de como usar la función:
#if defined(CONFIG_MODVERSIONS) && ! defined(MODVERSIONS)
   #include <linux/modversions.h>
   #define MODVERSIONS
#endif
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/interrupt.h>

static void my_tasklet_function(void)
{
  printk(KERN_INFO "<tasklet iniciado desde funcion>");
}

static int __section(.init.text) __cold notrace INIT_KERNEL(void)
{
  // Llamado de la función
  pb_static_tl(my_tasklet_function);
  pb_static_tl(my_tasklet_function);
  pb_static_tl(my_tasklet_function);
  
  return 0x0;
}

static void __section(.exit.data) EXIT_KERNEL(void)
{
  // fin de seccion
}

module_init(INIT_KERNEL);
module_exit(EXIT_KERNEL);
Como ven al igual que la anterior se puede re-llamar tantas veces como se quiere y este no usa kmalloc(parecido a malloc pero en el kernel).
Aun que mucho queda por sondear en este tema, Colas de trabajo, Softirq, Tasklets de alta resolucion, etc...

Por ahora espero que hayan entendido más acerca de éste tema, y recuerden todo procesamiento comienza con una interrupción.
Saludos y hasta otra!
Responder

Volver a “Fuentes”