CTO技术网首页 > CTO技术网 > 正文

A Primer on Signals in the Solaris OS

Learn the Ins and Outs of Implementing Signals in theSolaris Operating Environment


Signals are a process event notification mechanism that has beenpart of the UNIX? system from the earliest days. The APIs andunderlying behavioral characteristics of signalscharacterist andunderli behavior have evolved over theyears, at times diverging between the BSD and SVR4 releases of UNIX.Fortunately, industry standards brought things together, and you nowhaveindustri standard brought a well-understood and consistent foundation for signals.

Rather than work through a tutorial on writing code with signals (W. Richard Stevens'sAdvanced Programming in the UNIX Environment(see Resources) is an outstanding source for learning to program withsignals), this article opts instead to help you build a solidfoundation around signals with detailedsolidfound withsign outstand background and implementationdiscussions.

Signals are used to notify a process or thread of a particular event.Many engineers compare signals with hardware interrupts, which occur when ahardware subsystemparticular interrupt subsystem such as a disk I/O interface (an SCSI host adapter,for example) generates an interrupt to a processor as a result of acompleted Iprocessor interrupt acomplet/O. This event in turn causes the processor to enter aninterrupt handler, so subsequent processing can be done in theoperating system based on the sourceaninterrupt processor theoper and cause of the interrupt.

UNIX? guru W. Richard Stevens, however, aptly describes signals as software interrupts. When a signal is sent to a process or thread, a signal handlerinterrupt richard softwar may be entered (depending on the current disposition of the signal), which is similar to the system entering an interrupt handleras the result of receivinginterrupt disposit handlera an interrupt.

There is quite a bit of history related to signals, design changesin the signal code, and various implementations of UNIX. This was duein part tochangesin implement histori some deficiencies in the early implementation of signals, aswell as the parallel development work done on different versions ofUNIX, primarily BSD UNIX and AT&primarili implement parallel;T System V. W. Richard Stevens,James Cox, and Berny Goodheart (see Resources) cover these details intheir respective books. Whatdoeswarrant mention is that earlyimplementations of signals were deemed unreliable. The unreliabilitystemmed from the fact that in the old days the kernel would reset thesignalearlyimplement warrant thesign handler to its default if a process caught a signal and invokedits own handler, and the reset occurred before the handler was invoked.Attempts toinvokedit attempt process address this issue in user code by having the signalhandler first reinstall itself did not always solve the problem, assuccessive occurrences of the same signalsignalhandl assuccess reinstal resulted in race conditions,where the default action was invoked before the user-defined handlerwas reinstalled. For signals that had a default action of terminatingtheterminatingth handlerwa reinstal process, this created severe problems. This problem (and someothers) were addressed in 4.3BSD UNIX and SVR3 in the mid-'80s.

The implementation of reliable signals has been in place for manyyearsnow, where an installed signal handler remains persistent and is notreset by the kernel. Themanyyearsnow implement notreset POSIX standards provided a fairly well-definedset of interfaces for using signals in code, and today the SolarisOperating Environment implementation of signals is fullyPOSIX-compliantsolarisoper fullyposix definedset. Note that reliable signals require the use of thenewersigaction(2)interface, as opposed to the traditionalsignal(3C)call.

The occurrence of a signal may be synchronous or asynchronous to theprocess or thread, depending on the source of the signal and theunderlying reason ortheprocess theunderli asynchron cause. Synchronous signals occur as a directresult of the executing instruction stream, where an unrecoverableerror (such as an illegal instruction or illegal address reference)requiresdirectresult instruct synchron an immediate termination of the process. Such signals aredirected to the thread whose execution stream caused the error. Because an error of this type causesaredirect process stream a trap into a kernel trap handler,synchronous signals are sometimes referred to astraps.Asynchronous signals are external to (and in some cases unrelated to)the current execution context. One obvious example is the sendingof a signal to aasynchron sendingof current process from another process or thread, via akill(2),_lwp_kill(2), orsigsend(2)system call, or athr_kill(3T),pthread_kill(3T), orsigqueue(3R)library invocation. Asynchronous signals are also referred to as interrupts.

Every signal has a unique signal name, an abbreviation that begins withSIG(SIGINTfor interrupt signal, for example) and a corresponding signal number.Additionally, for all possible signals, the system defines a defaultdisposition, or action to take whendefaultdisposit correspond interrupt a signal occurs. There are fourpossible default dispositions:

    Exit: Forces the process to exitCore: Forces the process to exit, and creates a core fileStop: Stops the processIgnore: Ignores the signal; no action taken

A signal's disposition within a process's context defines whataction the system will take on behalf of the process when a signal isdelivered. Alldisposit process whatact threads and LWPs (lightweight processes) within aprocess share the signal disposition, which is processwide and cannotbe unique among threads within the same process. The tablelightweight processwid disposit belowprovides a complete list of signals, along with a description anddefault action.

Name Number Default action Description SIGHUP 1 Exit Hangup (reftermio(7I) ).SIGINT 2 Exit Interrupt (reftermio(7I) ).SIGQUIT 3 Core Quit (reftermio(7I) )SIGILL 4 Core Illegal Instruction SIGTRAP 5 Core Trace or breakpoint trap SIGABRT 6 Core Abort SIGEMT 7 Core Emulation trap SIGFPE 8 Core Arithmetic exception SIGKILL 9 Exit Kill SIGBUS 10 Core Bus error -- actually a misaligned address error SIGSEGV 11 Core Segmentation fault -- an address reference boundary error SIGSYS 12 Core Bad system call SIGPIPE 13 Exit Broken pipe SIGALRM 14 Exit Alarm clock SIGTERM 15 Exit Terminated SIGUSR1 16 Exit User defined signal 1 SIGUSR2 17 Exit User defined signal 2 SIGCHLD 18 Ignore Child process status changed SIGPWR 19 Ignore Power fail or restart SIGWINCH 20 Ignore Window size change SIGURG 21 Ignore Urgent socket condition SIGPOLL 22 Exit Pollable event (refstreamio(7I) )SIGSTOP 23 Stop Stop (cannot be caught or ignored) SIGTSTP 24 Stop Stop (job control, e.g.,^z) )SIGCONT 25 Ignore Continued SIGTTIN 26 Stop Stopped -- tty input (reftermio(7I) )SIGTTOU 27 Stop Stopped -- tty output (reftermio(7I) )SIGVTALRM 28 Exit Virtual timer expired SIGPROF 29 Exit Profiling timer expired SIGXCPU 30 Core CPU time limit exceeded (refgetrlimit(2) )SIGXFSZ 31 Core File size limit exceeded (refgetrlimit(2) )SIGWAITING 32 Ignore Concurrency signal used by threads library SIGLWP 33 Ignore Inter-LWP signal used by threads library SIGFREEZE 34 Ignore Checkpoint suspend SIGTHAW 35 Ignore Checkpoint resume SIGCANCEL 36 Ignore Cancellation signal used by threads library SIGLOST 37 Ignore Resource lost SIGRTMIN 38 Exit Highest priority realtime signal SIGRTMAX 45 Exit Lowest priority realtime signal

Back to Top

Signal description and default action

Note thatSIGLOSTfirst appeared in Solaris release 2.6. Solaris 2.5 and 2.5.1 do not define this signal, and instead haveSIGRTMINandSIGRTMAXat signal numbers 37 and 44, respectively. The kernel definesMAXSIG(available for user code in/usr/include/sys/signal.h) as a symbolic constant used in various places in kernel signal support code.MAXSIGis 44 in Solaris 2.5 and 2.5.1, and 45 in Solaris 2.6 and 7.

The disposition of a signal can be changed from its default, and aprocess can arrange to catch a signal and invoke a signal handlingroutine ofhandlingroutin disposit aprocess its own, or ignore a signal that may not have a defaultdisposition of Ignore. The only exceptions areSIGKILLandSIGSTOP, whose default dispositions cannot be changed. The interfaces for defining and changing signal disposition are thesignal(3C)andsigset(3C)libraries, and thesigaction(2)system call. Signals can also be blocked, which means the process hastemporarily prevented delivery of a signal. The generation of a signalthat has been blockedhastemporarili signalthat deliveri will result in the signal remaining pending tothe process until it is explicitly unblocked, or the disposition ischanged to Ignore. Thesigprocmask(2)system call willset or get a process's signal mask, the bit array that is inspected bythe kernel to determine if a signal is blockeddetermin willset process or not.thr_setsigmask(3T)andpthread_sigmask(3T)are the equivalent interfaces for setting and retrieving the signal mask at the user-threads level.

