[LINUX] What is the difference between usleep, nanosleep and clock_nanosleep?

Introduction

There are many sleep functions in C language, right? Often I don't know where to use what. That said, you can't be a true C programmer if you choose the sleep function properly. C programmers have a mission to choose the best of many options and deliver unrivaled performance.

Leave the joke aside

In this article, I will write about the difference between usleep, nanosleep, and clock_nanosleep, which can realize highly accurate sleep processing.

The target Linux kernel version is ** 5.4.2 **.

First conclusion

After this section, I will read the source code of the Linux kernel, but I do not know that, so for those who want to give a conclusion quickly, I will write the conclusion first.

How, these three functions do *** almost the same behavior ***!

Only clock_nanosleep can change its behavior depending on the argument, but if you pass CLOCK_MONOTONIC as the first argument of clock_nanosleep, the behavior of the three functions will be the same.

However, each of these functions has different usability. It seems best to use a function that is easy to call in each situation. If you want to make sure that they match at the source code level, see the following sections.

What kind of function is it in the first place?

Let's see what kind of functions usleep, nanosleep, and clock_nanosleep are. This information is taken from man's Linux Programmer's Manual.

usleep usleep --Defer execution in microseconds

#include <unistd.h>
int usleep(useconds_t usec);

nanosleep nanosleep-high precision sleep

#include <time.h>
int nanosleep(const struct timespec *req, struct timespec *rem); 

clock_nanosleep clock_nanosleep --Precise stop (sleep) at the specified clock

#include <time.h>
int clock_nanosleep(clockid_t clock_id, int flags,
                    const struct timespec *request,
                    struct timespec *remain);

Well, what I want to do is almost the same. I want to sleep at the nanosecond level.

System call or library function

Next, I would like to classify each function by system call or library function. (Well, system calls are also provided by the library side to wrap the assembler, but here we classify them according to whether they are defined as system calls in the Linux kernel or not.)

usleep nanosleep clock_nanosleep
Library function System call System call

It looks like this.

Now let's look at each function at the source code level.

Read and see the source code

usleep

Now let's look at the definition of usleep.

usleep is a function defined by glibc and is not a Linux system call. You can then expect usleep to be calling a system call to do sleep in that function. When I actually looked into the source code of glibc, it was as follows.

https://github.com/lattera/glibc/blob/master/sysdeps/posix/usleep.c

int
usleep (useconds_t useconds)
{
  struct timespec ts = { .tv_sec = (long int) (useconds / 1000000),
			 .tv_nsec = (long int) (useconds % 1000000) * 1000ul };

  /* Note the usleep() is a cancellation point.  But since we call
     nanosleep() which itself is a cancellation point we do not have
     to do anything here.  */
  return __nanosleep (&ts, NULL);
}

Looking at this source code and comments, usleep seems to be calling the nanosleep system call. In other words *** glibc "Isn't it troublesome to create a timespec structure for the argument of nanosleep? I defined a wrapper function" *** It is defined as such. Therefore, it can be said that usleep is a function that receives microseconds, creates a timespec structure based on it, and finally calls the nanosleep system call. For now, I know that usleep and nanosleep will behave similarly.

nanosleep Since nanosleep is a Linux system call, we will read the source code of the Linux kernel. nanosleep is defined as a system call /kernel/time/hrtimer.c line:1945 https://elixir.bootlin.com/linux/v5.4.2/source/kernel/time/hrtimer.c#L1945 is.

SYSCALL_DEFINE2(nanosleep, struct __kernel_timespec __user *, rqtp,
		struct __kernel_timespec __user *, rmtp)
{
	struct timespec64 tu;

	if (get_timespec64(&tu, rqtp))
		return -EFAULT;

	if (!timespec64_valid(&tu))
		return -EINVAL;

	current->restart_block.nanosleep.type = rmtp ? TT_NATIVE : TT_NONE;
	current->restart_block.nanosleep.rmtp = rmtp;
	return hrtimer_nanosleep(&tu, HRTIMER_MODE_REL, CLOCK_MONOTONIC);
}

You can finally see that we are calling a function called hrtimer_nanosleep. This function is a function that performs sleep processing using a high-precision timer called High Resolution Timer. CLOCK_MONOTONIC is passed as the third argument of the hrtimer_nanosleep function. Oh, this should have been a constant that could also be passed to clock_nanosleep. Now that I've smelled something, let's take a look at the implementation of the clock_nanosleep system call.

clock_nanosleep Finally, read the source code of clock_nanosleep. This system call /kernel/time/posix-stubs.c line: 124 https://elixir.bootlin.com/linux/v5.4.2/source/kernel/time/posix-stubs.c#L124 It is defined in.

SYSCALL_DEFINE4(clock_nanosleep, const clockid_t, which_clock, int, flags,
		const struct __kernel_timespec __user *, rqtp,
		struct __kernel_timespec __user *, rmtp)
{
	struct timespec64 t;

