5

I run the following command in a freshly started bash (without any prior child processes)

$ prlimit --pid $BASHPID --nproc=20:

which gives me an avalanche of

bash: fork: retry: No child processes
bash: fork: retry: No child processes
bash: fork: retry: No child processes
bash: fork: retry: No child processes
bash: fork: Resource temporarily unavailable

I wonder is 20 to low a number, or is the procedure wrong? What is going on here?

I know that bash has an internal builtin ulimit call, yet why would not prlimit work

update#

also bash builtin ulimit yields the same result

$ ulimit -Su 20
bash: fork: retry: No child processes
bash: fork: retry: No child processes
bash: fork: retry: No child processes
bash: fork: retry: No child processes
bash: fork: Resource temporarily unavailable
bash: wait_for: No record of process 7527
bash: fork: retry: No child processes
bash: fork: retry: No child processes

An answer to this question might be related to how the ulimit RLIMIT_NPROC is to be understood. It seems to be both UID but also PID bound?

Maybe somebody would also be able to give insight to what distinguishes the two different error messages No child processes and Resource temporarily unavailable

  • 1
    What's the output of ps -U yourusername | wc -l ? – Mark Plotnick Aug 13 '16 at 14:42
  • @MarkPlotnick good hint! Indeed that matters much. I thought the limit tracked child processes, while instead RLIMIT_NPROC value seems to set per UID not per PID values, true. Hence if I set this 20 processes than this is only possible if I have still less than 20 processes running, true. Do you have an idea why the message then did tell No child processes? – humanityANDpeace Aug 13 '16 at 14:58
  • @MarkPlotnick I did rather some ps m -ef | grep username | wc -l because the ulimit is relative to threads not processes, thanks! – humanityANDpeace Aug 13 '16 at 15:14
6

You've misunderstood how the process limit works. prlimit --nproc a.k.a. RLIMIT_NPROC a.k.a. ulimit -u is the maximum number of processes¹ for the user as a whole. If you already have 20 processes running, and you set the limit to 20, you can't create any new process. What matters is how many processes are running as your user, it doesn't matter who their parent is or what their limit setting is.

The subtlety is that while the limit is global, it only applies to the processes where it's set. So if you have 18 processes running and you run prlimit --nproc 20 bash in one terminal and prlimit --nproc 30 bash in another terminal, the first bash is unable to create any subprocesses, but the second one can create some more, until there's a total of 30 (whether they've been started from that bash or not).

If you set the limit to 1 for a process, then that process can't fork at all, but other processes can still fork. If you set the limit to a number in your login scripts, then that number applies to your processes (except ones started without reading your login scripts, e.g. from a cron job). Other cases can get confusing.

It's easiest to describe this from an implementation point of view. The limit is only read when executing the fork system call¹. When a process calls fork, the kernel counts the number R of processes are running as the same user. If the calling process's NPROC limit is less or equal to R then the call is rejected with the error EAGAIN (“resource temporarily unavailable”, i.e. “try again”).

In your case, you probably already have at least 20 processes running, and your .bashrc runs several subprocesses (or rather, fails to run them because the process limit has been reached).

You see two different messages because bash tries to fork several times when the error is EAGAIN. The first times it displays a message to say that it's retrying, and finally it displays a message to say that it's given up.

¹ More precisely, kernel threads.
² This system call is called clone on Linux.

| improve this answer | |
  • Thanks for pointing out the matter of the different error messages, what I was also wondering about in the question, very detailed answer at that point (and just to be complete, the message text is a perror derived thing, or does bash provide it, moreover (if you can maybe tell) does the kernel do this "giving up retrying" and sends a different error, or the bash shell?) – humanityANDpeace Aug 14 '16 at 8:26
  • @humanityANDpeace The retries are a bash thing. Try this in other shells, you'll see that they behave a bit differently, e.g. zsh only tries once and ksh tries forever. – Gilles 'SO- stop being evil' Aug 14 '16 at 9:34
1

Bottom line has been that -nproc sets the limit for runnable items (that is threads and processes and due to my bloated .bashrc stuff there are have been more than 20 threads necessary, at least that is my assumption since

after starting a new bash like this

$ bash --noprofile --norc

this was possible

bash-4.3$ ulimit -Su 1
bash-4.3$ echo 1
1
bash-4.3# echo 1 &
bash: fork: retry: No child processes

that is that one thread was sufficient, wow!

| improve this answer | |
  • The limit is indeed for kernel threads rather than processes, but it's likely that in all your testing, you only ran processes that have a single thread. The explanation has nothing to do with threads. When you set the limit to 1, the process can't fork since the limit is already reached. – Gilles 'SO- stop being evil' Aug 13 '16 at 21:23

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.