I mentioned earlier that a signal may originate from severaldifferent places, for a variety of different reasons. The first threesignals listed in the table aboveseveraldiffer threesign varieti -SIGHUP,SIGINT, andSIGQUIT- are generated by a keyboard entry from the controlling terminal (SIGINTandSIGHUP), or they are generated if the control terminal becomes disconnected (SIGHUP- use of thenohup(1)command makes processes "immune" from hangups by setting the disposition ofSIGHUPto Ignore). Other terminal I/O-related signals includeSIGSTOP,SIGTTIN,SIGTTOU, andSIGTSTP.For the signals that originate from a keyboard command, the actual keysequence that generates the signals, usually Ctrl-C, is defined withinthe parameters of thewithinth keyboard command terminal session, typically viastty(1), which results in aSIGINTbeing sent to a process, and has a default disposition of Exit.

Signals generated as a direct result of an error encountered duringinstruction execution start with a hardware trap on the system.Different processor architectures define variousduringinstruct architectur processor traps that result inan immediate vectored transfer of control to a kernel trap-handlingfunction. The Solaris kernel builds a trap table and insertstrap-handling routineshandlingfunct insertstrap transfer in the appropriate locations based on thearchitecture specification of the processors that Solaris supports:SPARC V7 (early Sun-4 architectures), SPARC V8 (SuperSPARCthearchitectur architectur supersparc - Sun-4m andSun-4d architectures), SPARC V9 (UltraSPARC), and x86 (in Intelparlance they're calledinterrupt descriptor tablesor IDTs; on SPARC, they're calledtrap tables).The kernel-installed trap handler will ultimately generate a signal tothe thread that caused the trap. The signals that result from hardwaretraps areSIGILL,SIGFPE,SIGSEGV,SIGTRAP,SIGBUS, andSIGEMT.

In addition to terminal I/O and error trap conditions, signals canoriginate from sources such as an explicit send programmatically viakill(2)orthr_kill(3T), or from a shell issuing akill(1)command. Parent processes are notified of status change in a child process viaSIGCHLD. Thealarm(2)system call sends aSIGALRMwhen the timer expires. Applications can create user-defined signals asa somewhat crude form of interprocess communication by defininghandlers forSIGUSR1orSIGUSR2and then sending those signals between processes. The kernel sendsSIGXCPUif a process exceeds its processor time resource limit orSIGXFSZif a file write exceeds the file size resource limit. ASIGABRTis sent as a result of an invocation of theabort(3C)library. If a process is writing to a pipe and the reader has terminated,SIGPIPEis generated.

These examples of signals generated as a result of events beyondhard errors and terminal I/O do not represent the complete list, butrather provide youbeyondhard butrath complet with a well-rounded set of examples of theprocess-induced and external events that can generate signals. You canfind a complete list in any numbertheprocess complet canfind of texts on UNIX programming.

