-
커널은
<asm/param.h>
헤더파일에 시스템 타이머의 진동수를 HZ라는 값에 저장한다. -
일반적으로 HZ 값은 100 또는 1000으로 설정돼있고, 커널 2.5 버전부터 기본값이 1000으로 상향됐다.
- 장점: 타이머 인터럽트의 해상도와 정확도가 향상돼 더 정확한 프로세스 선점이 가능해졌다.
- 단점: 타이머 인터럽트 처리에 더 많은 시간을 소모하고, 전력 소모가 늘어난다.
- 실험결과 시스템 타이머를 1,000Hz로 변경해도 성능을 크게 해치지 않는다는 결론이 났다.
-
<linux/jiffies.h>
에 jiffies 라는 전역변수에는 시스템 시작 이후 발생한 틱 횟수가 저장된다. -
타이머 인터럽트가 초당 HZ회 발생하므로 jiffies는 1초에 HZ만큼 증가한다.
-
따라서 시스템 가동 시간은 jiffies / HZ 로 계산할 수 있다.
-
32-bit 시스템에선 unsigned long 형인 jiffies는 HZ 100에선 497일, 1,000에선 50일이면 오버플로우가 발생한다.
-
반면에, 64-bit 시스템에선 평생 발생하지 않는다.
- 이 문제를 해결하기 위해 32-bit 시스템에서는
extern u64 jiffies_64
라는 변수를 만들고 - 주 커널 이미지 링커 스크립트에 jiffies = jiffies_64라고 써서 두 변수를 겹쳐버린다.
- 이러면 jiffies 변수는 32-bit 시스템에서도 오버플로우가 발생하지 않는다.
- 이 문제를 해결하기 위해 32-bit 시스템에서는
-
jiffies는 오버플로우일 때 다시 0으로 돌아간다.
-
서로 다른 두 jiffies값을 올바르게 비교할 수 있도록 매크로 함수를 제공하고 있다.
#define time_after(a, b) ((long)(b) - (long)(a) < 0)
#define time_before(a, b) ((long)(a) - (long)(b) < 0)
- 보통 a는 현재 jiffies값이, b는 비교하려는 값이 들어간다.
1. 타이머 인터럽트
- 타이머 인터럽트는 다음 과정을 처리한다.
- xtime_lock 락을 얻어 xtime, jiffies 변수에 안전하게 접근한다.
- 아키텍처 종속적인
tick_periodic()
함수를 호출한다. - jiffies 값을 1 증가, xtime에 현재 시간을 갱신한다.
- 설정 시간이 만료된 동적 타이머의 핸들러를 실행한다.
- 1/HZ 초마다 한 번씩 타이머 인터럽트가 발생해
tick_periodic()
핸들러가 호출된다. do_timer()
에서는 jiffies를 증가하고 시스템 내 여러 통계 변수를 갱신한다.update_process_time()
에서는account_process_tick()
함수에서 프로세서의 시간을 갱신한다.run_local_timers()
함수에서 제한시간이 만료된 타이머들의 핸들러를 실행한다.schedule_tick()
함수는 현재 프로세스의 타임슬라이스 값을 줄이고, 필요한 경우 need_sched 플래그를 설정해 스케줄링 여부를 결정한다.
2. 타이머
- 커널 타이머는 초기화 작업 → 핸들러 설정 → 타이머 활성화로 사용하고 만료된 이후 자동으로 소멸된다.
- 타이머는 비동기적으로 실행되므로 race condition이 발생할 잠재적인 위험이 있다. 따라서
del_timer()
함수 보다는 조금 더 안전한 버전인del_timer_sync()
함수를 사용하자.
3. 작은 지연
- 간혹 커널 코드에서는 아주 짧지만 정확한 지연 시간이 필요한 경우가 있다.
- 커널의
<linux/delay.h>
에는 jiffies 값을 사용하지 않고도 지연처리를 하는mdelay()
,udelay()
,ndelay()
3가지 함수를 제공한다.- 물론, 지연 하는 동안 시스템이 동작을 정지하므로 꼭 필요한 경우가 아니면 절대 쓰면 안 된다.
- 더 적당한 해결책은
schedule_timeout()
함수를 사용하는 것이다.- 최소한 인자로 넘긴 지정한 시간만큼 해당 작업이 휴면 상태로 전환됨을 보장한다.
- 당연하지만, 이 함수는 프로세스 컨텍스트에서만 사용할 수 있다.
참고