본문 바로가기
Linux System/Linux Kernel

[Kernel] Timer

by rewyear 2023. 2. 11.

jiffies

커널에서 시간은 타이머 인터럽트를 통해 관리되는데, 타이머 인터럽트는 1초당 n번 발생하는 빈도가 HZ로 정의되어 있음. 이 HZ값은 아키텍처마다 다르게 정의되어 있다. 만약 100HZ라고 하면 1초당 100번의 타이머 인터럽트가 발생함 

해당 커널 시스템의 HZ 값은 .config에 CONFIG_HZ로 정의되어 있다.

 

커널에는 시스템이 시작한 후, 해당 타이머 인터럽트 발생횟수를 저장하는 jiffies라고하는 전역변수가 정의되어 있는데

extern unsigned long volatile __cacheline_aligned_in_smp __jiffy_arch_data jiffies;

만약 HZ가 100인 시스템에서 시스템이 시작된 뒤 1초 후 jiffies는 값은 100이다.

 

해당 jiffies값을 이용하여 상대적인 시간 처리가 가능해지는데 예를 들어 HZ 값이 100일 때, 3초 뒤의 시간은 현재 jiffies 값에 3 * 100(HZ)를 더한 값이 3초 후를 나타낸다.

int timeout  = jiffies + 3*HZ; // 현재 시간으로 부터 3초 뒤를 나타내는 수식

 

위 jiffies를 기반으로 커널에서는 비동기적으로 타이머 작업을 수행할 수 있다.

 

struct timer_list

/* linux/timer.h*/

struct timer_list {
	/*
	 * All fields that change during normal runtime grouped to the
	 * same cacheline
	 */
	struct hlist_node	entry;
	unsigned long		expires;
	void			(*function)(struct timer_list *);
	u32			flags;

#ifdef CONFIG_LOCKDEP
	struct lockdep_map	lockdep_map;
#endif
};

커널에 정의되어 있는 timer API를 사용하기 위해서는 대개 struct timer_list를 정의해주어야 한다.

해당 구조체의 주요 변수로 expires의 경우 타이머가 만료되는 시간을 나타내며 대개 jiffies + α * HZ로 설정된다.

function의 경우 해당 타이머가 만료될 때 호출되는 콜백 함수를 등록하기 위한 변수이다.

flags는 해당 timer의 속성을 나타낸다.

 

타이머 초기화 및 등록

timer_setup

위의 struct timer_list를 초기화하는 macro로 timer객체, callback, flags를 인자로 받아 타이머 객체를 초기화한다.

#define timer_setup(timer, callback, flags)	__init_timer((timer), (callback), (flags))

 

mod_timer, add_timer

타이머 객체를 초기화 한 뒤에는, 초기화 된 timer 객체를 커널에 등록해야 하는데 mod_timer 또는 add_timer를 통해 타이머를 등록한다. 등록된 타이머는 설정한 expires 시간에 callback함수를 호출한다.

/**
 * mod_timer - modify a timer's timeout
 * @timer: the timer to be modified
 * @expires: new timeout in jiffies
 *
 * mod_timer() is a more efficient way to update the expire field of an
 * active timer (if the timer is inactive it will be activated)
 *
 * mod_timer(timer, expires) is equivalent to:
 *
 *     del_timer(timer); timer->expires = expires; add_timer(timer);
 *
 * Note that if there are multiple unserialized concurrent users of the
 * same timer, then mod_timer() is the only safe way to modify the timeout,
 * since add_timer() cannot modify an already running timer.
 *
 * The function returns whether it has modified a pending timer or not.
 * (ie. mod_timer() of an inactive timer returns 0, mod_timer() of an
 * active timer returns 1.)
 */
int mod_timer(struct timer_list *timer, unsigned long expires)
{
	return __mod_timer(timer, expires, 0);
}
EXPORT_SYMBOL(mod_timer);

/**
 * add_timer - start a timer
 * @timer: the timer to be added
 *
 * The kernel will do a ->function(@timer) callback from the
 * timer interrupt at the ->expires point in the future. The
 * current time is 'jiffies'.
 *
 * The timer's ->expires, ->function fields must be set prior calling this
 * function.
 *
 * Timers with an ->expires field in the past will be executed in the next
 * timer tick.
 */
void add_timer(struct timer_list *timer)
{
	BUG_ON(timer_pending(timer));
	mod_timer(timer, timer->expires);
}
EXPORT_SYMBOL(add_timer);

add_timer()는 timer list에 정의한 expires와 function이 반드시 등록되어 있어야 하며, expires 이후 function에 등록한 함수를 호출한다.

mod_timer()의 경우 새로 timeout을 인자로 받아들여 새로 expires 값을 설정한 후 timer 등록을 수행하는 함수이다. (description에 나와있듯이 기존 등록된 timer를 제거하고, expires를 재설정 후, add_timer() 동작을 수행한다.)

 

타이머 callback 함수에 해당 add_timer 함수를 재귀 호출하게 되면, 반복적으로 일정 간격마다 callback 함수를 호출하여 반복작업을 수행한다.

 

del_timer()

등록된 타이머는 타이머 동작 수행 후 알아서 등록된 timer를 제거하는데, 수행 이전 등록한 timer를 제거해야 하는 경우가 있다. (e.g. timeout 이전에 특정 동작이 되서 timeout를 알릴 필요가 없는 경우)

int del_timer(struct timer_list *timer)

 

 

300x250

'Linux System > Linux Kernel' 카테고리의 다른 글

Kernel Panic Calltrace 분석  (0) 2024.02.08
runtime에 target board kernel의 config 확인  (0) 2022.09.14
User Space와 Kernel Space  (0) 2022.08.17
Device Driver - Atomic  (0) 2022.05.23
Kernel Build  (0) 2022.03.03