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*                  Common Public License, Version 1.0                  *
7*                    by AT&T Intellectual Property                     *
8*                                                                      *
9*                A copy of the License is available at                 *
10*            http://www.opensource.org/licenses/cpl1.0.txt             *
11*         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
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
33static struct
34{
35	int	sig;
36	int	op;
37}
38signals[] =		/* 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
70static long	hold;			/* held signal mask		*/
71
72/*
73 * hold last signal for later delivery
74 */
75
76static void
77interrupt(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
95int
96sigcritical(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