del hardware usando distintos metodos como por ejemplo IRQ, IPC, RCU, sincronizacion en SMP,
etc...
Un clara prueba de una tarea planificada(para un futuro) son los "timer_list" o timers del kernel,
su API contiene funciónes para la ayuda de la programación-re-programación de tareas,
ahora bien, esta API tiene algunas limitaciones, como que por ejemplo algunos eventos del timer
no se puede sincronizar ni tampoco hay nada que garantize la exclusion mutua(o datos atomicos),
dentro de otras cosas...
Por eso se me ocurrió programar ésta estructura, la cual contiene algunas caracteristicas:
[+]Programación de tarea para un futuro(calibrada en segundos).
[+]Lanzamiento de procesos externos con hilos del kernel.
[+]loopeo de una función en el kernel con/sin exclusion mutua.
[+]Detecta cuando el tiempo de caducidad de la función a terminado y se optimiza a si mismo para liberar memoria del procesador.
[+]Optimizado, no congela el procesador en multiples tareas de ciclos repetitivos(como lo son los bucles).
[+]facil y libre configuración.
y bueno aca el código del driver:
/*
* ************************************************
* Autor: NvK
* Funcion: Estructura para la optimizacion de timers en el kernel.
* Fecha: 14-1-2014
* ************************************************
*/
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/proc_fs.h>
#include <linux/sched.h>
#include <linux/kthread.h>
struct tnvk_kernel_struct {
struct timer_list kern_timer;
int(*cpu_cycle)(struct tnvk_kernel_struct *tks, unsigned int secs);
bool free_timer;
bool lock_scheduler;
bool interrupt_cycle;
spinlock_t lock;
};
#define ELF_INITED ".text.data"
static struct task_struct *kthread_timer;
static struct tnvk_kernel_struct __attribute__((__section__(ELF_INITED), cold))*set_tnvk(struct tnvk_kernel_struct *tks,void (*callback_function), void *param, unsigned int aprox_secs);
static struct tnvk_kernel_struct __attribute__((__section__(ELF_INITED)))*__sync_timer_schedule (struct tnvk_kernel_struct *tks);
static void __attribute__((__section__(ELF_INITED)))tnvk_cpu_cycle(struct tnvk_kernel_struct *tks, unsigned aprox_secs);
static void __attribute__((__section__(ELF_INITED)))wu_process_tnvk(struct tnvk_kernel_struct *tks, void(*callback_func));
static const char KTHRD_TNVK_NAME[] __section(.init_rodata)= "TNVK_THREAD";
/*Loopear cpu funcion*/
#define tnvk_cpu_spin_cycle(tks, aprox_secs)({ \
spin_lock(&tks->lock); \
tnvk_cpu_cycle(tks, aprox_secs); \
spin_unlock(&tks->lock); \
})
static void __attribute__((__section__(ELF_INITED)))tnvk_cpu_cycle(struct tnvk_kernel_struct *tks,unsigned int aprox_secs)
{
if (tks->interrupt_cycle!=true)
tks->cpu_cycle= mod_timer((struct tnvk_kernel_struct *)&tks->kern_timer, jiffies+(aprox_secs*HZ)+0x1);
}
static struct tnvk_kernel_struct __attribute__((__section__(ELF_INITED)))
__attribute__((cold))*set_tnvk(struct tnvk_kernel_struct *tks, void (*callback_function),
void *param,
unsigned int aprox_secs)
{
init_timer(&(*tks).kern_timer);
(*tks).kern_timer.function= (callback_function);
(*tks).kern_timer.data= param;
(*tks).kern_timer.expires= jiffies+(aprox_secs*HZ)+0x1;
/* -- PRE -- */
tks->free_timer= true;
tks->lock_scheduler= false;
tks->interrupt_cycle= false;
return 0;
}
#define begin_tnvk(tks) \
add_timer(&tks->kern_timer);
#define start_tnvk(tks, callback_function, param, aprox_secs)({ \
set_tnvk(tks, callback_function, param, aprox_secs); \
add_timer(&tks->kern_timer); \
})
#define free_tnvk(tks)({ \
del_timer_sync(&tks->kern_timer); \
if (tks) \
kfree(tks); \
})
/* Para uso interno NO USAR */
static struct tnvk_kernel_struct
__attribute__((__section__(ELF_INITED)))*__sync_timer_schedule(struct tnvk_kernel_struct *tks)
{
if((*tks).lock_scheduler) spin_lock(&tks->lock);
for(;;)
{
schedule();
if (timer_pending(&tks->kern_timer)!=1)
break;
}
if(tks->free_timer)
del_timer_sync(&tks->kern_timer);
if((*tks).lock_scheduler) spin_unlock(&tks->lock);
__asm__("nop;");
if(kthread_timer)kthread_stop((struct task_struct*)kthread_timer);
return 0;
}
static void
__attribute__((__section__(ELF_INITED)))wu_process_tnvk(struct tnvk_kernel_struct *tks,void(*callback_func))
{
kthread_timer= kthread_create(callback_func, (struct tnvk_kernel_struct *)tks, (const char *)KTHRD_TNVK_NAME);
wake_up_process(kthread_timer);
}
#define schedule_tnvk(tks) {wu_process_tnvk((struct tnvk_kernel_struct *)tks, __sync_timer_schedule);}
/*****************************************************************/
Algúnos ejemplos:Ejemplo 1 - llama a la funcion timer_callback_func y la ejecuta cuando han pasado 5 segs,
Y además use schedule_tnvk(tks) el cual espera asincrónicamente que finalize la funcion
llamada, una vez hecho ésto la libera automaticamente.
NOTA: Dense cuenta como use .free_timer para liberar el timer al finalizar la función-callback y
crea una zona de exclusion mutua con .lock_scheduler.
Éstos 2 registros son opcionales.
#include ...
#include "tnvk_kernel_struct.h"
struct tnvk_kernel_struct *tks;
static void timer_callback_func()
{
printk("\n*funcion 1 llamada desde kernel_timer");
}
static int __section(.init.text) __cold notrace INIT_KERNEL(void)
{
/* ejemplo 1 */
tks= kmalloc(sizeof(*tks), GFP_KERNEL);
start_tnvk(tks, timer_callback_func, NULL, 5); // lanza el timer.
/* Una vez inicializado se configura la estructura */
tks->free_timer= true; // liberar al terminar (por defecto en true)
tks->lock_scheduler= true // crear una zona de exclusion mutua dentro de la función scheduler_tnvk
schedule_tnvk(tks);
return 0x0;
}
static void __section(.exit.data) EXIT_KERNEL(void)
{
// fin de seccion
free_tnvk(tks); // liberar memoria y timer.
}
module_init(INIT_KERNEL);
module_exit(EXIT_KERNEL);
Ejemplo 2 - llama a una funcion indefinidamente. Fijense que para activar el loop
hay que usar la función tnvk_cpu_cycle dentro de la función/procedimiento que se quiera
repetir.
NOTA: si usan éste metodo NO usen schedule_tnvk(tks) ya que esta sirve para optimizar la función
una vez terminada!.
#include ...
#include "tnvk_kernel_struct.h"
struct tnvk_kernel_struct *tks;
int i;
static void timer_callback_func()
{
printk("\n*funcion 1 llamada desde kernel_timer %d", i);
i++;
tnvk_cpu_cycle(tks, 5); // para loopear la funcion
}
static int __section(.init.text) __cold notrace INIT_KERNEL(void)
{
tks= kmalloc(sizeof(*tks), GFP_KERNEL);
start_tnvk(tks, timer_callback_func, NULL, 5);
return 0x0;
}
static void __section(.exit.data) EXIT_KERNEL(void)
{
// fin de seccion
free_tnvk(tks);
}
![Imagen](http://i.imgur.com/zdX37aD.png)
Ejemplo 3 - llama a 2 funciones(o las que se quieran), indefinidamente.
#include ...
#include "tnvk_kernel_struct.h"
struct tnvk_kernel_struct *tks, *tks2;
int i, x;
static void timer_callback_func()
{
printk("\n*funcion 1 llamada desde kernel_timer %d", i);
i++;
tnvk_cpu_cycle(tks, 5); // para loopear la funcion
}
static void timer_callback_func2()
{
printk("\n#funcion 2 llamada desde kernel_timer %d", x);
x++;
tnvk_cpu_cycle(tks2, 3); // para loopear la funcion
}
static int __section(.init.text) __cold notrace INIT_KERNEL(void)
{
tks= kmalloc(sizeof(*tks), GFP_KERNEL);
tks2= kmalloc(sizeof(*tks2), GFP_KERNEL);
start_tnvk(tks, timer_callback_func, NULL, 5);
start_tnvk(tks2, timer_callback_func2, NULL, 3);
return 0x0;
}
static void __section(.exit.data) EXIT_KERNEL(void)
{
// fin de seccion
free_tnvk(tks);
free_tnvk(tks2);
}
![Imagen](http://i.imgur.com/sXZblUn.png)
Ejemplo 4 - En ésta ocacion uso tnvk_cpu_spin_cycle(tks, 5); que es muy parecido a
hacer tnvk_cpu_cycle(tks, 5); con la diferencia que ésta vez creo una zona de exclusión
mutua dentro del loop de la función.
Ademas uso .interrupt_cycle lo cual detiene la función, y como ejemplo lo hago cuando int i a
llegado a 5, es decir que la función solo se repite 5 veces.
#include ...
#include "tnvk_kernel_struct.h"
struct tnvk_kernel_struct *tks;
int i;
static void timer_callback_func()
{
printk("\n*funcion 1 llamada desde kernel_timer %d", i);
i++;
tnvk_cpu_spin_cycle(tks, 5);
if (i==5) {
tks->interrupt_cycle= true;
}
}
static int __section(.init.text) __cold notrace INIT_KERNEL(void)
{
tks= kmalloc(sizeof(*tks), GFP_KERNEL);
start_tnvk(tks, timer_callback_func, NULL, 5);
return 0x0;
}
static void __section(.exit.data) EXIT_KERNEL(void)
{
// fin de seccion
free_tnvk(tks);
}
![Imagen](http://i.imgur.com/ektldou.png)