Linux kernel 에서는 unsigned long 타입의 변수 a와 b 사이에서
a가 b 보다 큰지 검사를 하는 매크로함수로 time_after() 라는 것을 제공한다.
여기서 그냥 "if ( a > b)" 이렇게 검사하면 되는거 아니야 ? 라고 할지 모르겠지만
timer_after()함수의 특성은 a가 overflow되어 값이 b보다 작아지는 경우에도
정상동작을 한다는것이다. 즉. 커널에서 jiffies 변수의 overflow를 고려하여 만든 함수이다.
프로토타입
int time_after(unsigned long a, unsigned long b)
리턴값 ( 1 : a 가 b 보다 크다 , 0 : a 가 b 보다 크지 않다. )
코드설명
time_after() 함수의 코드는 다음과 같다.
#define typecheck(type,x) \
({ type __dummy; \
typeof(x) __dummy2; \
(void)(&__dummy == &__dummy2); \
1; \
})
#define time_after(a,b) \
(typecheck(unsigned long, a) && \
typecheck(unsigned long, b) && \
((long)(b) - (long)(a) < 0))
여기서 typecheck는 항상 1이기 때문에 무시하면 결국 아래와 같은 형태가 된다.
((long)(b) - (long)(a) < 0))
결국 unsigned 형인 a와 b를 signed 형으로 casting 하여 b - a 의 결과가 0보다 작은지 비교하는 것이다.
이렇게 signed 로 casting 된 변수는 밑에 case 1,2,3의 예제와 같이 처리되어 overflow상황에서도
정상동작을 하게 되는것이다. (case2 이 overflow에 대한 예제)
case 1
b a
|----------------------------------------|----------------------------------------|
0x00000000 0x7FFFFFFF 0x8FFFFFFF 0xFFFFFFFF
0 2147483648 -2147483648 -1
"b - a = 음수"
결과가 음수 이기 때문에 a는 b 보다 크다.
case 2 (a가 overflow되어 b보다 작아진 경우)
a b
|----------------------------------------|----------------------------------------|
0x00000000 0x7FFFFFFF 0x8FFFFFFF 0xFFFFFFFF
0 2147483648 -2147483648 -1
a가 overflow 되어 b보다 작아진 경우다.
이 경우 time_after()함수처리에 의해서 signed 형으로 casting 되면 "음수b - 양수a" 의 형태가 된다.
즉 "음수b - 양수a" 의 결과는 음수가된다.
결과가 음수 이기 때문에 a는 b 보다 크다.
case 3
b a
|----------------------------------------|----------------------------------------|
0x00000000 0x7FFFFFFF 0x8FFFFFFF 0xFFFFFFFF
0 2147483648 -2147483648 -1
그러나 만약에 a와 b가 양수에서 음수로 변경되는 지점을 기준으로 양쪽에 존재하면?
"양수b - (음수a)" 의 계산결는 항상 양수가 되고 잘못된 결과를 리턴하는 것이 아니냐? 라는 의문을 가지게 된다.
그러나 이 지점에서의 "양수b - (음수a)" 결과는 2147483648 보다 큰값을 가지게 되며
결국 이로 인하여 부호가 변경되어 결과값은 음수가된다.
결과가 음수 이기 때문에 a는 b 보다 크다.
주의사항
b 와 a의 gap이 2147483648 이상 벌어지게 되면 의도하지 않은 +,- 부호 변화에 의해서 잘못된 결과를 리턴하게 된다.
이는 HZ가 1000인 linux box 에서 jiffies로 치면 대략 24.5일 정도가 소요되며 time_after() 및 관련 함수를 이용시
비교하는 변수 두개가 2147483648 이상 차이가 나지 않는 다는 전제 하에서 사용이 가능하다.
참고로 time_after64()를 사용하게 되면 292,471,208년 이상 gap벌어져야 잘못된 결과를 리턴한다. time_after64일 경우
마음 편하게 사용하자~