summaryrefslogtreecommitdiff
path: root/libc/sysdeps/linux/common/bits/sigset.h
blob: f220e817170bb08d46008dac14eceea05a0d44fd (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
/* __sig_atomic_t, __sigset_t, and related definitions.  Linux version.
   Copyright (C) 1991, 1992, 1994, 1996, 1997 Free Software Foundation, Inc.
   This file is part of the GNU C Library.

   The GNU C Library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Lesser General Public
   License as published by the Free Software Foundation; either
   version 2.1 of the License, or (at your option) any later version.

   The GNU C Library is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   Lesser General Public License for more details.

   You should have received a copy of the GNU Lesser General Public
   License along with the GNU C Library; if not, see
   <http://www.gnu.org/licenses/>.  */

#ifndef	_SIGSET_H_types
# define _SIGSET_H_types	1

typedef int __sig_atomic_t;

/* A 'sigset_t' has a bit for each signal.
 * glibc has space for 1024 signals (!), but most arches supported
 * by Linux have 64 signals, and only MIPS has 128.
 * There seems to be some historical baggage in sparc[64]
 * where they might have (or had in the past) 32 signals only,
 * I hope it's irrelevant now.
 * Signal 0 does not exist, so we have signals 1..64, not 0..63.
 * In uclibc, kernel and userspace sigset_t is always the same.
 * BTW, struct sigaction is also the same on kernel and userspace side.
 */
#if defined(__mips__)
# define _SIGSET_NWORDS	(128 / (8 * sizeof (unsigned long)))
#else
# define _SIGSET_NWORDS	(64 / (8 * sizeof (unsigned long)))
#endif
typedef struct {
	unsigned long __val[_SIGSET_NWORDS];
} __sigset_t;

#endif


/* We only want to define these functions if <signal.h> was actually
   included; otherwise we were included just to define the types.  Since we
   are namespace-clean, it wouldn't hurt to define extra macros.  But
   trouble can be caused by functions being defined (e.g., any global
   register vars declared later will cause compilation errors).  */

#if !defined _SIGSET_H_fns && defined _SIGNAL_H
# define _SIGSET_H_fns 1

/* Return a mask that includes the bit for SIG only.  */
/* Unsigned cast ensures shift/mask insns are used.  */
# define __sigmask(sig) \
  (((unsigned long) 1) << ((unsigned)((sig) - 1) % (8 * sizeof (unsigned long))))

/* Return the word index for SIG.  */
# define __sigword(sig)	((unsigned)((sig) - 1) / (8 * sizeof (unsigned long)))

/* gcc 4.3.1 is not clever enough to optimize for _SIGSET_NWORDS == 1 and 2,
 * which are about the only values which can be there */

# if defined __GNUC__ && __GNUC__ >= 2
#  define __sigemptyset(set) \
(__extension__ ({ \
	sigset_t *__set = (set);					\
	if (_SIGSET_NWORDS <= 2) {					\
		__set->__val[0] = 0;					\
		if (_SIGSET_NWORDS == 2)				\
			__set->__val[1] = 0;				\
	} else {							\
		int __cnt = _SIGSET_NWORDS;				\
		while (--__cnt >= 0) __set->__val[__cnt] = 0;		\
	}								\
	0;								\
}))
#  define __sigfillset(set) \
(__extension__ ({ \
	sigset_t *__set = (set);					\
	if (_SIGSET_NWORDS <= 2) {					\
		__set->__val[0] = ~0UL;					\
		if (_SIGSET_NWORDS == 2)				\
			__set->__val[1] = ~0UL;				\
	} else {							\
		int __cnt = _SIGSET_NWORDS;				\
		while (--__cnt >= 0) __set->__val[__cnt] = ~0UL;	\
	}								\
	0;								\
}))

#  ifdef __USE_GNU
/* The POSIX does not specify for handling the whole signal set in one
   command.  This is often wanted and so we define three more functions
   here.  */
#   define __sigisemptyset(set) \
(__extension__ ({ \
	long __ret;							\
	const sigset_t *__set = (set);					\
	if (_SIGSET_NWORDS == 1) {					\
		__ret = __set->__val[0];				\
	} else if (_SIGSET_NWORDS == 2) {				\
		__ret = __set->__val[0] | __set->__val[1];		\
	} else {							\
		int __cnt = _SIGSET_NWORDS;				\
		__ret = __set->__val[--__cnt];				\
		while (!__ret && --__cnt >= 0)				\
			__ret = __set->__val[__cnt];			\
	}								\
	__ret == 0;							\
}))
#   define __sigandset(dest, left, right) \
(__extension__ ({ \
	sigset_t *__dest = (dest);					\
	const sigset_t *__left = (left);				\
	const sigset_t *__right = (right);				\
	if (_SIGSET_NWORDS <= 2) {					\
		__dest->__val[0] = __left->__val[0] & __right->__val[0];\
		if (_SIGSET_NWORDS == 2)				\
			__dest->__val[1] = __left->__val[1] & __right->__val[1];\
	} else {							\
		int __cnt = _SIGSET_NWORDS;				\
		while (--__cnt >= 0)					\
			__dest->__val[__cnt] = (__left->__val[__cnt]	\
					& __right->__val[__cnt]);	\
	}								\
	0;								\
}))
#   define __sigorset(dest, left, right) \
(__extension__ ({ \
	sigset_t *__dest = (dest);					\
	const sigset_t *__left = (left);				\
	const sigset_t *__right = (right);				\
	if (_SIGSET_NWORDS <= 2) {					\
		__dest->__val[0] = __left->__val[0] | __right->__val[0];\
		if (_SIGSET_NWORDS == 2)				\
			__dest->__val[1] = __left->__val[1] | __right->__val[1];\
	} else {							\
		int __cnt = _SIGSET_NWORDS;				\
		while (--__cnt >= 0)					\
			__dest->__val[__cnt] = (__left->__val[__cnt]	\
					| __right->__val[__cnt]);	\
	}								\
	0;								\
}))
#  endif
# endif

/* These functions needn't check for a bogus signal number -- error
   checking is done in the non __ versions.  */

# if !defined __USE_EXTERN_INLINES || defined __PROVIDE_OUT_OF_LINE_SIGSETFN
extern int __sigismember (const __sigset_t *, int);
libc_hidden_proto(__sigismember)
extern void __sigaddset (__sigset_t *, int);
libc_hidden_proto(__sigaddset)
extern void __sigdelset (__sigset_t *, int);
libc_hidden_proto(__sigdelset)
# endif

# ifdef __USE_EXTERN_INLINES
#  undef _EXTERN_INLINE
#  ifdef __PROVIDE_OUT_OF_LINE_SIGSETFN
#   define _EXTERN_INLINE
#  else /* normal case */
    /* dropped extern below: otherwise every module with __USE_EXTERN_INLINES
     * will have its own copy of out-of line function emitted. */
#   define _EXTERN_INLINE /*extern*/ __always_inline
#  endif
#  define __SIGSETFN(RET_TYPE, NAME, BODY, CONST)			\
_EXTERN_INLINE RET_TYPE							\
NAME (CONST __sigset_t *__set, int __sig)				\
{									\
	unsigned long __mask = __sigmask (__sig);			\
	unsigned __word = __sigword (__sig);				\
	BODY;							\
}

__SIGSETFN (int, __sigismember, return (__set->__val[__word] & __mask) ? 1 : 0,
	const)
__SIGSETFN (void, __sigaddset, (__set->__val[__word] |= __mask), )
__SIGSETFN (void, __sigdelset, (__set->__val[__word] &= ~__mask), )

#  undef __SIGSETFN
# endif

# ifdef _LIBC
/* It's far too much PITA to __USE_EXTERN_INLINES from within libc.
 * Especially since we want to inline only calls with const sig,
 * but __USE_EXTERN_INLINES will inline all calls!
 */
static __always_inline unsigned long
const_sigismember(const __sigset_t *set, int sig)
{
	unsigned long mask = __sigmask(sig);
	unsigned word = __sigword(sig);
	return (set->__val[word] & mask);
}
#  define __sigismember(set, sig) \
	(__builtin_constant_p(sig) ? (const_sigismember(set, sig) != 0) : __sigismember(set, sig))
static __always_inline void
const_sigaddset(__sigset_t *set, int sig)
{
	unsigned long mask = __sigmask(sig);
	unsigned word = __sigword(sig);
	set->__val[word] |= mask;
}
#  define __sigaddset(set, sig) \
	(__builtin_constant_p(sig) ? const_sigaddset(set, sig)  : __sigaddset(set, sig))
static __always_inline void
const_sigdelset(__sigset_t *set, int sig)
{
	unsigned long mask = __sigmask(sig);
	unsigned word = __sigword(sig);
	set->__val[word] &= ~mask;
}
#  define __sigdelset(set, sig) \
	(__builtin_constant_p(sig) ? const_sigdelset(set, sig) : __sigdelset(set, sig))
# endif

#endif /* ! _SIGSET_H_fns.  */