In terms of actual implementation, a signal is represented as a bitin a data structure (several data structures, actually, as you'll seeshortly). More succinctlyseeshortli succinctli implement, the posting of a signal by the kernelresults in a bit getting set in a structure member at either theprocess or thread level. Because eachkernelresult theprocess structur signal has a unique signalnumber, a structure member of sufficient width is used, which allowsevery signal to be represented by simply setting the bit thatcorrespondsthatcorrespond allowseveri signalnumb to the signal number of the signal you wish to post (forexample, setting the 17th bit to post signal 17,SIGUSR1).

Because Solaris includes more than 32 possible signals, a long orint data type is not sufficiently wide to represent each possiblesignal as a unique bitpossiblesign possibl suffici, so a data structure is required. Thek_sigset_t datastructure defined in/usr/include/signal.his used in several of the process data structures to store the postedsignal bits. It's an array of two unsigned long data types (arraymemberspostedsign arraymemb structur 0 and 1), providing a bit width of 64 bits.

k_sigset_t data structure
Figure 1. k_sigset_t data structure
(Click image to enlarge.)
Signals in Solaris

The multithreaded architecture of Solaris made for some interestingchallenges in developing a means of supporting signals that comply withthe UNIX signal semantics, as defined bymultithread architectur develop industry standards such asPOSIX. Signals traditionally go through two well-defined stages:generation and delivery. Signal generation is the point of origin ofthe signal, ortradition industri standard the sending phase. A signal is said to be delivered whenwhatever disposition that has been established for the signal isinvoked, even if it is towhenwhatev establish disposit be ignored. If a signal is being blocked,thus postponing delivery, it is considered pending.

User threads in Solaris, created via explicit calls to eitherthr_create(3T)orpthread_create(3T),all have their own signal masks. Threads can choose to block signalsindependent of other threads executing in the same process, whichallows different threads to takesignalsindepend whichallow process delivery of different signals atvarious times during process execution. The thread's libraries (POSIXand Solaris threads) providethr_sigsetmask(3T)andpthread_sigmask(3T)interfaces for establishing per-user thread signal masks. Thedisposition and handlers for all signals are shared by all the threadsin a process. So, for examplethedisposit threadsin establish, aSIGINTwith the default disposition in place will cause the entire process to exit.

Signals generated as a result of a trap (SIGFPE,SIGILL,etc) are sent to the thread that caused the trap. Asynchronous signalsare delivered to the first thread that is found not blocking the signal.

The difficulty in implementing semantically correct signals inSolaris arises from the fact that user-level threads are not visible tothe kernel; the low-level kerneldifficulti implement insolari signal code has no way of knowingwhich threads have which signals blocked and, thus, which thread asignal should be sent to. Some sort of intermediaryknowingwhich intermediari signal phase needed to beimplemented, something that had visibility to the user-thread signalmasks as well as to the kernel. The solution comes in the formbeimplement signalmask visibl of aspecial LWP that is created by the thread's library for programs thatare linked tolibthread, called theaslwp(it's actually an LWP/kthread pair). The implementation of theaslwpextends the traditional signal generation and delivery phases by adding two additional steps: notification and redirection.

Generation -> Notification -> Redirection -> Delivery

When a signal (generation) is sent to a process, theaslwpis notified, at which point theaslwpwill look for a thread that can take delivery of the signal. Once sucha thread is located, the signal is redirected and delivered to thatthreadthatthread redirect deliveri.

Figure 2 shows the LWP/kthread and user-thread structures used to support signals in the process.

Back to Top

LWP/kthread and user-thread structures used to support signals in the process
Figure 2. LWP/kthread and user-thread structures
used to support signals in the process
(Click image to enlarge.)


    Advanced Programming in the UNIX Environment(Addison-Wesley, ISBN 0-201-56317-7) Stevens, W. Richard.Multithreaded Programming with Pthreads(Sun Microsystems Press/Prentice Hall ISBN 0-13-680729-1) Berg, Daniel, J. and Lewis, Bill.Programming with Threads(Sun Microsystems Press/Prentice Hall, ISBN 0-13-172389-8) Kleiman, Steve, Shah, Devang, and Smaalders, Bart.The Magic Garden Explained: The Internals of UNIX System V Release 4(Prentice Hall, ISBN 0-13-098138-9) Goodheart, Berny, Cox, James, and Mashey, John, R.UNIX Internals: The New Frontiers(Prentice Hall, ISBN 0-13-101908-2) Vahalia, Uresh.
About the author

Jim Mauro is a Senior Staff Engineer in the Performance andAvailability Engineering group at Sun Microsystems, where he focuses onsystem availability and failure recovery. Whenmicrosystem andavail onsystem not working or writing,Jim enjoys building Legos with his 2 sons, reading a wide variety offiction and non-fiction, listening to music, and droolingvarieti fiction offict over the nextupgrade of his stereo system.


Reprinted with permission from the April 1999 edition of SunWorldmagazine. Copyright Web Publishing Inc., an IDG Communications company.

登录 (请登录发言,并遵守相关规定)


友情链接 百度 | 谷歌 | CIO选型网 | CFO投资理财网 | 360理财网 | CoCo时尚网 | China Tours | 休闲吧 | 360行招工网 | 凌科软件