memo2005 has asked for the wisdom of the Perl Monks concerning the following question:

Please open a file named "my_program", and write three lines into it:
#!/usr/bin/perl -w print STDERR "$$\n"; `./my_program`;
Now open bash and execute command:
(ulimit -u150; ./my_program)
Could you please tell why this program hangs quite _often_ (not always...)? How to make it _always_ fail when number of processes reaches 150...?
My system is:
Debian GNU/Linux, 2.6.18-iplus #1 SMP Wed Dec 12 14:35:52 CET 2007 i68 +6 GNU/Linux perl, v5.8.8 built for i486-linux-gnu-thread-multi
My opinion is that perl waits for child to finish, but it didn't even start, and I don't see any solutions...

Replies are listed 'Best First'.
Re: Ulimit makes program hang
by Bloodnok (Vicar) on Aug 13, 2008 at 12:53 UTC
    Try putting a sleep in before shelling out - that way the scheduler should get time... e.g.
    #!/usr/bin/perl -w print STDERR "$$\n"; sleep 1; `./my_program`;
    HTH ,

    A user level that continues to overstate my experience :-))
      Unfortunatelly sleeping doesn't solve the problem.

      I have tested all more throughly and modified program:
      #!/usr/bin/perl -w my $x = $ARGV[0] + 1; print STDERR "$x\n"; `./my_program $x`;

      Now I ran commands:
      (ulimit -u100; ./my_program) (ulimit -u50; ./my_program) (ulimit -u20; ./my_program)

      The first one hang on 95-th iteration. The second hang on 45-th iteration. The third one hang on 15-th iteration. So wen you set maximum number or processes to N (ulimit -u<N>), then program hangs on N-5 iteration.
      I want that program to fail (return nonzero code) when no processes are available...

        ulimit sets the maximum number of process that your user can run. Since you are likely to be running some other processes (for instance, your shell), it comes as no surprise that there are fewer "slots" available for other processes.

        --
        David Serrano

        Hi ,

        I strongly suspect that, if you re-insert the sleep before shelling out, your results will be modified since the perl process won't otherwise have enough time to complete the print.

        Have you tried the fork/exec approach ?

        Have you tried an even lower limit and running the program using truss (or is it strace on linux) ?

        As an afterthought, I do wonder if you've uncovered a bug in perl...

        A user level that continues to overstate my experience :-))
Re: Ulimit makes program hang (bug)
by tye (Sage) on Aug 13, 2008 at 16:19 UTC

    This looks like a bug in Perl. It would be nice if people with similar systems and perls could validate or refute your results so we can narrow down where this problem occurs (use a much smaller -u to make it easy reproduce). Perl should report a failure to fork(), not hang.

    - tye        

      I don't think it's a bug. The fork() doesn't fail - the fork() is blocked. (Or rather, fork(1) fails, setting errno to EAGAIN).

      You can easily test it. Copy the program, so you have foo calling itself and bar calling itself. Now do from on shell:

      (ulimit -u 50 ./foo)
      This will print a bunch of pids, and the program "hangs". Now from another shell do:
      (ulimit -u 60 ./bar)
      This will print 10 or less pids, and it hangs. Go back to the first window, kill the program, and issue a killall foo (or whatever is the equivalent on your system). Watch the output of the bars.

      When reaching the maximum amount of processes set by ulimit, fork() blocks till another slot becomes available.

        So it isn't a bug in Perl but a change in behavior based on operating system (or some other environmental detail)? My prior experience shows fork failing due to ulimit and other examples in the thread show this behavior as well. Thanks for the insight.

        - tye        

      It would seem so. I run the script under strace and found that the qx op doesn't use fork syscall on my perl (Ubuntu Hardy), but clone syscall:

      • A working qx...
        21696 clone(child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETT +ID|SIGCHLD, child_tidptr=0x7f6015248770) = 21697 21697 close(5) = 0 21697 fcntl(6, F_SETFD, FD_CLOEXEC) = 0 21697 dup2(4, 1) = 1 21697 close(4) = 0 21697 close(3) = 0 21697 rt_sigaction(SIGFPE, {SIG_DFL}, {SIG_IGN}, 8) = 0 21697 execve("./my_program", ["./my_program"], [/* 11 vars */] <unfini +shed ...>
      • A non-working one...
        21742 clone(child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETT +ID|SIGCHLD, child_tidptr=0x7f4143c25770) = -1 EAGAIN (Resource tempor +arily unavailable) 21742 rt_sigprocmask(SIG_BLOCK, [CHLD], [], 8) = 0 21742 rt_sigaction(SIGCHLD, NULL, {SIG_DFL}, 8) = 0 21742 rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0 21742 nanosleep({5, 0}, <unfinished ...>

      The problem is that the nanosleep syscall should not be happening.

Re: Ulimit makes program hang
by massa (Hermit) on Aug 13, 2008 at 16:35 UTC
    You are suffering from buffering somewhere. I did:
    #!/usr/bin/perl -wl select STDERR; $|=1; print $$; sleep 1; print qx(./theProgram);
    and it worked as expected.
    []s, HTH, Massa (κς,πμ,πλ)
      This program hangs also. The effect is exactly the same as mine program.