Timers
- Sleeping
- Allows a process (or thread) to suspend execution for a period of time
- sleep(), nanosleep(), clock_nanosleep()
- Allows a process (or thread) to suspend execution for a period of time
- Timer
- Allows a process to schedule a notification for itself to occur at some time in the future
- alarm() → 주기적인 타이머를 사용하기에는 부적합
- Interval timer (itimer)
- POSIX timer
- Allows a process to schedule a notification for itself to occur at some time in the future
Interval Timers
- int setitimer(int which, const struct itimerval *value, struct itimerval *ovalue)
- Provide more control than alarm()
- Can automatically rearm themselves
- Arms a timer of type which with the expiration specified by value
- ITIMER_REAL
- Measures real time and sends the process a SIGALRM signal
- ITIMER_VIRTUAL
- Decrements only while the process' user-space code is executing and sends the process a SIGVTALRM signal
- ITIMER_PROF
- Decrements both while the process is executing, and while the kernel is executing on behalf of the process and sends the process a SIGPROF signal
- ITIMER_REAL
- Once the time specified by it_value elapses, the kernel rearms the timer with the time provided by it_interval
- it_value is the time remaining on the current timer
- If it_interval is 0, the timer is not rearmed ≒ alarm(it_value)
struct itimerval{
struct timeval it_interval; /* next value */
struct timeval it_value; /* current value */
}
- If ovalue is not NULL, the previous values for the interval timer of type which is returned → alarm()과 마찬가지로 덮어쓴 이전 알람을 얻을 수 있음
- Return value
- On success, 0 is returned; on error, -1 is returned
Interval Timers
- int getitimer(int which, struct itimerval *value)
- Returns the current values for the interval timer of type which
- Return value
- On success, 0 is returned; on error, -1 is returned
Example
void alarm_handler(int signo)
{
char *str = "Timer expired!\n";
write(1, str, strlen(str));
}
void foo(void)
{
struct itimerval delay;
int ret;
signal(SIGALRM, alarm_handler);
delay.it_value.tv_sec = 5;
delay.it_value.tv_usec = 0;
delay.it_interval.tv_sec = 1;
delay.it_interval.tv_nsec = 0;
ret = setitimer(ITIMER_REAL, &delay, NULL);
if(ret){
perror("setitimer");
return;
}
while(1) pause();
}
Interference with alarm()
- On Linux, alarm() and setitimer() share the same per-process real-time timer
- Setting a timer with one of these functions changes any timer previous set by either of the functions
- Use only one of setitimer() and alarm() for setting real-timer timers
- alarm()과 setitimer()에서의 ITIMER_REAL을 사용하는 경우는 같은 CLOCK을 공유하기 때문에 두 개를 동시에 같이 사용하면 오류가 발생할 수 있다.
Interval Timers
- If simplicity is a prime motivator, setitimer() is most likely a good choice
- Classical interval timers suffer a number of limitations
- We can set only one timer of each of the three type
- ITIMER_REAL, ITIMER_VIRTUAL, and ITIMER_PROF
- The only way of being notified of timer expiration is via delivery of a signal
- Can't change the signal that is generated when the timer expires
- If an interval timer expires multiple times while the corresponding signal is blocked, then the signal handler is called only once
- Timers are limited to microsecond resolution
- We can set only one timer of each of the three type
POSIX Timers
Creating a Timer
- int timer_create(clockid_t clockid, struct sigevent *evp, timer_t *timerid) → POSIX signal이기 때문에 sigaction()을 통해서 등록해야함
- Creates a new timer associated with the POSIX clock clockid and stores a unique timer identification in timerid
- clockid
- CLOCK_REALTIME
- CLOCK_MONOTONIC
- CLOCK_PROCESS_CPUTIME_ID
- CLOCK_THREAD_CPUTIME_ID, etc.
- Nothing actually happens until the timer is armed
- clockid
- Return value
- On success, returns 0; on failure, returns -1
- If evp is not NULL
- It defines the asynchronous notification that occurs when the timer expires
evp.sigev_notify | Notification method |
SIGEV_NONE | No notification; monitor timer using timer_gettime() |
SIGEV_SIGNAL | Send signal evp.sigev_signo to process → 정해진 signal을 보내는게 아니라 커스텀이 가능 |
SIGEV_THREAD | Call evp.sigev_notify_function as start function of new thread |
SIGEV_THREAD_ID | Send signal evp.sigev_signo to thread sigev_notify_thread_id |
- If evp is NULL,
- It is equivalent to specifying sigev_notify is SIGEV_SIGNAL, sigev_signo is SIGALRM, and sigev_value.sival_ptr is timerid
Example
struct sigevent evp;
timer_t timer;
int ret;
evp.sigev_value.sival_ptr = &timer;
evp.sigev_notify = SIGEV_SIGNAL;
evp.sigev_signo = SIGUSR1;
ret = timer_create(CLOCK_REALTIME, &evp, &timer);
if(ret)
perror("timer_create");
Arming a Timer
- int timer_settime(timer_t timerid, int flags, const stuct itimerspec *value, struct itimerspec *ovalue)
- Arms the timer specified by timerid with the expiration value
struct itimerspec{
struct timespec it_interval; /* next value */
struct timespec it_value; /* current value */
};
- flags
- 0: it_value is interpreted as relative
- TIMER_ABSTIME: it_value is interpreted as absolute
Obtaining the Expiration of a Timer
- int timer_gettime(timer_t timerid, struct itimerspec *value)
- Stores the time until next expiration and the interval of the timer specified by timerid in the structure pointed at by value
- Return value
- On success, return 0; on failure, returns -1
Obtaining the Overrun of a Timer
- int timer_getoverrun(timer_t timerid)
- Returns the overrun count for the timer specified by its timerid argument
- On failure, returns -1
- Async-signal-safe
- It is safe to call if form within a signal handler
- The timer overrun count is reset each time we receive the timer signal
Deleting a Timer
- int timer_delete(timer_t timerid)
- Destroys the timer associated with timerid
- Return value
- On success, returns 0; on failure, returns 01
Example
void alarm_handler(int signo)
{
char *str = "Timer expired!\n";
write(1, str, strlen(str));
}
void foo(void)
{
struct sigaction sa;
struct sigevent ev;
timer_t timerid;
struct itimerspec delay;
int ret;
sa.sa_handler = alarm_handler;
ret = sigaction(SIGUSR1, &sa, NULL);
if(ret){
perror("sigaction");
return;
}
ev.sigev_notify = SIGEV_SIGNAL;
ev.sigev_signo = SIGUSR1;
ev.sigev_value.sival_ptr = &timerid;
ret = timer_create(CLOCK_MONOTONIC, &ev, &timerid);
if(ret){
perror("timer_create");
return;
}
delay.it_value.tv_sec = 5;
delay.it_value.tv_nsec = 0;
delay.it_interval.tv_sec = 1;
delay.it_interval.tv_nsec = 0;
ret = timer_settime(timerid, 0, &delay, NULL);
if(ret){
perror("timer_settime");
return;
}
while(1) pause();
}
'[학교 수업] > [학교 수업] 시스템 프로그래밍' 카테고리의 다른 글
[시스템 프로그래밍] Sleeping (1) | 2024.12.11 |
---|---|
[시스템 프로그래밍] Time (1) | 2024.12.03 |
[시스템 프로그래밍] Standard I/O Library (1) | 2024.11.28 |
[시스템 프로그래밍] I/O Redirection (1) | 2024.11.28 |
[시스템 프로그래밍] Memory Mapped I/O (1) | 2024.11.24 |