|
|
1.1 root 1: /*
2: * Copyright (c) 1980 Regents of the University of California.
3: * All rights reserved.
4: *
5: * Redistribution and use in source and binary forms are permitted
6: * provided that this notice is preserved and that due credit is given
7: * to the University of California at Berkeley. The name of the University
8: * may not be used to endorse or promote products derived from this
9: * software without specific prior written permission. This software
10: * is provided ``as is'' without express or implied warranty.
11: */
12:
13: #ifdef notdef
14: static char sccsid[] = "@(#)sigretro.c 5.3 (Berkeley) 2/18/88";
15: #endif /* notdef */
16:
17: #include <signal.h>
18: #include <errno.h>
19: #include <setjmp.h>
20: #include "sigretro.h"
21:
22: /*
23: * Retrofit new signal interface to old signal primitives.
24: * Supported routines:
25: * sigsys(sig, func)
26: * sigset(sig, func)
27: * sighold(sig)
28: * sigrelse(sig)
29: * sigignore(sig)
30: * sigpause(sig)
31: * Also,
32: * sigchild()
33: * to set all held signals to ignored signals in the
34: * child process after fork(2)
35: */
36:
37: typedef int (*sigtype)();
38:
39: sigtype sigdisp(), sighold(), sigignore();
40:
41: /*
42: * The following helps us keep the extended signal semantics together.
43: * We remember for each signal the address of the function we're
44: * supposed to call. s_func is SIG_DFL / SIG_IGN if appropriate.
45: */
46: struct sigtable {
47: sigtype s_func; /* What to call */
48: int s_flag; /* Signal flags; see below */
49: } sigtable[NSIG + 1];
50:
51: /*
52: * Signal flag values.
53: */
54: #define SHELD 1 /* Signal is being held */
55: #define SDEFER 2 /* Signal occured while held */
56: #define SSET 4 /* s_func is believable */
57: #define SPAUSE 8 /* are pausing, waiting for sig */
58:
59: jmp_buf _pause; /* For doing sigpause() */
60:
61: /*
62: * Approximate sigsys() system call
63: * This is almost useless since one only calls sigsys()
64: * in the child of a vfork(). If you have vfork(), you have new signals
65: * anyway. The real sigsys() does all the stuff needed to support
66: * the real sigset() library. We don't bother here, assuming that
67: * you are either ignoring or defaulting a signal in the child.
68: */
69: sigtype
70: sigsys(sig, func)
71: sigtype func;
72: {
73: sigtype old;
74:
75: old = sigdisp(sig);
76: signal(sig, func);
77: return(old);
78: }
79:
80: /*
81: * Set the (permanent) disposition of a signal.
82: * If the signal is subsequently (or even now) held,
83: * the action you set here can be enabled using sigrelse().
84: */
85: sigtype
86: sigset(sig, func)
87: sigtype func;
88: {
89: sigtype old;
90: int _sigtramp();
91: extern int errno;
92:
93: if (sig < 1 || sig > NSIG) {
94: errno = EINVAL;
95: return(BADSIG);
96: }
97: old = sigdisp(sig);
98: /*
99: * Does anyone actually call sigset with SIG_HOLD!?
100: */
101: if (func == SIG_HOLD) {
102: sighold(sig);
103: return(old);
104: }
105: sigtable[sig].s_flag |= SSET;
106: sigtable[sig].s_func = func;
107: if (func == SIG_DFL) {
108: /*
109: * If signal has been held, must retain
110: * the catch so that we can note occurrance
111: * of signal.
112: */
113: if ((sigtable[sig].s_flag & SHELD) == 0)
114: signal(sig, SIG_DFL);
115: else
116: signal(sig, _sigtramp);
117: return(old);
118: }
119: if (func == SIG_IGN) {
120: /*
121: * Clear pending signal
122: */
123: signal(sig, SIG_IGN);
124: sigtable[sig].s_flag &= ~SDEFER;
125: return(old);
126: }
127: signal(sig, _sigtramp);
128: return(old);
129: }
130:
131: /*
132: * Hold a signal.
133: * This CAN be tricky if the signal's disposition is SIG_DFL.
134: * In that case, we still catch the signal so we can note it
135: * happened and do something crazy later.
136: */
137: sigtype
138: sighold(sig)
139: {
140: sigtype old;
141: extern int errno;
142:
143: if (sig < 1 || sig > NSIG) {
144: errno = EINVAL;
145: return(BADSIG);
146: }
147: old = sigdisp(sig);
148: if (sigtable[sig].s_flag & SHELD)
149: return(old);
150: /*
151: * When the default action is required, we have to
152: * set up to catch the signal to note signal's occurrance.
153: */
154: if (old == SIG_DFL) {
155: sigtable[sig].s_flag |= SSET;
156: signal(sig, _sigtramp);
157: }
158: sigtable[sig].s_flag |= SHELD;
159: return(old);
160: }
161:
162: /*
163: * Release a signal
164: * If the signal occurred while we had it held, cause the signal.
165: */
166: sigtype
167: sigrelse(sig)
168: {
169: sigtype old;
170: extern int errno;
171: int _sigtramp();
172:
173: if (sig < 1 || sig > NSIG) {
174: errno = EINVAL;
175: return(BADSIG);
176: }
177: old = sigdisp(sig);
178: if ((sigtable[sig].s_flag & SHELD) == 0)
179: return(old);
180: sigtable[sig].s_flag &= ~SHELD;
181: if (sigtable[sig].s_flag & SDEFER)
182: _sigtramp(sig);
183: /*
184: * If disposition was the default, then we can unset the
185: * catch to _sigtramp() and let the system do the work.
186: */
187: if (sigtable[sig].s_func == SIG_DFL)
188: signal(sig, SIG_DFL);
189: return(old);
190: }
191:
192: /*
193: * Ignore a signal.
194: */
195: sigtype
196: sigignore(sig)
197: {
198:
199: return(sigset(sig, SIG_IGN));
200: }
201:
202: /*
203: * Pause, waiting for sig to occur.
204: * We assume LUSER called us with the signal held.
205: * When we got the signal, mark the signal as having
206: * occurred. It will actually cause something when
207: * the signal is released.
208: *
209: * This is probably useless without job control anyway.
210: */
211: sigpause(sig)
212: {
213: extern int errno;
214:
215: if (sig < 1 || sig > NSIG) {
216: errno = EINVAL;
217: return;
218: }
219: sigtable[sig].s_flag |= SHELD|SPAUSE;
220: if (setjmp(_pause) == 0)
221: pause();
222: sigtable[sig].s_flag &= ~SPAUSE;
223: sigtable[sig].s_flag |= SDEFER;
224: }
225:
226: /*
227: * In the child process after fork(2), set the disposition of all held
228: * signals to SIG_IGN. This is a new procedure not in the real sigset()
229: * package, provided for retrofitting purposes.
230: */
231: sigchild()
232: {
233: register int i;
234:
235: for (i = 1; i <= NSIG; i++)
236: if (sigtable[i].s_flag & SHELD)
237: signal(i, SIG_IGN);
238: }
239:
240: /*
241: * Return the current disposition of a signal
242: * If we have not set this signal before, we have to
243: * ask the system
244: */
245: sigtype
246: sigdisp(sig)
247: {
248: extern int errno;
249: sigtype old;
250:
251: if (sig < 1 || sig > NSIG) {
252: errno = EINVAL;
253: return(BADSIG);
254: }
255: /*
256: * If we have no knowledge of this signal,
257: * ask the system, then save the result for later.
258: */
259: if ((sigtable[sig].s_flag & SSET) == 0) {
260: old = signal(sig, SIG_IGN);
261: sigtable[sig].s_func = old;
262: sigtable[sig].s_flag |= SSET;
263: signal(sig, old);
264: return(old);
265: }
266: /*
267: * If we have set this signal before, then sigset()
268: * will have been careful to leave something meaningful
269: * in s_func.
270: */
271: return(sigtable[sig].s_func);
272: }
273:
274: /*
275: * The following routine gets called for any signal
276: * that is to be trapped to a user function.
277: */
278: _sigtramp(sig)
279: {
280: extern int errno;
281: sigtype old;
282:
283: if (sig < 1 || sig > NSIG) {
284: errno = EINVAL;
285: return;
286: }
287:
288: top:
289: old = signal(sig, SIG_IGN);
290: /*
291: * If signal being paused on, wakeup sigpause()
292: */
293: if (sigtable[sig].s_flag & SPAUSE)
294: longjmp(_pause, 1);
295: /*
296: * If signal being held, mark its table entry
297: * so we can trigger it when signal released.
298: * Then just return.
299: */
300: if (sigtable[sig].s_flag & SHELD) {
301: sigtable[sig].s_flag |= SDEFER;
302: signal(sig, _sigtramp);
303: return;
304: }
305: /*
306: * If the signal is being ignored, just return.
307: * This would make SIGCONT more normal, but of course
308: * any system with SIGCONT also has the new signal pkg, so...
309: */
310: if (sigtable[sig].s_func == SIG_IGN)
311: return;
312: /*
313: * If the signal is SIG_DFL, then we probably got here
314: * by holding the signal, having it happen, then releasing
315: * the signal. I wonder if a process is allowed to send
316: * a signal to itself?
317: */
318: if (sigtable[sig].s_func == SIG_DFL) {
319: signal(sig, SIG_DFL);
320: kill(getpid(), sig);
321: /* Will we get back here? */
322: return;
323: }
324: /*
325: * Looks like we should just cause the signal...
326: * We hold the signal for the duration of the user's
327: * code with the signal re-enabled. If the signal
328: * happens again while in user code, we will recursively
329: * trap here and mark that we had another occurance
330: * and return to the user's trap code. When we return
331: * from there, we can cause the signal again.
332: */
333: sigtable[sig].s_flag &= ~SDEFER;
334: sigtable[sig].s_flag |= SHELD;
335: signal(sig, _sigtramp);
336: (*sigtable[sig].s_func)(sig);
337: /*
338: * If the signal re-occurred while in the user's routine,
339: * just go try it again...
340: */
341: sigtable[sig].s_flag &= ~SHELD;
342: if (sigtable[sig].s_flag & SDEFER)
343: goto top;
344: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.