DeviceDriver (5): temporizador de kernel

Uno: gestión del tiempo del kernel

1. El temporizador de hardware proporciona una fuente de reloj y se puede configurar la frecuencia de la fuente de reloj. Después de la configuración, puede generar periódicamente una interrupción del temporizador y el sistema puede utilizar la interrupción del temporizador para medir el tiempo. La frecuencia de interrupción periódica es la frecuencia del sistema, también denominada frecuencia de pulsación; por ejemplo, 1000 Hz, 500 Hz, 100 Hz son la frecuencia de pulsación del sistema. La frecuencia de pulsación del sistema se puede configurar y se puede configurar al configurar el kernel de Linux. El valor predeterminado es 100 Hz, que es 10 ms, que está representado por "HZ" en el kernel de Linux:

# undef HZ
# define HZ		CONFIG_HZ	/* Internal kernel timer frequency */
# define USER_HZ	100		/* some user interfaces are */
# define CLOCKS_PER_SEC	(USER_HZ)       /* in "ticks" like times() */

2. El kernel de Linux usa la variable global jiffies para registrar el número de latidos del sistema desde que se inició, y los jiffies se inicializarán en 0 cuando se inicie el sistema.

extern u64 __jiffy_data jiffies_64;
extern unsigned long volatile __jiffy_data jiffies;

Para el desbordamiento de datos jiffies, el kernel de Linux proporciona algunas API para tratar:

#define time_after(a,b)		\
	(typecheck(unsigned long, a) && \
	 typecheck(unsigned long, b) && \
	 ((long)((b) - (a)) < 0))
#define time_before(a,b)	time_after(b,a)

#define time_after_eq(a,b)	\
	(typecheck(unsigned long, a) && \
	 typecheck(unsigned long, b) && \
	 ((long)((a) - (b)) >= 0))
#define time_before_eq(a,b)	time_after_eq(b,a)

time_after (a, b): generalmente un valor es jiffies, y el valor b es un valor de comparación. Devuelve verdadero cuando a excede b; de lo contrario, es falso. La función time_before devuelve el valor opuesto. La función time_after_eq y time_before_eq tienen una más igual a la condición de juicio.

El kernel de Linux también proporciona varias API para convertir entre jiffies y ms, us y ns:

unsigned int jiffies_to_msecs(const unsigned long j)
unsigned int jiffies_to_usecs(const unsigned long j)
inline u64 jiffies_to_nsecs(const unsigned long j)

unsigned long msecs_to_jiffies(const unsigned int m)
unsigned long usecs_to_jiffies(const unsigned int u)
unsigned long nsecs_to_jiffies(u64 n)

Dos: temporizador de núcleo

1. El método de uso del temporizador del kernel de Linux solo necesita proporcionar el tiempo de espera (similar al tiempo de temporización) y la función de procesamiento de tiempo de espera. Cuando se alcanza el tiempo de espera, se ejecutará la función de procesamiento de tiempo de espera correspondiente. Debe tenerse en cuenta que el temporizador del kernel de Linux no se ejecuta periódicamente, se cerrará después del tiempo de espera.Si desea realizar el ciclo, solo necesita reiniciar el temporizador en la función de procesamiento de tiempo de espera.

Definición del temporizador del kernel de Linux:

struct timer_list {
	/*
	 * All fields that change during normal runtime grouped to the
	 * same cacheline
	 */
	struct list_head entry;                    
	unsigned long expires;                              /* 定时器超时时间,单位是节拍数 */
	struct tvec_base *base;

	void (*function)(unsigned long);                    /* 超时处理函数 */
	unsigned long data;                                 /* 传递给处理函数的参数*/

	int slack;
};

2. API relacionada con el temporizador central

(1) Inicialización

void init_timer(struct timer_list *timer)

(2) Registre el temporizador y el temporizador comenzará a funcionar después de que se registre el kernel

void add_timer(struct timer_list *timer)

(3) Elimina el temporizador, el valor de retorno es 0 significa que el temporizador no se ha activado, de lo contrario se ha activado

int del_timer(struct timer_list * timer)

(4) Espere a que el temporizador salga (es decir, se agote) y luego elimínelo, y no se puede usar en el contexto de interrupción

int del_timer_sync(struct timer_list *timer)

(5) Modificar el valor de tiempo

int mod_timer(struct timer_list *timer, unsigned long expires)

Tres: Ejemplo

struct timer_list timer; /* 定义定时器 */

/* 定时器回调函数 */
void function(unsigned long arg)
{
	/*
	* 定时器处理代码
	*/
	
	/* 如果需要定时器周期性运行的话就使用 mod_timer
	* 函数重新设置超时值并且启动定时器。
	*/
	mod_timer(&dev->timertest, jiffies + msecs_to_jiffies(2));
}

/* 初始化函数 */
void init(void)
{
	init_timer(&timer); /* 初始化定时器 */
	
	timer.function = function; /* 设置定时处理函数 */
	timer.expires=jffies + msecs_to_jiffies(2);/* 超时时间 2 秒 */
	timer.data = (unsigned long)&dev; /* 将设备结构体作为参数 */
	
	add_timer(&timer); /* 启动定时器 */
}

/* 退出函数 */
void exit(void)
{
	del_timer(&timer); /* 删除定时器 */
	/* 或者使用 */
	del_timer_sync(&timer);
}

 

Supongo que te gusta

Origin blog.csdn.net/qq_34968572/article/details/103698005
Recomendado
Clasificación