How does thread::sleep work?

I've always been curious as to how putting a thread to sleep works at the low level.

I've always imagined that it blocks the thread by running a loop for the specified amount of time, not letting the thread do any other work, but that would be ludicrous and still cause the CPU to do actual work.

I'm guessing it tells the Operating System to remove it from the schedule somehow? If that's the case then how does the Operating System handle it? Do runtimes that offer green threads would have to do this too?

The exact implementation depends on the OS, but the general idea is to loop until time runs out, and inside that loop use some sort of OS sleep primitive. In some situations, it makes the most sense to use a "yield" primitive which just gives control of the thread back to the OS kernel, but I think on mainstream OSs there actually are sleep primitives to use. It doesn't just call the sleep syscall as they usually won't guarantee it sleeps for the full amount of time, only that it sleeps some amount between 0ms and the full amount.

For example, here's the implementation of sleep on *unix systems, from https://doc.rust-lang.org/src/std/sys/unix/thread.rs.html#165-187 :

    pub fn sleep(dur: Duration) {
        let mut secs = dur.as_secs();
        let mut nsecs = dur.subsec_nanos() as _;

        // If we're awoken with a signal then the return value will be -1 and
        // nanosleep will fill in `ts` with the remaining time.
        unsafe {
            while secs > 0 || nsecs > 0 {
                let mut ts = libc::timespec {
                    tv_sec: cmp::min(libc::time_t::max_value() as u64, secs) as libc::time_t,
                    tv_nsec: nsecs,
                };
                secs -= ts.tv_sec as u64;
                if libc::nanosleep(&ts, &mut ts) == -1 {
                    assert_eq!(os::errno(), libc::EINTR);
                    secs += ts.tv_sec as u64;
                    nsecs = ts.tv_nsec;
                } else {
                    nsecs = 0;
                }
            }
        }
    }
1 Like

Curious question.

At the bottom of the stack of kernel, operating system, application, if all processes are sleeping, waiting for some time to pass or for some external input, then we would like the CPU to basically stop. Thus saving power consumption. Rather than having it thrashing around in a loop, checking the time and polling for inputs.

To that end, processors have a "wait for interrupt" instruction that causes the CPU to basically stop until an interrupt comes in from a timer or some I/O device. On Intel machines this is the "HLT" or halt instruction. https://en.wikipedia.org/wiki/HLT_(x86_instruction)

Without that simple instruction in the hardware of your computer it would be running around all the time with a 100% CPU load, doing nothing!

As for "green threads", the OS knows nothing of those, but when they have nothing to do they end up sleeping the real thread they run on. Which might end up hitting the same HLT instruction if there is not much else going on with the machine.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.