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