0. 도입
컴퓨터는 시간을 어떻게 측정하는 것일까? 컴퓨터에서 Timer는 매우 중요한 역할을 한다. 단순히 알람, 컴퓨터 꺼짐 예약뿐만 아니라 각 process에 할당된 time slice를 정해주고 preemption 시켜주는 역할도 timer가 한다. 이번에는 실제 system의 timer hardware를 사용하여 다양한 timer interrupt와 이에 필요로 하는 구조체, 변수들을 알아보자.
1. Timer Interrupt
timer interrup는 시스템의 timing hardware에 의해서 주기적으로 발생한다. 하긴, 컴퓨터에 수천개의 process, context가 존재하는데 매 순간순간마다 어딘가에서 변수를 증가시키는 형태로 하는 것은 불가능할 것이다. Interrupt를 걸어서 Interrupt context내에서 수행해야 될 것이다. 이 Interval(HZ)은 boot time에 kernel에 의해서 정해질 수 있으며, 1초에 발생하게 하고 싶은 interrupt의 수를 나타낸다. (2.6으로 넘어오면서 USER_HZ로 바뀌었다고 한다) 그리고 각각의 interrupt마다 jiffies라는 변수를 증가시키게 된다. (2.6부터는 이전의 32bit jiffies변수가 너무 작았기 때문에 그 한계를 극복하기 위하여 64bit의 jiffies값을 사용하게 되었고 이를 jiffies_64라고 하였다.) 이 변수는 마치 class에서 변수를 직접 접근하는 것이 지양되는 것처럼 get_jiffies_64()라는 함수를 통해서 접근하는 것을 지향한다.
다른 모든 Interrupt와 마찬가지로 Interrupt가 발생하면 'do_IRQ'로 들어오게 된다. 다음 interrupt handler인 'timer_interrupt'가 호출이 되고 'do_timer_interrupt', 'do_timer_interrupt_hook', 'do_timer'가 차례대로 호출이 된 다음, 마지막으로 jiffes_64의 값이 1 증가된다.
HZ는 default로 2.4에서는 100, 2.6이후부터는 1000이 되었다. HZ가 증가한 이유는 무엇일까? HZ의 값이 100인 경우에는 어떠한 일의 최소 처리 단위 시간이 0.01초였다. 즉, 특정 시간 이후에 무엇을 하고 싶다면 최소한 0.01초는 기다려야 된다는 것이다. 하지만 컴퓨터의 처리 속도가 증가하면서 하나의 작업을 하는데 필요한 시간이 줄어들었다. 따라서 단위 시간당 interrupt가 더 필요로 하게 되었고 이에 따라서 1000으로 증가된 것이다. HZ를 customizing 하는 것도 가능하지만, 이는 kernel의 recompile을 요구하는 작업이다.
Jiffies는 HZ와 매우 연관이 깊은 변수이다. 1/HZ초마다 jiffies가 증가하기 때문에 1초에 HZ만큼의 jiffies가 증가하는 관계를 가진다. 앞에서 말한 것에 추가적으로 한가지 더 설명하면 jiffies와 jiffies_64는 같은 memory space를 가리키고 있다. 즉, jiffies_64의 하위 32bit는 jiffies와 동일한 값이다. 이는 호환성을 위해 이렇게 설정되었다.
2. Delay Execution
하드웨어와의 synchronize에서 주로 사용이 된다. 작은 시간을 delay 시키는 역할을 한다.
- mdelay() - below 5 millisecond (ms 단위)
- udelay() - below 1000 microsecond (us 단위)
- ndelay() - 2.6 버전 이후 (ns 단위)
만약 더 오랜 기간의 delay가 필요로 한다면 busy waiting을 사용한다. 이외의 Machine cycle, clock cycle, clock frequency를 사용하는 정말 미묘한 delay도 가능하다.
3. Kernel Timer
kernel timer는 '사용자 설정 시간' 이후에 '사용자 설정 인자'를 가지고 '사용자 지정 함수'를 수행할 수 있게 해주는 것이다. 현재 process를 blocking하지 않고 이후에 일어날 일을 scheduling을 하거나, 정해진 시간마다 interrupt를 발생시키지 못하는 hardware에서 일을 완료하였는지 확인하는 Polling과정에서 사용한다. 이 기능은 'timer interrupt handler'에 구현이 되어있다. 즉, jiffies를 증가시키는 것, process scheduling 등등 과 같은 우선적인 routine을 수행한 뒤에 실행이 된다.
#include <linux/timer.h>
struct time_list{
unsigned long expires; // User defined time
void (*function) (unsigned long); // User defined function
unsigned long data; // User defined parameter
}
위와 같이 timer_list라는 구조체를 사용하여 정의한다. 해당 구조체를 Init_timer를 사용하여 initialize 하고 안의 변수와 함수를 넣은 뒤, add_timer를 통해 커널 내부의 timer_list들에 추가한다. 이후 timer interrupt handler는 jiffies값을 증가시킨 이후에 각각의 timer_list structure안의 expires값과 비교하여 expire가 되었으면 user defined function을 수행하게 된다. expire 되기 전에 del_timer를 통해서 timer_list구조체에서 삭제를 해주게 된다. 이미 삭제된 timer라면 0을 정상적인 삭제가 되면 1을 반환한다. (또는 expire가 되면 자동으로 삭제가 된다)
'리눅스' 카테고리의 다른 글
Linux 사용자(user) 추가하기 (0) | 2021.11.26 |
---|---|
IPMI ssh로 접속하기 (0) | 2021.09.23 |
Kernel Memory Allocation (0) | 2021.06.08 |
Device Control Method (0) | 2021.04.21 |
Cross Development Environment(교차 개발 환경) (0) | 2021.03.12 |