	switch (which_clock) {
	case CLOCK_REALTIME:
	case CLOCK_MONOTONIC:
	case CLOCK_BOOTTIME:
		break;
	default:
		return -EINVAL;
	}

	if (get_timespec64(&t, rqtp))
		return -EFAULT;
	if (!timespec64_valid(&t))
		return -EINVAL;
	if (flags & TIMER_ABSTIME)
		rmtp = NULL;
	current->restart_block.nanosleep.type = rmtp ? TT_NATIVE : TT_NONE;
	current->restart_block.nanosleep.rmtp = rmtp;
	return hrtimer_nanosleep(&t, flags & TIMER_ABSTIME ?
				 HRTIMER_MODE_ABS : HRTIMER_MODE_REL,
				 which_clock);
}

This function first looks at the specified clockid. Other than CLOCK_REALTIME, CLOCK_MONOTONIC, CLOCK_BOOTTIME, it seems that an error will occur. After reading, ***, except for the flags check, it does almost the same as the definition of the nanosleep system call we saw in the previous section. *** ***

For the time being, the description is different from nanosleep

flags & TIMER_ABSTIME ?
                 HRTIMER_MODE_ABS : HRTIMER_MODE_REL

I will explain this part briefly as well. flags are flags that can be passed to the clock_nanosleep system call. If *** TIMER_ABSTIME *** is set for this flag, HRTIMER_MODE_ABS will be passed to the *** hrtimer_nanosleep *** function if it is not set. According to man's description, if you specify the *** TIMER_ABSTIME *** flag,

** If flags is TIMER_ABSTIME, the remain argument is not used and is not needed (stopping at an absolute value can be called again with the same request argument). ** **

is what they said. In other words, I found that this process was added to handle the clock_nanosleep flag.

Conclusion after reading the source code

I've said the conclusion above, but apparently these three functions behave in much the same way. In other words, each method ultimately calls the hrtimer_nanosleep function, and the process of determining the arguments to pass to that function is different. If I force you to make a difference, I think it's that flexibility. usleep and nanosleep can only use CLOCK_MONOTONIC as a sleep flag, but clock_nanosleep can be freely decided by the programmer.

in conclusion

The conclusion was that there wasn't much difference in the end, but an open source culture was essential to reach this conclusion. The best open source, I hope that free software will continue to develop!

Recommended Posts

What is the difference between usleep, nanosleep and clock_nanosleep?
What is the difference between `pip` and` conda`?
What is the difference between Unix and Linux?
What is the difference between a symbolic link and a hard link?
About the difference between "==" and "is" in python
[Introduction to Python] What is the difference between a list and a tuple?
Difference between == and is in python
[Introduction to Infectious Disease Models] What is the difference between the April epidemic and this epidemic? .. .. ‼
The answer of "1/2" is different between python2 and 3
About the difference between PostgreSQL su and sudo
Consideration of the difference between ROC curve and PR curve
The rough difference between Unicode and UTF-8 (and their friends)
Can BERT tell the difference between "candy (candy)" and "candy (rain)"?
How to use argparse and the difference between optparse
Difference between process and job
What is the Linux kernel?
Difference between regression and classification
[Python] Python and security-① What is Python?
Difference between np.array and np.arange
Difference between MicroPython and CPython
What is the interface for ...
What is the Callback function?
Difference between ps a and ps -a
Difference between return and print-Python
Understand the difference between cumulative assignment to variables and cumulative assignment to objects
Difference between SQLAlchemy back_populates and backref and when neither is used
The difference between foreground and background processes understood by the principle
Difference between Ruby and Python split
Difference between java and python (memo)
Memorandum (difference between csv.reader and csv.dictreader)
[Python] What is @? (About the decorator)
(Note) Difference between gateway and default gateway
[python] What is the sorted key?
Difference between Numpy randint and Random randint
Difference between sort and sorted (memorial)
Difference between python2 series and python3 series dict.keys ()
What is the X Window System?
What is the python underscore (_) for?
I investigated the behavior of the difference between hard links and symbolic links
[Python] Difference between function and method
Difference between SQLAlchemy flush () and commit ()
[Python] Comprehension notation. Write a for statement simply. (A collection is the difference between an iterator and an iterator)
Python --Difference between exec and eval
[Python] Difference between randrange () and randint ()
[Python] Difference between sorted and sorted (Colaboratory)
[Xg boost] Difference between softmax and softprob
difference between statements (statements) and expressions (expressions) in Python
[Django ORM] Difference between values () and only ()
Difference between PHP and Python finally and exit
What is the ETL processing framework clivoa?
[Unix] What is the zombie process / orphan process?
Difference between @classmethod and @staticmethod in Python
What is the cause of the following error?
Difference between append and + = in Python list
Difference between nonlocal and global in Python
Difference between linear regression, Ridge regression and Lasso regression
What is "mahjong" in the Python library? ??
[Python] Difference between class method and static method
Difference between docker-compose env_file and .env file
The subtle relationship between Gentoo and pip
About the relationship between Git and GitHub