⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 signal.texi

📁 一个C源代码分析器
💻 TEXI
📖 第 1 页 / 共 5 页
字号:
sigaction (SIGHUP, NULL, &temp);if (temp.sa_handler != SIG_IGN)  @{    temp.sa_handler = handle_sighup;    sigemptyset (&temp.sa_mask);    sigaction (SIGHUP, &temp, NULL);  @}@end group@end smallexample@node Defining Handlers@section Defining Signal Handlers@cindex signal handler functionThis section describes how to write a signal handler function that canbe established with the @code{signal} or @code{sigaction} functions.A signal handler is just a function that you compile together with therest of the program.  Instead of directly invoking the function, you use@code{signal} or @code{sigaction} to tell the operating system to callit when a signal arrives.  This is known as @dfn{establishing} thehandler.  @xref{Signal Actions}.There are two basic strategies you can use in signal handler functions:@itemize @bullet@itemYou can have the handler function note that the signal arrived bytweaking some global data structures, and then return normally.@itemYou can have the handler function terminate the program or transfercontrol to a point where it can recover from the situation that causedthe signal.@end itemizeYou need to take special care in writing handler functions because theycan be called asynchronously.  That is, a handler might be called at anypoint in the program, unpredictably.  If two signals arrive during avery short interval, one handler can run within another.  This sectiondescribes what your handler should do, and what you should avoid.@menu* Handler Returns::             Handlers that return normally, and what                                 this means. * Termination in Handler::      How handler functions terminate a program.* Longjmp in Handler::          Nonlocal transfer of control out of a                                 signal handler.* Signals in Handler::          What happens when signals arrive while                                 the handler is already occupied.* Merged Signals::		When a second signal arrives before the				 first is handled.* Nonreentrancy::               Do not call any functions unless you know they                                 are reentrant with respect to signals. * Atomic Data Access::          A single handler can run in the middle of                                 reading or writing a single object. @end menu@node Handler Returns@subsection Signal Handlers that ReturnHandlers which return normally are usually used for signals such as@code{SIGALRM} and the I/O and interprocess communication signals.  Buta handler for @code{SIGINT} might also return normally after setting aflag that tells the program to exit at a convenient time.It is not safe to return normally from the handler for a program errorsignal, because the behavior of the program when the handler functionreturns is not defined after a program error.  @xref{Program ErrorSignals}.Handlers that return normally must modify some global variable in orderto have any effect.  Typically, the variable is one that is examinedperiodically by the program during normal operation.  Its data typeshould be @code{sig_atomic_t} for reasons described in @ref{AtomicData Access}.Here is a simple example of such a program.  It executes the body ofthe loop until it has noticed that a @code{SIGALRM} signal has arrived.This technique is useful because it allows the iteration in progresswhen the signal arrives to complete before the loop exits.@smallexample@include sigh1.c.texi@end smallexample@node Termination in Handler@subsection Handlers That Terminate the ProcessHandler functions that terminate the program are typically used to causeorderly cleanup or recovery from program error signals and interactiveinterrupts.The cleanest way for a handler to terminate the process is to raise thesame signal that ran the handler in the first place.  Here is how to dothis:@smallexamplevolatile sig_atomic_t fatal_error_in_progress = 0;voidfatal_error_signal (int sig)@{@group  /* @r{Since this handler is established for more than one kind of signal, }     @r{it might still get invoked recursively by delivery of some other kind}     @r{of signal.  Use a static variable to keep track of that.} */  if (fatal_error_in_progress)    raise (sig);  fatal_error_in_progress = 1;@end group@group  /* @r{Now do the clean up actions:}     @r{- reset terminal modes}     @r{- kill child processes}     @r{- remove lock files} */  @dots{}@end group@group  /* @r{Now reraise the signal.  Since the signal is blocked,}     @r{it will receive its default handling, which is}     @r{to terminate the process.  We could just call}     @r{@code{exit} or @code{abort}, but reraising the signal}     @r{sets the return status from the process correctly.} */  raise (sig);@}@end group@end smallexample@node Longjmp in Handler@subsection Nonlocal Control Transfer in Handlers@cindex non-local exit, from signal handlerYou can do a nonlocal transfer of control out of a signal handler usingthe @code{setjmp} and @code{longjmp} facilities (@pxref{Non-LocalExits}).When the handler does a nonlocal control transfer, the part of theprogram that was running will not continue.  If this part of the programwas in the middle of updating an important data structure, the datastructure will remain inconsistent.  Since the program does notterminate, the inconsistency is likely to be noticed later on.There are two ways to avoid this problem.  One is to block the signalfor the parts of the program that update important data structures.Blocking the signal delays its delivery until it is unblocked, once thecritical updating is finished.  @xref{Blocking Signals}.The other way to re-initialize the crucial data structures in the signalhandler, or make their values consistent.Here is a rather schematic example showing the reinitialization of oneglobal variable.@smallexample@group#include <signal.h>#include <setjmp.h>jmp_buf return_to_top_level;volatile sig_atomic_t waiting_for_input;voidhandle_sigint (int signum)@{  /* @r{We may have been waiting for input when the signal arrived,}     @r{but we are no longer waiting once we transfer control.} */  waiting_for_input = 0;  longjmp (return_to_top_level, 1);@}@end group@groupintmain (void)@{  @dots{}  signal (SIGINT, sigint_handler);  @dots{}  while (1) @{    prepare_for_command ();    if (setjmp (return_to_top_level) == 0)      read_and_execute_command ();  @}@}@end group@group/* @r{Imagine this is a subroutine used by various commands.} */char *read_data ()@{  if (input_from_terminal) @{    waiting_for_input = 1;    @dots{}    waiting_for_input = 0;  @} else @{     @dots{}  @}@}@end group@end smallexample@node Signals in Handler@subsection Signals Arriving While a Handler Runs@cindex race conditions, relating to signalsWhat happens if another signal arrives while your signal handlerfunction is running?When the handler for a particular signal is invoked, that signal isautomatically blocked until the handler returns.  That means that if twosignals of the same kind arrive close together, the second one will beheld until the first has been handled.  (The handler can explicitlyunblock the signal using @code{sigprocmask}, if you want to allow moresignals of this type to arrive; see @ref{Process Signal Mask}.)However, your handler can still be interrupted by delivery of anotherkind of signal.  To avoid this, you can use the @code{sa_mask} member ofthe action structure passed to @code{sigaction} to explicitly specifywhich signals should be blocked while the signal handler runs.  Thesesignals are in addition to the signal for which the handler was invoked,and any other signals that are normally blocked by the process.@xref{Blocking for Handler}.When the handler returns, the set of blocked signals is restored to thevalue it had before the handler ran.  So using @code{sigprocmask} insidethe handler only affects what signals can arrive during the execution ofthe handler itself, not what signals can arrive once the handler returns.@strong{Portability Note:} Always use @code{sigaction} to establish ahandler for a signal that you expect to receive asynchronously, if youwant your program to work properly on System V Unix.  On this system,the handling of a signal whose handler was established with@code{signal} automatically sets the signal's action back to@code{SIG_DFL}, and the handler must re-establish itself each time itruns.  This practice, while inconvenient, does work when signals cannotarrive in succession.  However, if another signal can arrive right away,it may arrive before the handler can re-establish itself.  Then thesecond signal would receive the default handling, which could terminatethe process.@node Merged Signals@subsection Signals Close Together Merge into One@cindex handling multiple signals@cindex successive signals@cindex merging of signalsIf multiple signals of the same type are delivered to your processbefore your signal handler has a chance to be invoked at all, thehandler may only be invoked once, as if only a single signal hadarrived.  In effect, the signals merge into one.  This situation canarise when the signal is blocked, or in a multiprocessing environmentwhere the system is busy running some other processes while the signalsare delivered.  This means, for example, that you cannot reliably use asignal handler to count signals.  The only distinction you can reliablymake is whether at least one signal has arrived since a given time inthe past.Here is an example of a handler for @code{SIGCHLD} that compensates forthe fact that the number of signals recieved may not equal the number ofchild processes generate them.  It assumes that the program keeps trackof all the child processes with a chain of structures as follows:@smallexamplestruct process@{  struct process *next;  /* @r{The process ID of this child.}  */  int pid;  /* @r{The descriptor of the pipe or pseudo terminal}     @r{on which output comes from this child.}  */  int input_descriptor;  /* @r{Nonzero if this process has stopped or terminated.}  */  sig_atomic_t have_status;  /* @r{The status of this child; 0 if running,}     @r{otherwise a status value from @code{waitpid}.}  */  int status;@};struct process *process_list;@end smallexampleThis example also uses a flag to indicate whether signals have arrivedsince some time in the past---whenever the program last cleared it tozero.@smallexample/* @r{Nonzero means some child's status has changed}   @r{so look at @code{process_list} for the details.}  */int process_status_change;@end smallexampleHere is the handler itself:@smallexamplevoidsigchld_handler (int signo)@{  int old_errno = errno;  while (1) @{    register int pid;    int w;    struct process *p;    /* @r{Keep asking for a status until we get a definitive result.}  */    do       @{        errno = 0;        pid = waitpid (WAIT_ANY, &w, WNOHANG | WUNTRACED);      @}    while (pid <= 0 && errno == EINTR);    if (pid <= 0) @{      /* @r{A real failure means there are no more}         @r{stopped or terminated child processes, so return.}  */      errno = old_errno;      return;    @}    /* @r{Find the process that signaled us, and record its status.}  */    for (p = process_list; p; p = p->next)      if (p->pid == pid) @{        p->status = w;        /* @r{Indicate that the @code{status} field}           @r{has data to look at.  We do this only after storing it.}  */        p->have_status = 1;        /* @r{If process has terminated, stop waiting for its output.}  */        if (WIFSIGNALED (w) || WIFEXITED (w))          if (p->input_descriptor)            FD_CLR (p->input_de

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -