Low resolution sleeping
- unsigned int sleep(unsigned int seconds)
- Puts the invoking process to sleep for the number of seconds specified by seconds
- Return value
- Number of seconds not slept (does not set errno)
- A seccessful call returns 0, but the function may return other values between 0 and seconds
- A signal interrupt the nap
- If sleeping the entire specified time is truly a concern (not a usual case):
- Number of seconds not slept (does not set errno)
unsigned int s = 5;
while((s=sleep(s))
;
Process State
- Running
- A process is running on a processor
- Ready
- A process is ready to run, but the OS has chosen not to run it at this given moment
- Blocked (Waiting)
- A process is not ready to run until some event takes place
Example
#define BILLION 100000000L
int main(int argc, char *argv[])
{
struct timespec start, end;
unit64_t diff;
clockid_t clk;
clockid_t clocks[] = {
CLOCK_REALTIME,
CLOCK_MONOTONIC,
CLOCK_PROCESS_CPUTIME_ID,
CLOCK_THREAD_CPUTIME_ID};
clk = clocks[atoi(argv[1])];
clock_gettime(clk, &start);
sleep(3);
clock_gettime(clk, &end);
diff = BILLION * (end.tv_sec - start.tv_sec) + end.tv_nsec - start.tv_nsec;
printf("Time = %llu ns\n", (long long unsigned int) diff);
return 0;
}
output
+ sleep()은 원하는 시간만큼 sleep하는 것은 보장하지만, 정확하지는 않다 (overrun).
+ Time이 정확히 3초가 아닌 것은 Noise가 들어가서인데, system call을 수행하는데 걸리는 overheads, Block → Ready로 넘어갈 때 Ready상태에서 대기한 시간 아니면 OS가 3초를 측정하는데에 오차가 발생할 수 있다는 등 여러 가지 Noise가 있을 수 있다.
+ 3, 4번째 예시의 경우는 Process, Thread time으로 해당 프로세스나 thread가 CPU자원을 점유한 시간을 측정하는 것이다. sleep을 하는 동안은 run상태가 아닌 wait상태이기 때문에, sleep하는 동안은 시간이 흐르지 않는다. 또한 multi-threads환경이 아니기 때문에 process time과 thread time이 똑같다.
Sleeping with Nanosecond Resolution
- int nanosleep(const struct timespec *req, struct timespec *rem)
- Puts the invoking process to sleep for the time specified by req
- Return value
- On success, returns 0; on error, returns -1
- If a signal interrupts the sleep, the call can return before the specified time has elapsed
- Return value == -1 and errno == EINTR
- Places the remaining time to sleep (the amount of req not slept) in rem
- sleep()은 signal에 의해 interrupt가 발생해도 -1을 리턴하거나, errno가 EINTR로 세팅되지 않는데, nanosleep()의 경우는 signal에 의해 interrupt가 발생하면 -1을 리턴하고 errno가 EINTR이며, rem에 남은 시간을 적어준다.
- int clock_nanosleep(clockid_t clock_id, int flags, const struct timespec *req, struct timespec *rem)
- clock_id specifies the time source to measure
- flags parameter is either 0 or TIMER_ABSTIME
- 0: req is treated as interval
- TIMER_ABSTIME: req is treated as absolute (rarely uesd)
Example
#define BILLION 1000000000L
void my_handler(int signum)
{
char *str = "Wake up!\n";
write(1, str, strlen(str));
}
int main(void)
{
struct timespec start, end, req, rem;
unit64_t diff;
int rv;
signal(SIGUSR1, my_handler);
/* 5.5 sec */
req.tv_sec = 5;
req.tv_nsec = 500000000;
clock_gettime(CLOCK_MONOTONIC, &start);
rv = clock_nanosleep(CLOCK_MONOTONIC, 0, &req, &rem);
clock_gettime(CLOCK_MONOTONIC, &end);
diff = BILLION * (end.tv_sec - start.tv_sec) + end.tv_nsec - start.tv_nsec;
printf("Time = %llu ns\n", (long long unsigned int) diff);
if(rv)
printf("Remaining time = %ld s, %ld ns\n", rem.tv_sec, rem.tv_nsec);
return 0;
}
output
Alarms
- unsigned int alarm(unsigned int seconds)
- Schedules the delivery of a SIGALRM signal to the invoking process after seconds seconds of real time have elapsed
- If a previously scheduled signal was pending
- Cancels the previous alarm, replaces it with the newly requested alarm, and
- Returns the number of seconds remaining in the previous alarm
- process당 alarm은 하나기 때문에, 새로운 alarm을 설정하면 기존의 alarm은 삭제되고 return값으로 이전 alarm이 울리기까지 남았던 시간을 return해준다.
- If seconds is 0, the previous alarm, if any, is canceled, but no new alarm is scheduled
- 만약 second parameter에 0을 넣는다면, 이전 alarm은 삭제되고 새로운 alarm은 설정되지 않는다.
Example
int left;
char *msg1 = "Beep\n";
char *msg2 = "Boom!\n";
void bomb(int signum)
{
left--;
if(left){
write(1, msg1, strlen(msg1));
alarm(1);
}
else{
write(1, msg2, strlen(msg2));
_exit(0);
}
}
int main(int argc, char *argv[])
{
left = atoi(argc[1]);
signal(SIGALRM, bomb);
write(1, msg1, strlen(msg1));
alarm(1);
while(1)
pause();
return 0;
}
output
Overruns
- System calls discussed guarantee that they will sleep at least as long as requested (or return an error indicating otherwise)
- Never return success without the requested delay elapsing
- It is possible, however, for an interval longer than the requested delay to pass
- Timer granularity
- Granularity of the timer is coarser than the requested time interval
- Delayed scheduling
- Requested time may have elapsed, and the kernel may have woken up the process on time, but the scheduler may have selected a different task to run
- Timer granularity
- 만약 sleep()을 여러번 한다면 overruns으로 인해 오류가 누적될 수도 있다.
'[학교 수업] > [학교 수업] 시스템 프로그래밍' 카테고리의 다른 글
[시스템 프로그래밍] Timers (1) | 2024.12.12 |
---|---|
[시스템 프로그래밍] 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 |