Coder Perfect

Infinite slumber, Bash (infinite blocking)


To start X, I use startx, which evaluates my.xinitrc file. In my.xinitrc, I use /usr/bin/mywm to start my window manager. Now, if I kill my WM (for example, to test another WM), X will also shut down because the.xinitrc script has reached the end of its execution. As a result, I appended the following at the end of my.xinitrc:

while true; do sleep 10000; done

If I kill my WM, X will not terminate. Now here’s my question: instead of looping sleep, how can I perform an infinite sleep? Is there a command that will halt the script in some way?

Asked by watain

Solution #1

Sleep infinity accomplishes exactly what it says it will and does it without harming cats.

Answered by Donarsson

Solution #2

As usual, there is a response for everything that is simple, easy to comprehend, easy to follow, and absolutely incorrect. This is where tail -f /dev/null comes in handy;)

If you run strace tail -f /dev/null on it, you’ll see that this approach is far from blocking! It’s arguably much worse than the sleep answer in the question, because it consumes valuable resources such as the inotify system (under Linux). Other processes that write to /dev/null also cause a tail loop. (On my Ubuntu64 16.10 system, this adds several ten syscalls per second to a system that is already busy.)

Read: I’m not sure whether there’s a method to directly archive this with the shell.

Anything (even infinity slumber) can be disrupted by a signal. So, if you really want to make sure it doesn’t come back, you’ll have to run it in a loop, just like you did with your sleep. Please note that /bin/sleep on Linux appears to be limited to 24 days (see strace sleep infinite), thus the best you can probably do is:

while :; do sleep 2073600; done

(Note that I believe sleep loops internally for longer than 24 days, but this does not indicate it is blocking; rather, it is looping extremely slowly.) So why don’t we move this loop outside?)

As long as no signals are sent to the process, you can construct something that truly blocks. The following example employs bash 4, two PIDs, and one fifo:

bash -c 'coproc { exec >&-; read; }; eval exec "${COPROC[0]}<&-"; wait'

If you want, you can use strace to verify that this indeed blocks:

strace -ff bash -c '..see above..'

If there is no input data, read blocks (see some other answers). The tty (also known as stdin) is usually not a good source because it is closed when the user logs out. It’s also possible that it’ll take some input from the tty. It’s not nice.

We need to wait for anything like a fifo to return nothing before we can build a read block. Coproc is a command in Bash 4 that can provide us with exactly such a fifo. We’re done if we also wait for the blocked read (which is our coproc). Regrettably, this necessitates keeping two PIDs and a fifo open.

If you don’t want to use a named fifo, you can do it like this:

mkfifo "$HOME/.pause.fifo" 2>/dev/null; read <"$HOME/.pause.fifo"

It’s a little sloppy not to use a loop on the read, but you can reuse this fifo as many as you like and make the reads terminate with touch “$HOME/.pause.fifo” (if there are more than a single read waiting, all are terminated at once).

There is a Linux kernel method named pause() that performs exactly what we want: wait indefinitely (until a signal arrives). There is, however, no userspace program for this (yet).

It is simple to create such a program. Here’s a snippet for making a tiny Linux program called pause that pauses endlessly (requires diet, gcc, and other things):

printf '#include <unistd.h>\nint main(){for(;;)pause();}' > pause.c;
diet -Os cc pause.c -o pause;
strip -s pause;
ls -al pause

You can use this under Linux if you don’t want to compile things yourself but have Python installed:

python -c 'while 1: import ctypes; ctypes.CDLL(None).pause()'

(Note: To replace the current shell, use exec python -c…; this frees one PID.) The solution can also benefit from some IO redirection, which frees up unused FDs. This is entirely up to you.)

ctypes, I believe, is how this works. CDLL(None) loads the standard C library and calls the pause() function from it in a loop. It’s not as efficient as the C version, but it gets the job done.

Continue to sleep in a loop. It’s simple to use, portable, and blocks the majority of the time.

Answered by Tino

Solution #3

Perhaps this is unattractive, but why not just run cat and let it wait for input indefinitely?

Answered by MichaƂ Trybus

Solution #4

TL;DR: sleep infinite sleeps for the maximum amount of time permitted, which is finite.

I was curious as to why this wasn’t described anywhere, so I looked through the GNU coreutils files and discovered that it does something like this:

In the Linux kernel, this is TIME T MAX, which is defined as follows (time.h):

(time_t)((1UL << ((sizeof(time_t) << 3) - 1)) - 1)

It’s worth noting that time t is __kernel time t and time t is long; the LP64 data model is utilized, therefore sizeof(long) is 8. (64 bits).

TIME T MAX = 9223372036854775807 TIME T MAX = 9223372036854775807 TIME T MAX = 9223372036854

That is, if you sleep indefinitely, you will sleep for 9223372036854775807 seconds (1011 years). And 2147483647 seconds for 32-bit linux systems (sizeof(long) is 4 (32 bits)) (68 years; see also year 2038 problem).

Edit: it appears that the nanoseconds function is an OS-dependent wrapper rather than the syscall itself (also defined in gnulib).

As a result, when HAVE BUG BIG NANOSLEEP is true, the sleep is reduced to 24 days and then called in a loop for some systems. For certain (or all?) Linux distributions, this is the case. If a configure-time test succeeds, this wrapper may not be used (source).

That would be 24 * 24 * 60 * 60 = 2073600 seconds (plus 999999999 nanoseconds); however, this is called in a loop to ensure that the overall sleep time is respected. As a result, the prior conclusions hold true.

Finally, while the resulting sleep period is not limitless, it is sufficient for all practical purposes, even if the actual time lapse is not portable; this is dependent on the OS and architecture.

To answer the original question, this is obviously good enough but if for some reason (a very resource-constrained system) you really want to avoid an useless extra countdown timer, I guess the most correct alternative is to use the cat method described in other answers.

Instead of looping, recent GNU coreutils versions will try to use the pause syscall (if available). The previous argument is no longer valid when targeting these newer versions in Linux (and possibly BSD).

This is a serious and well-founded concern:

Answered by jp48

Solution #5

Sleep infinity appears to be the most elegant, but for some reason it does not always function. In that scenario, try blocking commands like cat, read, tail -f /dev/null, grep a, and so forth.

Answered by Hui Zheng

Post is based on