1 /***********************************************************************
2 *                                                                      *
3 *               This software is part of the ast package               *
4 *          Copyright (c) 1985-2011 AT&T Intellectual Property          *
5 *                      and is licensed under the                       *
6 *                 Eclipse Public License, Version 1.0                  *
7 *                    by AT&T Intellectual Property                     *
8 *                                                                      *
9 *                A copy of the License is available at                 *
10 *          http://www.eclipse.org/org/documents/epl-v10.html           *
11 *         (with md5 checksum b35adb5213ca9657e911e9befb180842)         *
12 *                                                                      *
13 *              Information and Software Systems Research               *
14 *                            AT&T Research                             *
15 *                           Florham Park NJ                            *
16 *                                                                      *
17 *                 Glenn Fowler <gsf@research.att.com>                  *
18 *                  David Korn <dgk@research.att.com>                   *
19 *                   Phong Vo <kpv@research.att.com>                    *
20 *                                                                      *
21 ***********************************************************************/
22 #pragma prototyped
23 /*
24  * Glenn Fowler
25  * AT&T Research
26  *
27  * signal critical region support
28  */
29 
30 #include <ast.h>
31 #include <sig.h>
32 
33 static struct
34 {
35 	int	sig;
36 	int	op;
37 }
38 signals[] =		/* held inside critical region	*/
39 {
40 	SIGINT,		SIG_REG_EXEC,
41 #ifdef SIGPIPE
42 	SIGPIPE,	SIG_REG_EXEC,
43 #endif
44 #ifdef SIGQUIT
45 	SIGQUIT,	SIG_REG_EXEC,
46 #endif
47 #ifdef SIGHUP
48 	SIGHUP,		SIG_REG_EXEC,
49 #endif
50 #if defined(SIGCHLD) && ( !defined(SIGCLD) || SIGCHLD != SIGCLD || _lib_sigprocmask || _lib_sigsetmask )
51 	SIGCHLD,	SIG_REG_PROC,
52 #endif
53 #ifdef SIGTSTP
54 	SIGTSTP,	SIG_REG_TERM,
55 #endif
56 #ifdef SIGTTIN
57 	SIGTTIN,	SIG_REG_TERM,
58 #endif
59 #ifdef SIGTTOU
60 	SIGTTOU,	SIG_REG_TERM,
61 #endif
62 };
63 
64 #ifndef SIG_SETMASK
65 #undef	_lib_sigprocmask
66 #endif
67 
68 #if !_lib_sigprocmask && !_lib_sigsetmask
69 
70 static long	hold;			/* held signal mask		*/
71 
72 /*
73  * hold last signal for later delivery
74  */
75 
76 static void
interrupt(int sig)77 interrupt(int sig)
78 {
79 	signal(sig, interrupt);
80 	hold |= sigmask(sig);
81 }
82 
83 #endif
84 
85 /*
86  * critical signal region handler
87  *
88  * op>0		new region according to SIG_REG_*, return region level
89  * op==0	pop region, return region level
90  * op<0		return non-zero if any signals held in current region
91  *
92  * signals[] held until region popped
93  */
94 
95 int
sigcritical(int op)96 sigcritical(int op)
97 {
98 	register int		i;
99 	static int		region;
100 	static int		level;
101 #if _lib_sigprocmask
102 	static sigset_t		mask;
103 	sigset_t		nmask;
104 #else
105 #if _lib_sigsetmask
106 	static long		mask;
107 #else
108 	static Sig_handler_t	handler[elementsof(signals)];
109 #endif
110 #endif
111 
112 	if (op > 0)
113 	{
114 		if (!level++)
115 		{
116 			region = op;
117 			if (op & SIG_REG_SET)
118 				level--;
119 #if _lib_sigprocmask
120 			sigemptyset(&nmask);
121 			for (i = 0; i < elementsof(signals); i++)
122 				if (op & signals[i].op)
123 					sigaddset(&nmask, signals[i].sig);
124 			sigprocmask(SIG_BLOCK, &nmask, &mask);
125 #else
126 #if _lib_sigsetmask
127 			mask = 0;
128 			for (i = 0; i < elementsof(signals); i++)
129 				if (op & signals[i].op)
130 					mask |= sigmask(signals[i].sig);
131 			mask = sigblock(mask);
132 #else
133 			hold = 0;
134 			for (i = 0; i < elementsof(signals); i++)
135 				if ((op & signals[i].op) && (handler[i] = signal(signals[i].sig, interrupt)) == SIG_IGN)
136 				{
137 					signal(signals[i].sig, handler[i]);
138 					hold &= ~sigmask(signals[i].sig);
139 				}
140 #endif
141 #endif
142 		}
143 		return level;
144 	}
145 	else if (op < 0)
146 	{
147 #if _lib_sigprocmask
148 		sigpending(&nmask);
149 		for (i = 0; i < elementsof(signals); i++)
150 			if (region & signals[i].op)
151 			{
152 				if (sigismember(&nmask, signals[i].sig))
153 					return 1;
154 			}
155 		return 0;
156 #else
157 #if _lib_sigsetmask
158 		/* no way to get pending signals without installing handler */
159 		return 0;
160 #else
161 		return hold != 0;
162 #endif
163 #endif
164 	}
165 	else
166 	{
167 		/*
168 		 * a vfork() may have intervened so we
169 		 * allow apparent nesting mismatches
170 		 */
171 
172 		if (--level <= 0)
173 		{
174 			level = 0;
175 #if _lib_sigprocmask
176 			sigprocmask(SIG_SETMASK, &mask, NiL);
177 #else
178 #if _lib_sigsetmask
179 			sigsetmask(mask);
180 #else
181 			for (i = 0; i < elementsof(signals); i++)
182 				if (region & signals[i].op)
183 					signal(signals[i].sig, handler[i]);
184 			if (hold)
185 			{
186 				for (i = 0; i < elementsof(signals); i++)
187 					if (region & signals[i].op)
188 					{
189 						if (hold & sigmask(signals[i].sig))
190 							kill(getpid(), signals[i].sig);
191 					}
192 				pause();
193 			}
194 #endif
195 #endif
196 		}
197 		return level;
198 	}
199 }
200