Beefy Boxes and Bandwidth Generously Provided by pair Networks
There's more than one way to do things
 
PerlMonks  

Killing wayward children

by SpaceAce (Beadle)
on Nov 17, 2002 at 12:27 UTC ( [id://213546]=perlquestion: print w/replies, xml ) Need Help??

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

Har.

A program I am working on uses a control panel setup for operation. Everything is done with buttons in a form. When the main portion of the program is executed, it forks off and operates in the background. You can monitor its progress by viewing a log file it creates as it goes.

Now, the background process can take anywhere from a handful of seconds to quite a few minutes to complete. I want add a way for users to kill the background process if they need to. Currently, I have the process write it's PID to a file (which doubles as a lock to prevent multiple instances of the program from being run at the same time). So, when a user wants to stop the process, the control panel portion of the script can get the PID out of the file and kill it. The problem is, I want to be able to get the process name of PID xxx so I can have the script check and be sure that pid xxx is what it should be. I don't want to have someone click the "kill" button a week after the script has stopped and kill some other process that just happens to share the same number (of course, the script deletes the lock/PID file when it finishes so this shouldn't happen, but just in case...). I want to do this using PERL functions, if possible. I don't want to make system calls to ps or anything like that if I can avoid it, but that's what my searches keep turning up.

I know that there are a lot of factors conspiring against me accidentally killing off the wrong process, but I suffer from paranoia. I don't like to leave anything to chance. I'd appreciate it if someone can point me in the right direction.

Thanks,
SpaceAce

Replies are listed 'Best First'.
Re: Killing wayward children
by Zaxo (Archbishop) on Nov 17, 2002 at 12:36 UTC

    You could kill INT, $pid; which is like hitting Ctrl-C. If the child is already gone, the signal will not be delivered to an unrelated process with the same pid. That shouldn't be a problem, anyway, if you are handling SIGCHLD.

    Update: Re diotalevi's question, kill fails with EPERM if the real or effective uid of the sender is not root or the same as that of the $pid addressed. See 'man 2 kill'. It is true that one of the user's own processes could reacquire the child pid. That is why the SIGCHLD handler should arrange to note the death of $pid, so the issue of misdelivery never comes up.

    After Compline,
    Zaxo

      Color me confused. So of the two parts, delivery and execution let me know where I'm off base. Does the INT not get sent to the non-child PID or is the INT somehow not honored by the non-child of the same pid? And how is this different from using kill(1) from the command line where it doesn't matter whether the process is a child or not. I did a quick read of kill from perlfunc and Signals from perlipc and I didn't see anything about INT not being sent to non-child processes. So what's the scoop here, how did you come up with that?

      Update: then I wasn't wrong. Unstated was the assumption that normal user control functions so you can only kill your own processes. It's just unlikely that a given user ends up with another process at the same UID, not actually prohibited some how.

      __SIG__ use B; printf "You are here %08x\n", unpack "L!", unpack "P4", pack "L!", B::svref_2object(sub{})->OUTSIDE;
      That sounds about like what I'm looking for. Thanks.

      SpaceAce
      s>>sp>;s>..|>\u$&ace>g;print;

Re: Killing wayward children
by robartes (Priest) on Nov 17, 2002 at 14:22 UTC
    I'm with diotalevi on this one. kill INT, $pid will send the INT signal to the process with $PID, regardless of whether or not said process is a child of the process sending the signal. However, if the sending process is not running as root, the chances of actually interrupting another process with this are lessened because i) there needs to be a process with $PID, which with current 32-bit process ID spaces tends to take a while and ii) said process needs to be running under the same UID as the sending process. However, it is still not a chance one should take in production environments. Hence:

    To check whether your $PID is still the correct process, have a look at Proc::ProcessTable to browse throught the process table. This will give you a way to check whether process $PID is still the correct one:

    use strict; use Proc::ProcessTable; my $table=Proc::ProcessTable->new; my @procs=$table->table; foreach $p ($table->table) { if ($p->pid == $saved_pid) { send_signal() if ($p->cmdline eq "expected command line"); } } #Warning: code is utterly untested and not the most efficient either.

    CU
    Robartes-

Re: Killing wayward children
by pg (Canon) on Nov 17, 2002 at 21:56 UTC
    Why not use process group id? When you fork a child process, the child process inherits the process group id. We have getpgrp func to find out the process grp id of a process id, and just don't kill it, if it has a different process grp id. There also a func to set process group id.
Re: Killing wayward children
by SpaceAce (Beadle) on Nov 19, 2002 at 07:38 UTC
    Much of the confusion is my fault.

    1) I may not have made it clear that the control panel is not a constant process. It is web-based and every function you execute through the control panel is going to be a new process which will die and return the user to the control panel HTML page after it is done doing what it does. So, unless I am mistaken, the process created when a user hits the "Halt script" button would not be the parent of the child process, anyway.

    2) I misunderstood the first answer given. It's a useful place for me to start doing some reading but it won't solve the problem I am currently dealing with.

    I think checking the process group ID is the way for me to go. I don't want to anything to break the program for ActivePerl (I develop using Perl 5.6.1 on Linux), but I can always throw in an eval block to avoid any real problems.

    Thanks again for all the help, Monks.

    SpaceAce
    s>>sp>;s>..|>\u$&ace>g;print;

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://213546]
Approved by grinder
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others taking refuge in the Monastery: (5)
As of 2024-04-25 14:00 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found