42

I am just interested how sleep(time in ms) is implemented in a C library or basically at the OS level...

I am guessing...

  1. May be the based on the processor speed you do a while loop of nop's (I am not sure if the sleep time will be accurate)...
  2. Any special register in processor, where you write some value and the processor simply halts for specified time (this would be very inefficient as the processor can't run even other programs).

Any clues? Probably C library source code can explain? I am not too particular about how "C" is implementing it... I am just wondering in general how the "sleep()" function is implemented.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
FatDaemon
  • 766
  • 2
  • 8
  • 13

6 Answers6

34

Sleep() is implemented at the OS level. The processor doesn't spin when a task/thread/process is sleeping. That particular thread is put on a pending queue (the thread isn't ready to run) until the time has expired at which point the thread will be placed on the ready to run queue.

In the meantime, other threads that are ready to run will be run.

Only if no threads are ready to run will the OS go into the idle thread, which in generally issues instructions to shutdown (or put into a low-power state anyway) the processor until an hardware interrupt occurs.

Only for a very simple system (like the most simple of embedded systems), might Sleep() actually be implemented as nothing more than a busy wait loop.

Any operating system textbook, such as "Modern Operating Systems" by Tanenbaum will cover this in great detail - pretty much any of them (even an old, cheap, used one).

Michael Burr
  • 333,147
  • 50
  • 533
  • 760
  • ahhh.. so its not guaranteed to wake up after the time out.. Its up to the scheduler or basically other tasks in the system...?? – FatDaemon Nov 12 '09 at 00:43
  • 3
    How soon after the timeout expires the task will get to run again is dependent on the scheduler. The system may guarantee that it'll run as soon as the timeout expires, but I think most will simply place it at the appropriate place in the ready-to-run queue (which might be at the front if the thread priority is greater than any other), adn it'll get run when it's next scheduled. – Michael Burr Nov 12 '09 at 00:46
  • Many embedded processors have a dedicated sleep instruction – mocj Nov 12 '09 at 02:20
  • @mocj -yes on re-reading, what I said about the idle thread wasn't as clear as I intended about halting the processor. I hope it's a little better now. – Michael Burr Nov 12 '09 at 06:01
  • It is guaranteed to NOT run until the timer is up. – Quinn Wilson Nov 12 '09 at 06:09
  • 2
    this misses a very important explanation : why the OS scheduler has CPU time to do queue manipulation in the first place ? Option 1 : because it wakes up at every kernel tick to update its logic. Option 2 : because it has setup a timer on the CPU that wakes the CPU and the OS up after the decided period of sleep time. (tickless kernels) – v.oddou Mar 26 '13 at 02:48
  • @v.oddou Can you elaborate on tickful vs tickless operations. I feel like that is the fundamental explanation of how sleep is actually implemented. – CMCDragonkai Jun 25 '16 at 03:00
  • 1
    @CMCDragonkai maybe start with doc about NOHZ http://lwn.net/Articles/549593/, Frederic Weisbecker material http://ertl.jp/~shinpei/conf/ospert13/slides/FredericWeisbecker.pdf, the timer wheel structure http://www.cs.columbia.edu/~nahum/w6998/papers/sosp87-timing-wheels.pdf, Windows 7 timer coalescing: http://download.microsoft.com/download/9/C/5/9C5B2167-8017-4BAE-9FDE-D599BAC8184A/TimerCoal.docx and google left and right from here ? – v.oddou Jun 27 '16 at 01:42
  • Pretty conclusive bunch of tests for FreeBSD done on this thread. we can see, with a low HZ resolution, the sleep functions behave poorly. http://lists.freebsd.org/pipermail/freebsd-java/2015-November/011312.html – v.oddou Jun 27 '16 at 01:56
3

The answer to your question is completely operating-system and implementation-dependent.

A simple way to think about it: When you call sleep(), the OS calculates the wakeup time, then sticks your process on a priority queue somewhere. It then just doesn't schedule your process to get any execution time until enough real time has passed for it to get popped off the queue.

Carl Norum
  • 219,201
  • 40
  • 422
  • 469
3

In a typical operating system, sleep calls into the kernel, which sets the process to wait until the specified amount of time is elapsed, and then goes and finds some other process to run. Absent anything better to do, it will run the 'idle process'. Once the time elapses, the scheduler will note that the sleeping process is good to go, and it will schedule it again.

bmargulies
  • 97,814
  • 39
  • 186
  • 310
  • Absolutely and it has to be noted that the Idle process is a process that runs the HLT instruction. In modern CPUs it gets very complex and depending on the period of sleep time it will go down to CN modes. (C0 awake, C1 short sleep,...C7 long sleep) – v.oddou Mar 26 '13 at 02:51
1

You don't do any while loops, otherwise the system won't be able to do anything - not respond to the mouse, keyboard, network, etc.

Usually what most operating systems do is you add the delay to the current timestamp to get the timestamp when the task that requested the delay will be resumed (assuming there is no higher priority task running at that time) and add the [wakeupTimestamp, task pointer] to a list that is sorted by ascending by the timestamp. After that, the OS performs a context switch and runs the next available task. Periodically, the system compares the earliest timestamp on the sleepy list with the current timestamp, and if the deadline has passed, it moves the sleeping task into the "ready" task queue.

florin
  • 13,986
  • 6
  • 46
  • 47
  • 2
    How come you say something intelligent in the second part and yet so stupid in the first part ? a while loop is preemptable and will not disrupt any mouse event whatsoever. – v.oddou Mar 26 '13 at 02:54
1

Sleep blocks your task/thread for the time value passed. Your task becomes un-runnable for that period or until something else interesting happens (like a signal), whichever is sooner.

It is not uncommon for sleep to call select() and pass no descriptors to wait on and a timeout value equal to your sleep period.

The system may implement this by setting a timer to expire after the time passed and then waiting on a semaphore that will be signalled when that timer expires. Thus it is blocked on that semaphore.

Southern Hospitality
  • 1,260
  • 1
  • 8
  • 12
1

cpu usage: 0%
requirements:
create_gate (Set up the IRQ handlers)
pic_mask_clear (Enable specific interrupts)
rtc_poll (Set up RTC)
rtc_irq
smp_wake_up

; In\   RAX = Time in millisecond
; Out\  All registers preserved
sleep:
    push rcx
    push rax

    mov rcx, [rtc_irq.up_time]
    add rax, rcx
.os_delay_loop:
    hlt
    cmp qword [rtc_irq.up_time], rax
    jle .os_delay_loop

    pop rax
    pop rcx
    ret

smp_wake_up

; In\   Nothing
; Out\  Nohting
smp_wakeup_all:
    push rdi
    push rax

    mov rdi, [os_LocalAPICAddress]
    xor eax, eax
    mov [rdi+0x0310], eax   ; Write to the high bits first
    mov eax, 0x000C0080 ; Execute interrupt 0x80
    mov [rdi+0x0300], eax   ; Then write to the low bits

    pop rax
    pop rdi
    ret

rtc_irq:

; UIP (0), RTC@32.768KHz (010), Rate@1024Hz (0110)
; In\   Nothing
; Out\  Nothing
rtc_irq:
    inc qword[.up_time]
    call smp_wakup_all
    ret
.up_time:       dq 0

usage :

mov rax, 1000 (millisecond)
call sleep

its fine

S.S. Anne
  • 15,171
  • 8
  • 38
  • 76
Mahdi Mohammadi
  • 239
  • 2
  • 7