/share/doc/psd/04.uprog/p6

https://bitbucket.org/freebsd/freebsd-head/ · #! · 361 lines · 351 code · 10 blank · 0 comment · 0 complexity · 0e4bf158ee7645b7d74bc122fd5c1045 MD5 · raw file

  1. .\" Copyright (C) Caldera International Inc. 2001-2002. All rights reserved.
  2. .\"
  3. .\" Redistribution and use in source and binary forms, with or without
  4. .\" modification, are permitted provided that the following conditions are
  5. .\" met:
  6. .\"
  7. .\" Redistributions of source code and documentation must retain the above
  8. .\" copyright notice, this list of conditions and the following
  9. .\" disclaimer.
  10. .\"
  11. .\" Redistributions in binary form must reproduce the above copyright
  12. .\" notice, this list of conditions and the following disclaimer in the
  13. .\" documentation and/or other materials provided with the distribution.
  14. .\"
  15. .\" All advertising materials mentioning features or use of this software
  16. .\" must display the following acknowledgement:
  17. .\"
  18. .\" This product includes software developed or owned by Caldera
  19. .\" International, Inc. Neither the name of Caldera International, Inc.
  20. .\" nor the names of other contributors may be used to endorse or promote
  21. .\" products derived from this software without specific prior written
  22. .\" permission.
  23. .\"
  24. .\" USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
  25. .\" INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
  26. .\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  27. .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  28. .\" DISCLAIMED. IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE
  29. .\" FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR
  30. .\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  31. .\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
  32. .\" BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
  33. .\" WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
  34. .\" OR OTHERWISE) RISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
  35. .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  36. .\"
  37. .\" $FreeBSD$
  38. .\"
  39. .\" @(#)p6 8.1 (Berkeley) 6/8/93
  40. .\"
  41. .NH
  42. SIGNALS \(em INTERRUPTS AND ALL THAT
  43. .PP
  44. This section is concerned with how to
  45. deal gracefully with signals from
  46. the outside world (like interrupts), and with program faults.
  47. Since there's nothing very useful that
  48. can be done from within C about program
  49. faults, which arise mainly from illegal memory references
  50. or from execution of peculiar instructions,
  51. we'll discuss only the outside-world signals:
  52. .IT interrupt ,
  53. which is sent when the
  54. .UC DEL
  55. character is typed;
  56. .IT quit ,
  57. generated by the
  58. .UC FS
  59. character;
  60. .IT hangup ,
  61. caused by hanging up the phone;
  62. and
  63. .IT terminate ,
  64. generated by the
  65. .IT kill
  66. command.
  67. When one of these events occurs,
  68. the signal is sent to
  69. .IT all
  70. processes which were started
  71. from the corresponding terminal;
  72. unless other arrangements have been made,
  73. the signal
  74. terminates the process.
  75. In the
  76. .IT quit
  77. case, a core image file is written for debugging
  78. purposes.
  79. .PP
  80. The routine which alters the default action
  81. is
  82. called
  83. .UL signal .
  84. It has two arguments: the first specifies the signal, and the second
  85. specifies how to treat it.
  86. The first argument is just a number code, but the second is the
  87. address is either a function, or a somewhat strange code
  88. that requests that the signal either be ignored, or that it be
  89. given the default action.
  90. The include file
  91. .UL signal.h
  92. gives names for the various arguments, and should always be included
  93. when signals are used.
  94. Thus
  95. .P1
  96. #include <signal.h>
  97. ...
  98. signal(SIGINT, SIG_IGN);
  99. .P2
  100. causes interrupts to be ignored, while
  101. .P1
  102. signal(SIGINT, SIG_DFL);
  103. .P2
  104. restores the default action of process termination.
  105. In all cases,
  106. .UL signal
  107. returns the previous value of the signal.
  108. The second argument to
  109. .UL signal
  110. may instead be the name of a function
  111. (which has to be declared explicitly if
  112. the compiler hasn't seen it already).
  113. In this case, the named routine will be called
  114. when the signal occurs.
  115. Most commonly this facility is used
  116. to allow the program to clean up
  117. unfinished business before terminating, for example to
  118. delete a temporary file:
  119. .P1
  120. #include <signal.h>
  121. main()
  122. {
  123. int onintr();
  124. if (signal(SIGINT, SIG_IGN) != SIG_IGN)
  125. signal(SIGINT, onintr);
  126. /* Process ... */
  127. exit(0);
  128. }
  129. onintr()
  130. {
  131. unlink(tempfile);
  132. exit(1);
  133. }
  134. .P2
  135. .PP
  136. Why the test and the double call to
  137. .UL signal ?
  138. Recall that signals like interrupt are sent to
  139. .ul
  140. all
  141. processes started from a particular terminal.
  142. Accordingly, when a program is to be run
  143. non-interactively
  144. (started by
  145. .UL & ),
  146. the shell turns off interrupts for it
  147. so it won't be stopped by interrupts intended for foreground processes.
  148. If this program began by announcing that all interrupts were to be sent
  149. to the
  150. .UL onintr
  151. routine regardless,
  152. that would undo the shell's effort to protect it
  153. when run in the background.
  154. .PP
  155. The solution, shown above, is to test the state of interrupt handling,
  156. and to continue to ignore interrupts if they are already being ignored.
  157. The code as written
  158. depends on the fact that
  159. .UL signal
  160. returns the previous state of a particular signal.
  161. If signals were already being ignored, the process should continue to ignore them;
  162. otherwise, they should be caught.
  163. .PP
  164. A more sophisticated program may wish to intercept
  165. an interrupt and interpret it as a request
  166. to stop what it is doing
  167. and return to its own command-processing loop.
  168. Think of a text editor:
  169. interrupting a long printout should not cause it
  170. to terminate and lose the work
  171. already done.
  172. The outline of the code for this case is probably best written like this:
  173. .P1
  174. #include <signal.h>
  175. #include <setjmp.h>
  176. jmp_buf sjbuf;
  177. main()
  178. {
  179. int (*istat)(), onintr();
  180. istat = signal(SIGINT, SIG_IGN); /* save original status */
  181. setjmp(sjbuf); /* save current stack position */
  182. if (istat != SIG_IGN)
  183. signal(SIGINT, onintr);
  184. /* main processing loop */
  185. }
  186. .P2
  187. .P1
  188. onintr()
  189. {
  190. printf("\enInterrupt\en");
  191. longjmp(sjbuf); /* return to saved state */
  192. }
  193. .P2
  194. The include file
  195. .UL setjmp.h
  196. declares the type
  197. .UL jmp_buf
  198. an object in which the state
  199. can be saved.
  200. .UL sjbuf
  201. is such an object; it is an array of some sort.
  202. The
  203. .UL setjmp
  204. routine then saves
  205. the state of things.
  206. When an interrupt occurs,
  207. a call is forced to the
  208. .UL onintr
  209. routine,
  210. which can print a message, set flags, or whatever.
  211. .UL longjmp
  212. takes as argument an object stored into by
  213. .UL setjmp ,
  214. and restores control
  215. to the location after the call to
  216. .UL setjmp ,
  217. so control (and the stack level) will pop back
  218. to the place in the main routine where
  219. the signal is set up and the main loop entered.
  220. Notice, by the way, that
  221. the signal
  222. gets set again after an interrupt occurs.
  223. This is necessary; most signals are automatically
  224. reset to their default action when they occur.
  225. .PP
  226. Some programs that want to detect signals simply can't be stopped
  227. at an arbitrary point,
  228. for example in the middle of updating a linked list.
  229. If the routine called on occurrence of a signal
  230. sets a flag and then
  231. returns instead of calling
  232. .UL exit
  233. or
  234. .UL longjmp ,
  235. execution will continue
  236. at the exact point it was interrupted.
  237. The interrupt flag can then be tested later.
  238. .PP
  239. There is one difficulty associated with this
  240. approach.
  241. Suppose the program is reading the
  242. terminal when the interrupt is sent.
  243. The specified routine is duly called; it sets its flag
  244. and returns.
  245. If it were really true, as we said
  246. above, that ``execution resumes at the exact point it was interrupted,''
  247. the program would continue reading the terminal
  248. until the user typed another line.
  249. This behavior might well be confusing, since the user
  250. might not know that the program is reading;
  251. he presumably would prefer to have the signal take effect instantly.
  252. The method chosen to resolve this difficulty
  253. is to terminate the terminal read when execution
  254. resumes after the signal, returning an error code
  255. which indicates what happened.
  256. .PP
  257. Thus programs which catch and resume
  258. execution after signals should be prepared for ``errors''
  259. which are caused by interrupted
  260. system calls.
  261. (The ones to watch out for are reads from a terminal,
  262. .UL wait ,
  263. and
  264. .UL pause .)
  265. A program
  266. whose
  267. .UL onintr
  268. program just sets
  269. .UL intflag ,
  270. resets the interrupt signal, and returns,
  271. should usually include code like the following when it reads
  272. the standard input:
  273. .P1
  274. if (getchar() == EOF)
  275. if (intflag)
  276. /* EOF caused by interrupt */
  277. else
  278. /* true end-of-file */
  279. .P2
  280. .PP
  281. A final subtlety to keep in mind becomes important
  282. when signal-catching is combined with execution of other programs.
  283. Suppose a program catches interrupts, and also includes
  284. a method (like ``!'' in the editor)
  285. whereby other programs can be executed.
  286. Then the code should look something like this:
  287. .P1
  288. if (fork() == 0)
  289. execl(...);
  290. signal(SIGINT, SIG_IGN); /* ignore interrupts */
  291. wait(&status); /* until the child is done */
  292. signal(SIGINT, onintr); /* restore interrupts */
  293. .P2
  294. Why is this?
  295. Again, it's not obvious but not really difficult.
  296. Suppose the program you call catches its own interrupts.
  297. If you interrupt the subprogram,
  298. it will get the signal and return to its
  299. main loop, and probably read your terminal.
  300. But the calling program will also pop out of
  301. its wait for the subprogram and read your terminal.
  302. Having two processes reading
  303. your terminal is very unfortunate,
  304. since the system figuratively flips a coin to decide
  305. who should get each line of input.
  306. A simple way out is to have the parent program
  307. ignore interrupts until the child is done.
  308. This reasoning is reflected in the standard I/O library function
  309. .UL system :
  310. .P1
  311. #include <signal.h>
  312. system(s) /* run command string s */
  313. char *s;
  314. {
  315. int status, pid, w;
  316. register int (*istat)(), (*qstat)();
  317. if ((pid = fork()) == 0) {
  318. execl("/bin/sh", "sh", "-c", s, 0);
  319. _exit(127);
  320. }
  321. istat = signal(SIGINT, SIG_IGN);
  322. qstat = signal(SIGQUIT, SIG_IGN);
  323. while ((w = wait(&status)) != pid && w != -1)
  324. ;
  325. if (w == -1)
  326. status = -1;
  327. signal(SIGINT, istat);
  328. signal(SIGQUIT, qstat);
  329. return(status);
  330. }
  331. .P2
  332. .PP
  333. As an aside on declarations,
  334. the function
  335. .UL signal
  336. obviously has a rather strange second argument.
  337. It is in fact a pointer to a function delivering an integer,
  338. and this is also the type of the signal routine itself.
  339. The two values
  340. .UL SIG_IGN
  341. and
  342. .UL SIG_DFL
  343. have the right type, but are chosen so they coincide with
  344. no possible actual functions.
  345. For the enthusiast, here is how they are defined for the PDP-11;
  346. the definitions should be sufficiently ugly
  347. and nonportable to encourage use of the include file.
  348. .P1
  349. #define SIG_DFL (int (*)())0
  350. #define SIG_IGN (int (*)())1
  351. .P2