What's the algorithm behind sleep()?

后端 未结 8 1904
灰色年华
灰色年华 2020-12-07 16:36

Now there\'s something I always wondered: how is sleep() implemented ?

If it is all about using an API from the OS, then how is the API made ?

Does it all bo

8条回答
  •  爱一瞬间的悲伤
    2020-12-07 17:15

    glibc 2.21 Linux

    Forwards to the nanosleep system call.

    glibc is the default implementation for the C stdlib on most Linux desktop distros.

    How to find it: the first reflex is:

    git ls-files | grep sleep
    

    This contains:

    sysdeps/unix/sysv/linux/sleep.c
    

    and we know that:

    sysdeps/unix/sysv/linux/
    

    contains the Linux specifics.

    On the top of that file we see:

    /* We are going to use the `nanosleep' syscall of the kernel.  But the
       kernel does not implement the stupid SysV SIGCHLD vs. SIG_IGN
       behaviour for this syscall.  Therefore we have to emulate it here.  */
    unsigned int
    __sleep (unsigned int seconds)
    

    So if you trust comments, we are done basically.

    At the bottom:

     weak_alias (__sleep, sleep)
    

    which basically says __sleep == sleep. The function uses nanosleep through:

    result = __nanosleep (&ts, &ts);
    

    After greppingg:

    git grep nanosleep | grep -v abilist
    

    we get a small list of interesting occurrences, and I think __nanosleep is defined in:

    sysdeps/unix/sysv/linux/syscalls.list 
    

    on the line:

    nanosleep   -   nanosleep   Ci:pp   __nanosleep nanosleep
    

    which is some super DRY magic format parsed by:

    sysdeps/unix/make-syscalls.sh
    

    Then from the build directory:

    grep -r __nanosleep
    

    Leads us to: /sysd-syscalls which is what make-syscalls.sh generates and contains:

    #### CALL=nanosleep NUMBER=35 ARGS=i:pp SOURCE=-
    ifeq (,$(filter nanosleep,$(unix-syscalls)))
    unix-syscalls += nanosleep
    $(foreach p,$(sysd-rules-targets),$(foreach o,$(object-suffixes),$(objpfx)$(patsubst %,$p,nanosleep)$o)): \
            $(..)sysdeps/unix/make-syscalls.sh
        $(make-target-directory)
        (echo '#define SYSCALL_NAME nanosleep'; \
         echo '#define SYSCALL_NARGS 2'; \
         echo '#define SYSCALL_SYMBOL __nanosleep'; \
         echo '#define SYSCALL_CANCELLABLE 1'; \
         echo '#include '; \
         echo 'weak_alias (__nanosleep, nanosleep)'; \
         echo 'libc_hidden_weak (nanosleep)'; \
        ) | $(compile-syscall) $(foreach p,$(patsubst %nanosleep,%,$(basename $(@F))),$($(p)CPPFLAGS))
    endif
    

    It looks like part of a Makefile. git grep sysd-syscalls shows that it is included at:

    sysdeps/unix/Makefile:23:-include $(common-objpfx)sysd-syscalls 
    

    compile-syscall looks like the key part, so we find:

    # This is the end of the pipeline for compiling the syscall stubs.
    # The stdin is assembler with cpp using sysdep.h macros.
    compile-syscall = $(COMPILE.S) -o $@ -x assembler-with-cpp - \
                       $(compile-mkdep-flags)
    

    Note that -x assembler-with-cpp is a gcc option.

    This #defines parameters like:

    #define SYSCALL_NAME nanosleep
    

    and then use them at:

    #include 
    

    OK, this is as far as I will go on the macro expansion game for now.

    I think then this generates the posix/nanosleep.o file which must be linked together with everything.

    Linux 4.2 x86_64 nanosleep syscall

    Uses the scheduler: it's not a busy sleep.

    Search ctags:

    sys_nanosleep
    

    Leads us to kernel/time/hrtimer.c:

    SYSCALL_DEFINE2(nanosleep, struct timespec __user *, rqtp,
    

    hrtimer stands for High Resolution Timer. From there the main line looks like:

    • hrtimer_nanosleep
    • do_nanosleep
      • set_current_state(TASK_INTERRUPTIBLE); which is interruptible sleep
      • freezable_schedule(); which calls schedule() and allows other processes to run
    • hrtimer_start_expires
    • hrtimer_start_range_ns
    • TODO: reach the arch/x86 timing level
    • TODO: are the above steps done directly in the syscal call interrupt handler, or in a regular kernel thread?

    A few articles about it:

    • https://geeki.wordpress.com/2010/10/30/ways-of-sleeping-in-linux-kernel/
    • http://www.linuxjournal.com/article/8144

提交回复
热议问题