1314817Sngie/* $NetBSD: t_sigqueue.c,v 1.7 2017/01/13 20:44:10 christos Exp $ */
2272343Sngie
3272343Sngie/*-
4272343Sngie * Copyright (c) 2011 The NetBSD Foundation, Inc.
5272343Sngie * All rights reserved.
6272343Sngie *
7272343Sngie * This code is derived from software contributed to The NetBSD Foundation
8272343Sngie * by Christos Zoulas.
9272343Sngie *
10272343Sngie * Redistribution and use in source and binary forms, with or without
11272343Sngie * modification, are permitted provided that the following conditions
12272343Sngie * are met:
13272343Sngie * 1. Redistributions of source code must retain the above copyright
14272343Sngie *    notice, this list of conditions and the following disclaimer.
15272343Sngie * 2. Redistributions in binary form must reproduce the above copyright
16272343Sngie *    notice, this list of conditions and the following disclaimer in the
17272343Sngie *    documentation and/or other materials provided with the distribution.
18272343Sngie *
19272343Sngie * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20272343Sngie * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21272343Sngie * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22272343Sngie * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23272343Sngie * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24272343Sngie * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25272343Sngie * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26272343Sngie * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27272343Sngie * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28272343Sngie * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29272343Sngie * POSSIBILITY OF SUCH DAMAGE.
30272343Sngie */
31272343Sngie
32272343Sngie#include <sys/cdefs.h>
33314817Sngie__RCSID("$NetBSD: t_sigqueue.c,v 1.7 2017/01/13 20:44:10 christos Exp $");
34272343Sngie
35272343Sngie#include <atf-c.h>
36314817Sngie#include <err.h>
37272343Sngie#include <errno.h>
38272343Sngie#include <signal.h>
39314817Sngie#include <stdio.h>
40272343Sngie#include <stdlib.h>
41272343Sngie#include <sched.h>
42272343Sngie#include <unistd.h>
43272343Sngie
44272343Sngiestatic void	handler(int, siginfo_t *, void *);
45272343Sngie
46272343Sngie#define VALUE (int)0xc001dad1
47272343Sngiestatic int value;
48272343Sngie
49272343Sngiestatic void
50314817Sngiehandler(int signo __unused, siginfo_t *info, void *data __unused)
51272343Sngie{
52272343Sngie	value = info->si_value.sival_int;
53272343Sngie	kill(0, SIGINFO);
54272343Sngie}
55272343Sngie
56272343SngieATF_TC(sigqueue_basic);
57272343SngieATF_TC_HEAD(sigqueue_basic, tc)
58272343Sngie{
59272343Sngie	atf_tc_set_md_var(tc, "descr", "Checks sigqueue(3) sigval delivery");
60272343Sngie}
61272343Sngie
62272343SngieATF_TC_BODY(sigqueue_basic, tc)
63272343Sngie{
64272343Sngie	struct sigaction sa;
65272343Sngie	union sigval sv;
66272343Sngie
67272343Sngie	sa.sa_sigaction = handler;
68272343Sngie	sigemptyset(&sa.sa_mask);
69272343Sngie	sa.sa_flags = SA_SIGINFO;
70272343Sngie
71272343Sngie	if (sigaction(SIGUSR1, &sa, NULL) != 0)
72272343Sngie		atf_tc_fail("sigaction failed");
73272343Sngie
74272343Sngie	sv.sival_int = VALUE;
75272343Sngie
76276478Sngie#ifdef __FreeBSD__
77313498Sngie	/*
78276478Sngie	 * From kern_sig.c:
79276478Sngie	 * Specification says sigqueue can only send signal to single process.
80276478Sngie	 */
81276478Sngie	if (sigqueue(getpid(), SIGUSR1, sv) != 0)
82276478Sngie#else
83272343Sngie	if (sigqueue(0, SIGUSR1, sv) != 0)
84276478Sngie#endif
85272343Sngie		atf_tc_fail("sigqueue failed");
86272343Sngie
87272343Sngie	sched_yield();
88272343Sngie	ATF_REQUIRE_EQ(sv.sival_int, value);
89272343Sngie}
90272343Sngie
91272343SngieATF_TC(sigqueue_err);
92272343SngieATF_TC_HEAD(sigqueue_err, tc)
93272343Sngie{
94272343Sngie	atf_tc_set_md_var(tc, "descr", "Test errors from sigqueue(3)");
95272343Sngie}
96272343Sngie
97272343SngieATF_TC_BODY(sigqueue_err, tc)
98272343Sngie{
99313498Sngie	static union sigval sv;
100272343Sngie
101272343Sngie	errno = 0;
102272343Sngie	ATF_REQUIRE_ERRNO(EINVAL, sigqueue(getpid(), -1, sv) == -1);
103272343Sngie}
104272343Sngie
105313498Sngiestatic int signals[] = {
106313498Sngie	SIGINT, SIGRTMIN + 1, SIGINT, SIGRTMIN + 0, SIGRTMIN + 2,
107313498Sngie	SIGQUIT, SIGRTMIN + 1
108313498Sngie};
109313498Sngie#ifdef __arraycount
110313498Sngie#define CNT	__arraycount(signals)
111313498Sngie#else
112313498Sngie#define CNT	(sizeof(signals) / sizeof(signals[0]))
113313498Sngie#endif
114313498Sngie
115313498Sngiestatic sig_atomic_t count = 0;
116313498Sngiestatic int delivered[CNT];
117313498Sngie
118313498Sngiestatic void
119314817Sngiemyhandler(int signo, siginfo_t *info, void *context __unused)
120313498Sngie{
121313498Sngie	delivered[count++] = signo;
122313498Sngie	printf("Signal #%zu: signo: %d\n", (size_t)count, signo);
123313498Sngie}
124313498Sngie
125313498Sngiestatic int
126313498Sngieasc(const void *a, const void *b)
127313498Sngie{
128313498Sngie	const int *ia = a, *ib = b;
129313498Sngie	return *ib - *ia;
130313498Sngie}
131313498Sngie
132313498Sngie/*
133313498Sngie * given a array of signals to be delivered in tosend of size len
134313498Sngie * place in ordered the signals to be delivered in delivery order
135313498Sngie * and return the number of signals that should be delivered
136313498Sngie */
137313498Sngiestatic size_t
138313498Sngiesigorder(int *ordered, const int *tosend, size_t len)
139313498Sngie{
140313498Sngie	memcpy(ordered, tosend, len * sizeof(*tosend));
141313498Sngie	qsort(ordered, len, sizeof(*ordered), asc);
142313498Sngie	if (len == 1)
143313498Sngie		return len;
144313498Sngie
145313498Sngie#ifdef __FreeBSD__
146313498Sngie	/*
147313498Sngie	 * Don't dedupe signal numbers (bug 212173)
148313498Sngie	 *
149313498Sngie	 * Per kib's comment..
150313498Sngie	 *
151313498Sngie	 * "
152313498Sngie	 * OTOH, FreeBSD behaviour is to treat all signals as realtime while
153313498Sngie	 * there is no mem shortage and siginfo can be allocated.  In
154313498Sngie	 * particular, signals < SIGRTMIN are not collapsed when queued more
155313498Sngie	 * than once.
156313498Sngie	 * "
157313498Sngie	 */
158313498Sngie
159313498Sngie	return len;
160313498Sngie#else
161313498Sngie
162313498Sngie	size_t i, j;
163313498Sngie	for (i = 0, j = 0; i < len - 1; i++) {
164313498Sngie		if (ordered[i] >= SIGRTMIN)
165313498Sngie			continue;
166313498Sngie		if (j == 0)
167313498Sngie			j = i + 1;
168313498Sngie		while (ordered[i] == ordered[j] && j < len)
169313498Sngie			j++;
170313498Sngie		if (j == len)
171313498Sngie			break;
172313498Sngie		ordered[i + 1] = ordered[j];
173313498Sngie	}
174313498Sngie	return i + 1;
175313498Sngie#endif
176313498Sngie}
177313498Sngie
178313498SngieATF_TC(sigqueue_rt);
179313498SngieATF_TC_HEAD(sigqueue_rt, tc)
180313498Sngie{
181313498Sngie	atf_tc_set_md_var(tc, "descr", "Test queuing of real-time signals");
182313498Sngie}
183313498Sngie
184313498SngieATF_TC_BODY(sigqueue_rt, tc)
185313498Sngie{
186313498Sngie	pid_t pid;
187313498Sngie	union sigval val;
188313498Sngie	struct sigaction act;
189313498Sngie	int ordered[CNT];
190313498Sngie	struct sigaction oact[CNT];
191313498Sngie	size_t ndelivered;
192313498Sngie
193313498Sngie	ndelivered = sigorder(ordered, signals, CNT);
194313498Sngie
195313498Sngie	act.sa_flags = SA_SIGINFO;
196313498Sngie	act.sa_sigaction = myhandler;
197313498Sngie	sigemptyset(&act.sa_mask);
198313498Sngie	for (size_t i = 0; i < ndelivered; i++)
199313498Sngie		ATF_REQUIRE(sigaction(ordered[i], &act, &oact[i]) != -1);
200313498Sngie
201313498Sngie	val.sival_int = 0;
202313498Sngie	pid = getpid();
203313498Sngie
204313498Sngie	sigset_t mask, orig;
205313498Sngie	sigemptyset(&mask);
206313498Sngie	for (size_t i = 0; i < CNT; i++)
207313498Sngie		if (sigaddset(&mask, signals[i]) == -1)
208313498Sngie			warn("sigaddset");
209313498Sngie
210313498Sngie	ATF_REQUIRE(sigprocmask(SIG_BLOCK, &mask, &orig) != -1);
211313498Sngie
212313498Sngie	for (size_t i = 0; i < CNT; i++)
213313498Sngie		ATF_REQUIRE(sigqueue(pid, signals[i], val) != -1);
214313498Sngie
215313498Sngie	ATF_REQUIRE(sigprocmask(SIG_UNBLOCK, &mask, &orig) != -1);
216313498Sngie	sleep(1);
217313498Sngie	ATF_CHECK_MSG((size_t)count == ndelivered,
218313498Sngie	    "count %zu != ndelivered %zu", (size_t)count, ndelivered);
219313498Sngie	for (size_t i = 0; i < ndelivered; i++)
220313498Sngie		ATF_REQUIRE_MSG(ordered[i] == delivered[i],
221313498Sngie		    "%zu: ordered %d != delivered %d",
222313498Sngie		    i, ordered[i], delivered[i]);
223313498Sngie
224314817Sngie	if ((size_t)count > ndelivered)
225314817Sngie		for (size_t i = ndelivered; i < (size_t)count; i++)
226313498Sngie			printf("Undelivered signal #%zu: %d\n", i, ordered[i]);
227313498Sngie
228313498Sngie	for (size_t i = 0; i < ndelivered; i++)
229313498Sngie		ATF_REQUIRE(sigaction(signals[i], &oact[i], NULL) != -1);
230313498Sngie}
231313498Sngie
232272343SngieATF_TP_ADD_TCS(tp)
233272343Sngie{
234272343Sngie
235272343Sngie	ATF_TP_ADD_TC(tp, sigqueue_basic);
236272343Sngie	ATF_TP_ADD_TC(tp, sigqueue_err);
237313498Sngie	ATF_TP_ADD_TC(tp, sigqueue_rt);
238272343Sngie
239272343Sngie	return atf_no_error();
240272343Sngie}
241