On 3/1/22 10:39 AM, Denys Vlasenko wrote:
> On Tue, Feb 15, 2022 at 12:31 PM Rob Landley <[email protected]> wrote:
>> On 2/14/22 10:09 AM, Roberto A. Foglietta wrote:
>> >  However, if this bug shows-up, probably it means that the system has
>> > a lot of processes running and a lot of processes created and
>> > destroyed compared to the max PID available. Thus, the system might be
>> > incorrectly configured compared with its typical usage which probably
>> > is the main reason because nobody complained before.
>>
>> Nah, a shell script can spin through an awful lot of PIDs pretty fast, and if
>> you're doing a -j 8 build that has a lot of script snippets (let alone 
>> parallel
>> autoconf etc) vs something with say a 10 second timeout?
> 
> I try the below and it seems to be able to spawn "only"
> ~1500 processes/second.

Let's see, off the top of my head...

1) make -j 8

2) Not all wrapper variants ala system() and ccache and friends will exec()
without a fork().

3) the default /proc/sys/kernel/pid_max is only 32768, 10 second timeout would
see a wrap at 1.5k/sec.

4) my laptop has about 500 persistent processes running right now and isn't
really busy: the system can only recycle the free ones.

5) Containers tend to have a small PID budget since each container PID is mapped
to a host PID (https://kubernetes.io/docs/concepts/policy/pid-limiting/)...

6) Some of those short-lived processes may be threaded, does TID count as using
a PID? (I honestly don't know how that maps these days: cat
/proc/sys/kernel/threads-max is 127327 WHILE pid_max is 32768?)

> $ time sh -c 'i=30000; while test $((--i)) != 0; do sleep 0 & done 
> 2>/dev/null'
> real    0m19.190s
> user    0m23.062s
> sys    0m6.732s
> 
> My memory is hazy on this, but IIRC kernel also actually has some
> defensive code to not immediately reuse pids which just died.

Other than zombie processes? Isn't it just LRU cycling through them in order? It
won't reuse a PID that's still active (open filehandle and such) but once it's
gone it forgets about it.

It's hard to tell what kernel/pid.c is doing these days with all the namespace
stuff in there, but the idr_alloc_cyclic() call just takes pid_min and pid_max
as arguments...?

Are you thinking of SO_REUSEADDR perhaps?

> It's interesting to find out why pids are reused that fast on the
> affected system.

The list above is not remotely exhaustive, it's just what came to mind. I have
no idea what horrific combination of systemd and ruby might decide to spawn a
process to handle every dbus event or run an RPC service via inetd, but I try
not to assume it won't happen either. (I never know what ELSE the system is
doing...)

> Meanwhile: what "timeout" is doing is it tries to get out
> of the way of the PROG to be launched so that timeout's parent
> sees PROG (not timeout) as a child. E.g. it can send signals
> to it, get waitpid notifications if PROG has been stopped
> with a signal, and such.

Is that how any other timeout works? On devuan:

$ timeout 100 /bin/bash
$ ps $PPID
  PID TTY      STAT   TIME COMMAND
28825 pts/19   S      0:00 timeout 100 /bin/bash

Or for that matter:

$ sudo /bin/bash
# ps $PPID
  PID TTY      STAT   TIME COMMAND
28690 pts/19   S      0:00 sudo /bin/bash

A lot of commands like env/nohup/chroot/linux64 exec their arguments, but that's
because they do a thing up front to modify the process context and are then
done. There's no "env process" lying around monitoring the child because there's
nothing for it to do. When there IS something left to do:

$ strace /bin/bash 2>/dev/null
ps $PPID
  PID TTY      STAT   TIME COMMAND
29428 pts/19   S+     0:00 strace /bin/bash

It's generally gonna stay the parent because the parent/child process
relationship with zombie sigchild delivery is the traditional unix mechanism to
avoids PID reuse races.

> And PROG also has no spurious "timeout" child.
> "timeout" exists as an orphaned granchild.
> 
> Let's go with a solution with fd opened to /proc/PID?

*shrug* I leave you to it. Not what I did:

https://github.com/landley/toybox/blob/master/toys/other/timeout.c

Let's hold our nose and see what coreutils did...

https://github.com/coreutils/coreutils/blob/master/src/timeout.c

Looks like fork(), execvp(), and waitpid(). Standard parent/child relationship.

Rob
_______________________________________________
busybox mailing list
[email protected]
http://lists.busybox.net/mailman/listinfo/busybox

Reply via email to