📄 perlipc.1
字号:
\& };\& if ($@ and $@ !~ /alarm clock restart/) { die }.Ve.PPIf the operation being timed out is \fIsystem()\fR or \fIqx()\fR, this techniqueis liable to generate zombies. If this matters to you, you'llneed to do your own \fIfork()\fR and \fIexec()\fR, and kill the errant child process..PPFor more complex signal handling, you might see the standard \s-1POSIX\s0module. Lamentably, this is almost entirely undocumented, butthe \fIt/lib/posix.t\fR file from the Perl source distribution has someexamples in it..Sh "Handling the \s-1SIGHUP\s0 Signal in Daemons".IX Subsection "Handling the SIGHUP Signal in Daemons"A process that usually starts when the system boots and shuts downwhen the system is shut down is called a daemon (Disk And ExecutionMONitor). If a daemon process has a configuration file which ismodified after the process has been started, there should be a way totell that process to re-read its configuration file, without stoppingthe process. Many daemons provide this mechanism using the \f(CW\*(C`SIGHUP\*(C'\fRsignal handler. When you want to tell the daemon to re-read the fileyou simply send it the \f(CW\*(C`SIGHUP\*(C'\fR signal..PPNot all platforms automatically reinstall their (native) signalhandlers after a signal delivery. This means that the handler worksonly the first time the signal is sent. The solution to this problemis to use \f(CW\*(C`POSIX\*(C'\fR signal handlers if available, their behaviouris well-defined..PPThe following example implements a simple daemon, which restartsitself every time the \f(CW\*(C`SIGHUP\*(C'\fR signal is received. The actual code islocated in the subroutine \f(CW\*(C`code()\*(C'\fR, which simply prints some debuginfo to show that it works and should be replaced with the real code..PP.Vb 1\& #!/usr/bin/perl \-w\&\& use POSIX ();\& use FindBin ();\& use File::Basename ();\& use File::Spec::Functions;\&\& $|=1;\&\& # make the daemon cross\-platform, so exec always calls the script\& # itself with the right path, no matter how the script was invoked.\& my $script = File::Basename::basename($0);\& my $SELF = catfile $FindBin::Bin, $script;\&\& # POSIX unmasks the sigprocmask properly\& my $sigset = POSIX::SigSet\->new();\& my $action = POSIX::SigAction\->new(\*(AqsigHUP_handler\*(Aq,\& $sigset,\& &POSIX::SA_NODEFER);\& POSIX::sigaction(&POSIX::SIGHUP, $action);\&\& sub sigHUP_handler {\& print "got SIGHUP\en";\& exec($SELF, @ARGV) or die "Couldn\*(Aqt restart: $!\en";\& }\&\& code();\&\& sub code {\& print "PID: $$\en";\& print "ARGV: @ARGV\en";\& my $c = 0;\& while (++$c) {\& sleep 2;\& print "$c\en";\& }\& }\& _\|_END_\|_.Ve.SH "Named Pipes".IX Header "Named Pipes"A named pipe (often referred to as a \s-1FIFO\s0) is an old Unix \s-1IPC\s0mechanism for processes communicating on the same machine. It worksjust like a regular, connected anonymous pipes, except that theprocesses rendezvous using a filename and don't have to be related..PPTo create a named pipe, use the \f(CW\*(C`POSIX::mkfifo()\*(C'\fR function..PP.Vb 2\& use POSIX qw(mkfifo);\& mkfifo($path, 0700) or die "mkfifo $path failed: $!";.Ve.PPYou can also use the Unix command \fImknod\fR\|(1) or on somesystems, \fImkfifo\fR\|(1). These may not be in your normal path..PP.Vb 8\& # system return val is backwards, so && not ||\& #\& $ENV{PATH} .= ":/etc:/usr/etc";\& if ( system(\*(Aqmknod\*(Aq, $path, \*(Aqp\*(Aq)\& && system(\*(Aqmkfifo\*(Aq, $path) )\& {\& die "mk{nod,fifo} $path failed";\& }.Ve.PPA fifo is convenient when you want to connect a process to an unrelatedone. When you open a fifo, the program will block until there's somethingon the other end..PPFor example, let's say you'd like to have your \fI.signature\fR file be anamed pipe that has a Perl program on the other end. Now every time anyprogram (like a mailer, news reader, finger program, etc.) tries to readfrom that file, the reading program will block and your program willsupply the new signature. We'll use the pipe-checking file test \fB\-p\fRto find out whether anyone (or anything) has accidentally removed our fifo..PP.Vb 2\& chdir; # go home\& $FIFO = \*(Aq.signature\*(Aq;\&\& while (1) {\& unless (\-p $FIFO) {\& unlink $FIFO;\& require POSIX;\& POSIX::mkfifo($FIFO, 0700)\& or die "can\*(Aqt mkfifo $FIFO: $!";\& }\&\& # next line blocks until there\*(Aqs a reader\& open (FIFO, "> $FIFO") || die "can\*(Aqt write $FIFO: $!";\& print FIFO "John Smith (smith\e@host.org)\en", \`fortune \-s\`;\& close FIFO;\& sleep 2; # to avoid dup signals\& }.Ve.Sh "Deferred Signals (Safe Signals)".IX Subsection "Deferred Signals (Safe Signals)"In Perls before Perl 5.7.3 by installing Perl code to deal withsignals, you were exposing yourself to danger from two things. First,few system library functions are re-entrant. If the signal interruptswhile Perl is executing one function (like \fImalloc\fR\|(3) or \fIprintf\fR\|(3)),and your signal handler then calls the same function again, you couldget unpredictable behavior\*(--often, a core dump. Second, Perl isn'titself re-entrant at the lowest levels. If the signal interrupts Perlwhile Perl is changing its own internal data structures, similarlyunpredictable behaviour may result..PPThere were two things you could do, knowing this: be paranoid or bepragmatic. The paranoid approach was to do as little as possible in yoursignal handler. Set an existing integer variable that already has avalue, and return. This doesn't help you if you're in a slow system call,which will just restart. That means you have to \f(CW\*(C`die\*(C'\fR to \fIlongjmp\fR\|(3) outof the handler. Even this is a little cavalier for the true paranoiac,who avoids \f(CW\*(C`die\*(C'\fR in a handler because the system \fIis\fR out to get you.The pragmatic approach was to say \*(L"I know the risks, but prefer theconvenience\*(R", and to do anything you wanted in your signal handler,and be prepared to clean up core dumps now and again..PPIn Perl 5.7.3 and later to avoid these problems signals are\&\*(L"deferred\*(R"\-\- that is when the signal is delivered to the process bythe system (to the C code that implements Perl) a flag is set, and thehandler returns immediately. Then at strategic \*(L"safe\*(R" points in thePerl interpreter (e.g. when it is about to execute a new opcode) theflags are checked and the Perl level handler from \f(CW%SIG\fR isexecuted. The \*(L"deferred\*(R" scheme allows much more flexibility in thecoding of signal handler as we know Perl interpreter is in a safestate, and that we are not in a system library function when thehandler is called. However the implementation does differ fromprevious Perls in the following ways:.IP "Long-running opcodes" 4.IX Item "Long-running opcodes"As the Perl interpreter only looks at the signal flags when it is aboutto execute a new opcode, a signal that arrives during a long-runningopcode (e.g. a regular expression operation on a very large string) willnot be seen until the current opcode completes..SpN.B. If a signal of any given type fires multiple times during an opcode (such as from a fine-grained timer), the handler for that signal willonly be called once after the opcode completes, and all the otherinstances will be discarded. Furthermore, if your system's signal queuegets flooded to the point that there are signals that have been raisedbut not yet caught (and thus not deferred) at the time an opcodecompletes, those signals may well be caught and deferred duringsubsequent opcodes, with sometimes surprising results. For example, youmay see alarms delivered even after calling \f(CWalarm(0)\fR as the latterstops the raising of alarms but does not cancel the delivery of alarmsraised but not yet caught. Do not depend on the behaviors described inthis paragraph as they are side effects of the current implementation andmay change in future versions of Perl..IP "Interrupting \s-1IO\s0" 4.IX Item "Interrupting IO"When a signal is delivered (e.g. \s-1INT\s0 control-C) the operating systembreaks into \s-1IO\s0 operations like \f(CW\*(C`read\*(C'\fR (used to implement Perls<> operator). On older Perls the handler was calledimmediately (and as \f(CW\*(C`read\*(C'\fR is not \*(L"unsafe\*(R" this worked well). Withthe \*(L"deferred\*(R" scheme the handler is not called immediately, and ifPerl is using system's \f(CW\*(C`stdio\*(C'\fR library that library may re-start the\&\f(CW\*(C`read\*(C'\fR without returning to Perl and giving it a chance to call the\&\f(CW%SIG\fR handler. If this happens on your system the solution is to use\&\f(CW\*(C`:perlio\*(C'\fR layer to do \s-1IO\s0 \- at least on those handles which you wantto be able to break into with signals. (The \f(CW\*(C`:perlio\*(C'\fR layer checksthe signal flags and calls \f(CW%SIG\fR handlers before resuming \s-1IO\s0 operation.).SpNote that the default in Perl 5.7.3 and later is to automatically usethe \f(CW\*(C`:perlio\*(C'\fR layer..SpNote that some networking library functions like \fIgethostbyname()\fR areknown to have their own implementations of timeouts which may conflictwith your timeouts. If you are having problems with such functions,you can try using the \s-1POSIX\s0 \fIsigaction()\fR function, which bypasses thePerl safe signals (note that this means subjecting yourself topossible memory corruption, as described above). Instead of setting\&\f(CW$SIG{ALRM}\fR:.Sp.Vb 1\& local $SIG{ALRM} = sub { die "alarm" };.Ve.Sptry something like the following:.Sp.Vb 4\& use POSIX qw(SIGALRM);\& POSIX::sigaction(SIGALRM,\& POSIX::SigAction\->new(sub { die "alarm" }))\& or die "Error setting SIGALRM handler: $!\en";.Ve.SpAnother way to disable the safe signal behavior locally is to usethe \f(CW\*(C`Perl::Unsafe::Signals\*(C'\fR module from \s-1CPAN\s0 (which will affectall signals)..IP "Restartable system calls" 4.IX Item "Restartable system calls"On systems that supported it, older versions of Perl used the\&\s-1SA_RESTART\s0 flag when installing \f(CW%SIG\fR handlers. This meant thatrestartable system calls would continue rather than returning whena signal arrived. In order to deliver deferred signals promptly,Perl 5.7.3 and later do \fInot\fR use \s-1SA_RESTART\s0. Consequently, restartable system calls can fail (with $! set to \f(CW\*(C`EINTR\*(C'\fR) in placeswhere they previously would have succeeded..SpNote that the default \f(CW\*(C`:perlio\*(C'\fR layer will retry \f(CW\*(C`read\*(C'\fR, \f(CW\*(C`write\*(C'\fRand \f(CW\*(C`close\*(C'\fR as described above and that interrupted \f(CW\*(C`wait\*(C'\fR and \&\f(CW\*(C`waitpid\*(C'\fR calls will always be retried..ie n .IP "Signals as ""faults""" 4.el .IP "Signals as ``faults''" 4.IX Item "Signals as faults"Certain signals, e.g. \s-1SEGV\s0, \s-1ILL\s0, and \s-1BUS\s0, are generated as a result ofvirtual memory or other \*(L"faults\*(R". These are normally fatal and there islittle a Perl-level handler can do with them, so Perl now delivers themimmediately rather than attempting to defer them..IP "Signals triggered by operating system state" 4.IX Item "Signals triggered by operating system state"On some operating systems certain signal handlers are supposed to \*(L"dosomething\*(R" before returning. One example can be \s-1CHLD\s0 or \s-1CLD\s0 whichindicates a child process has completed. On some operating systems thesignal handler is expected to \f(CW\*(C`wait\*(C'\fR for the completed childprocess. On such systems the deferred signal scheme will not work forthose signals (it does not do the \f(CW\*(C`wait\*(C'\fR). Again the failure willlook like a loop as the operating system will re-issue the signal asthere are un-waited-for completed child processes..PPIf you want the old signal behaviour back regardless of possiblememory corruption, set the environment variable \f(CW\*(C`PERL_SIGNALS\*(C'\fR to\&\f(CW"unsafe"\fR (a new feature since Perl 5.8.1)..SH "Using \fIopen()\fP for IPC".IX Header "Using open() for IPC"Perl's basic \fIopen()\fR statement can also be used for unidirectionalinterprocess communication by either appending or prepending a pipesymbol to the second argument to \fIopen()\fR. Here's how to startsomething up in a child process you intend to write to:.PP.Vb 5\& open(SPOOLER, "| cat \-v | lpr \-h 2>/dev/null")\& || die "can\*(Aqt fork: $!";\& local $SIG{PIPE} = sub { die "spooler pipe broke" };\& print SPOOLER "stuff\en";\& close SPOOLER || die "bad spool: $! $?";.Ve.PPAnd here's how to start up a child process you intend to read from:.PP.Vb 7\& open(STATUS, "netstat \-an 2>&1 |")\& || die "can\*(Aqt fork: $!";\& while (<STATUS>) {\& next if /^(tcp|udp)/;\& print;\& }\& close STATUS || die "bad netstat: $! $?";.Ve.PPIf one can be sure that a particular program is a Perl script that isexpecting filenames in \f(CW@ARGV\fR, the clever programmer can write somethinglike this:.PP.Vb 1\& % program f1 "cmd1|" \- f2 "cmd2|" f3 < tmpfile.Ve.PPand irrespective of which shell it's called from, the Perl program willread from the file \fIf1\fR, the process \fIcmd1\fR, standard input (\fItmpfile\fRin this case), the \fIf2\fR file, the \fIcmd2\fR command, and finally the \fIf3\fRfile. Pretty nifty, eh?.PPYou might notice that you could use backticks for much thesame effect as opening a pipe for reading:.PP.Vb 2\& print grep { !/^(tcp|udp)/ } \`netstat \-an 2>&1\`;\& die "bad netstat" if $?;.Ve.PPWhile this is true on the surface, it's much more efficient to process thefile one line or record at a time because then you don't have to read thewhole thing into memory at once. It also gives you finer control of thewhole process, letting you to kill off the child process early if you'dlike..PPBe careful to check both the \fIopen()\fR and the \fIclose()\fR return values. Ifyou're \fIwriting\fR to a pipe, you should also trap \s-1SIGPIPE\s0. Otherwise,think of what happens when you start up a pipe to a command that doesn'texist: the \fIopen()\fR will in all likelihood succeed (it only reflects the\&\fIfork()\fR's success), but then your output will fail\*(--spectacularly. Perlcan't know whether the command worked because your command is actuallyrunning in a separate process whose \fIexec()\fR might have failed. Therefore,while readers of bogus commands return just a quick end of file, writersto bogus command will trigger a signal they'd better be prepared to
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -