Matteo Croce personal homepage

pause on ARM

I was tracing some syscalls to check when and how the sleep command was being executed.

I was expecting to see a call to clock_nanosleep, but instead I found a call to ppoll(NULL, 0, NULL, NULL, 0), so I got curious.
I filtered the running processes and I’ve found sleep inf running, so I’ve discovered that sleep supports the “inf” argument to sleep indefinitely.
This was not documented in the man page, so I looked at sleep source code to know more, but in the code there were no references to the “inf” syntax, so I got even more curious.

I realized the sleep uses strtod to parse its arguments which, according to its man page, parses the “INF” or “INFINITY” string as the IEEE 754 special value for positive infinite (which is 0x7ff0000000000000, btw).
This value is passed to an internal helper called xnanosleep, which detects the infinite value and calls pause() to sleep forever.
This is a very smart wat to sleep indefinitely, instead of using a loop to call sleep in a cycle.

But why ppoll was being called instead of pause? Obviously, the result is the same, but why don’t just call pause directly?
So I wrote this small tool to see what syscall was effectively being called:

#include <unistd.h>

int main(void)
{
	pause();

	return 0;
}

The answer is: depends on the architecture. This happens on an ARM machine:

$ strace -e clock_nanosleep,ppoll,pause ./pause
ppoll(NULL, 0, NULL, NULL, 281473054674784

and this on an x86 machine:

$ strace -e clock_nanosleep,ppoll,pause ./pause
pause(

A quick look at the kernel syscall source shows that pause is available on architectures that define __ARCH_WANT_SYS_PAUSE, which is set for i386 and arm but not arm64.
So, the ppoll call is a fallback for architectures that don’t have the pause syscall, like arm64.

#Linux #Arm