xref: /netbsd/tests/lib/libc/sys/t_sigqueue.c (revision b685d7fd)
1*b685d7fdSchristos /* $NetBSD: t_sigqueue.c,v 1.7 2017/01/13 20:44:10 christos Exp $ */
2615e5d6aSchristos 
3615e5d6aSchristos /*-
4615e5d6aSchristos  * Copyright (c) 2011 The NetBSD Foundation, Inc.
5615e5d6aSchristos  * All rights reserved.
6615e5d6aSchristos  *
7615e5d6aSchristos  * This code is derived from software contributed to The NetBSD Foundation
8615e5d6aSchristos  * by Christos Zoulas.
9615e5d6aSchristos  *
10615e5d6aSchristos  * Redistribution and use in source and binary forms, with or without
11615e5d6aSchristos  * modification, are permitted provided that the following conditions
12615e5d6aSchristos  * are met:
13615e5d6aSchristos  * 1. Redistributions of source code must retain the above copyright
14615e5d6aSchristos  *    notice, this list of conditions and the following disclaimer.
15615e5d6aSchristos  * 2. Redistributions in binary form must reproduce the above copyright
16615e5d6aSchristos  *    notice, this list of conditions and the following disclaimer in the
17615e5d6aSchristos  *    documentation and/or other materials provided with the distribution.
18615e5d6aSchristos  *
19615e5d6aSchristos  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20615e5d6aSchristos  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21615e5d6aSchristos  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22615e5d6aSchristos  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23615e5d6aSchristos  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24615e5d6aSchristos  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25615e5d6aSchristos  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26615e5d6aSchristos  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27615e5d6aSchristos  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28615e5d6aSchristos  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29615e5d6aSchristos  * POSSIBILITY OF SUCH DAMAGE.
30615e5d6aSchristos  */
31615e5d6aSchristos 
32615e5d6aSchristos #include <sys/cdefs.h>
33*b685d7fdSchristos __RCSID("$NetBSD: t_sigqueue.c,v 1.7 2017/01/13 20:44:10 christos Exp $");
34615e5d6aSchristos 
35615e5d6aSchristos #include <atf-c.h>
36*b685d7fdSchristos #include <err.h>
375167a305Sjruoho #include <errno.h>
385167a305Sjruoho #include <signal.h>
39*b685d7fdSchristos #include <stdio.h>
405167a305Sjruoho #include <stdlib.h>
415167a305Sjruoho #include <sched.h>
425167a305Sjruoho #include <unistd.h>
43615e5d6aSchristos 
445167a305Sjruoho static void	handler(int, siginfo_t *, void *);
45615e5d6aSchristos 
461180b13bSchristos #define VALUE (int)0xc001dad1
47615e5d6aSchristos static int value;
48615e5d6aSchristos 
49615e5d6aSchristos static void
handler(int signo __unused,siginfo_t * info,void * data __unused)50*b685d7fdSchristos handler(int signo __unused, siginfo_t *info, void *data __unused)
51615e5d6aSchristos {
52615e5d6aSchristos 	value = info->si_value.sival_int;
53615e5d6aSchristos 	kill(0, SIGINFO);
54615e5d6aSchristos }
55615e5d6aSchristos 
565167a305Sjruoho ATF_TC(sigqueue_basic);
ATF_TC_HEAD(sigqueue_basic,tc)575167a305Sjruoho ATF_TC_HEAD(sigqueue_basic, tc)
585167a305Sjruoho {
595167a305Sjruoho 	atf_tc_set_md_var(tc, "descr", "Checks sigqueue(3) sigval delivery");
605167a305Sjruoho }
615167a305Sjruoho 
ATF_TC_BODY(sigqueue_basic,tc)625167a305Sjruoho ATF_TC_BODY(sigqueue_basic, tc)
63615e5d6aSchristos {
64615e5d6aSchristos 	struct sigaction sa;
65615e5d6aSchristos 	union sigval sv;
66615e5d6aSchristos 
67615e5d6aSchristos 	sa.sa_sigaction = handler;
68615e5d6aSchristos 	sigemptyset(&sa.sa_mask);
69615e5d6aSchristos 	sa.sa_flags = SA_SIGINFO;
70615e5d6aSchristos 
715167a305Sjruoho 	if (sigaction(SIGUSR1, &sa, NULL) != 0)
725167a305Sjruoho 		atf_tc_fail("sigaction failed");
73615e5d6aSchristos 
74615e5d6aSchristos 	sv.sival_int = VALUE;
755167a305Sjruoho 
765167a305Sjruoho 	if (sigqueue(0, SIGUSR1, sv) != 0)
775167a305Sjruoho 		atf_tc_fail("sigqueue failed");
78615e5d6aSchristos 
79615e5d6aSchristos 	sched_yield();
80615e5d6aSchristos 	ATF_REQUIRE_EQ(sv.sival_int, value);
81615e5d6aSchristos }
82615e5d6aSchristos 
835167a305Sjruoho ATF_TC(sigqueue_err);
ATF_TC_HEAD(sigqueue_err,tc)845167a305Sjruoho ATF_TC_HEAD(sigqueue_err, tc)
855167a305Sjruoho {
865167a305Sjruoho 	atf_tc_set_md_var(tc, "descr", "Test errors from sigqueue(3)");
875167a305Sjruoho }
885167a305Sjruoho 
ATF_TC_BODY(sigqueue_err,tc)895167a305Sjruoho ATF_TC_BODY(sigqueue_err, tc)
905167a305Sjruoho {
916a4b698aSjoerg 	static union sigval sv;
925167a305Sjruoho 
935167a305Sjruoho 	errno = 0;
945167a305Sjruoho 	ATF_REQUIRE_ERRNO(EINVAL, sigqueue(getpid(), -1, sv) == -1);
955167a305Sjruoho }
965167a305Sjruoho 
971d1c8bdeSchristos static int signals[] = {
981d1c8bdeSchristos 	SIGINT, SIGRTMIN + 1, SIGINT, SIGRTMIN + 0, SIGRTMIN + 2,
991d1c8bdeSchristos 	SIGQUIT, SIGRTMIN + 1
1001d1c8bdeSchristos };
1011d1c8bdeSchristos #ifdef __arraycount
1021d1c8bdeSchristos #define CNT	__arraycount(signals)
1031d1c8bdeSchristos #else
1041d1c8bdeSchristos #define CNT	(sizeof(signals) / sizeof(signals[0]))
1051d1c8bdeSchristos #endif
1061d1c8bdeSchristos 
1071d1c8bdeSchristos static sig_atomic_t count = 0;
1081d1c8bdeSchristos static int delivered[CNT];
1091d1c8bdeSchristos 
1101d1c8bdeSchristos static void
myhandler(int signo,siginfo_t * info,void * context __unused)111*b685d7fdSchristos myhandler(int signo, siginfo_t *info, void *context __unused)
1121d1c8bdeSchristos {
1131d1c8bdeSchristos 	delivered[count++] = signo;
114*b685d7fdSchristos 	printf("Signal #%zu: signo: %d\n", (size_t)count, signo);
1151d1c8bdeSchristos }
1161d1c8bdeSchristos 
1171d1c8bdeSchristos static int
asc(const void * a,const void * b)1181d1c8bdeSchristos asc(const void *a, const void *b)
1191d1c8bdeSchristos {
1201d1c8bdeSchristos 	const int *ia = a, *ib = b;
1211d1c8bdeSchristos 	return *ib - *ia;
1221d1c8bdeSchristos }
1231d1c8bdeSchristos 
1241d1c8bdeSchristos /*
1251d1c8bdeSchristos  * given a array of signals to be delivered in tosend of size len
1261d1c8bdeSchristos  * place in ordered the signals to be delivered in delivery order
1271d1c8bdeSchristos  * and return the number of signals that should be delivered
1281d1c8bdeSchristos  */
1291d1c8bdeSchristos static size_t
sigorder(int * ordered,const int * tosend,size_t len)1301d1c8bdeSchristos sigorder(int *ordered, const int *tosend, size_t len)
1311d1c8bdeSchristos {
1321d1c8bdeSchristos 	memcpy(ordered, tosend, len * sizeof(*tosend));
1331d1c8bdeSchristos 	qsort(ordered, len, sizeof(*ordered), asc);
1341d1c8bdeSchristos 	if (len == 1)
1351d1c8bdeSchristos 		return len;
1361d1c8bdeSchristos 
1371d1c8bdeSchristos 	size_t i, j;
1381d1c8bdeSchristos 	for (i = 0, j = 0; i < len - 1; i++) {
1391d1c8bdeSchristos 		if (ordered[i] >= SIGRTMIN)
1401d1c8bdeSchristos 			continue;
1411d1c8bdeSchristos 		if (j == 0)
1421d1c8bdeSchristos 			j = i + 1;
1431d1c8bdeSchristos 		while (ordered[i] == ordered[j] && j < len)
1441d1c8bdeSchristos 			j++;
1451d1c8bdeSchristos 		if (j == len)
1461d1c8bdeSchristos 			break;
1471d1c8bdeSchristos 		ordered[i + 1] = ordered[j];
1481d1c8bdeSchristos 	}
1491d1c8bdeSchristos 	return i + 1;
1501d1c8bdeSchristos }
1511d1c8bdeSchristos 
1521d1c8bdeSchristos ATF_TC(sigqueue_rt);
ATF_TC_HEAD(sigqueue_rt,tc)1531d1c8bdeSchristos ATF_TC_HEAD(sigqueue_rt, tc)
1541d1c8bdeSchristos {
1551d1c8bdeSchristos 	atf_tc_set_md_var(tc, "descr", "Test queuing of real-time signals");
1561d1c8bdeSchristos }
1571d1c8bdeSchristos 
ATF_TC_BODY(sigqueue_rt,tc)1581d1c8bdeSchristos ATF_TC_BODY(sigqueue_rt, tc)
1591d1c8bdeSchristos {
1601d1c8bdeSchristos 	pid_t pid;
1611d1c8bdeSchristos 	union sigval val;
1621d1c8bdeSchristos 	struct sigaction act;
1631d1c8bdeSchristos 	int ordered[CNT];
1641d1c8bdeSchristos 	struct sigaction oact[CNT];
1651d1c8bdeSchristos 	size_t ndelivered;
1661d1c8bdeSchristos 
1671d1c8bdeSchristos 	ndelivered = sigorder(ordered, signals, CNT);
1681d1c8bdeSchristos 
1691d1c8bdeSchristos 	act.sa_flags = SA_SIGINFO;
1701d1c8bdeSchristos 	act.sa_sigaction = myhandler;
1711d1c8bdeSchristos 	sigemptyset(&act.sa_mask);
1721d1c8bdeSchristos 	for (size_t i = 0; i < ndelivered; i++)
1731d1c8bdeSchristos 		ATF_REQUIRE(sigaction(ordered[i], &act, &oact[i]) != -1);
1741d1c8bdeSchristos 
1751d1c8bdeSchristos 	val.sival_int = 0;
1761d1c8bdeSchristos 	pid = getpid();
1771d1c8bdeSchristos 
1781d1c8bdeSchristos 	sigset_t mask, orig;
1791d1c8bdeSchristos 	sigemptyset(&mask);
1801d1c8bdeSchristos 	for (size_t i = 0; i < CNT; i++)
181*b685d7fdSchristos 		if (sigaddset(&mask, signals[i]) == -1)
182*b685d7fdSchristos 			warn("sigaddset");
1831d1c8bdeSchristos 
1841d1c8bdeSchristos 	ATF_REQUIRE(sigprocmask(SIG_BLOCK, &mask, &orig) != -1);
1851d1c8bdeSchristos 
1861d1c8bdeSchristos 	for (size_t i = 0; i < CNT; i++)
1871d1c8bdeSchristos 		ATF_REQUIRE(sigqueue(pid, signals[i], val) != -1);
1881d1c8bdeSchristos 
1891d1c8bdeSchristos 	ATF_REQUIRE(sigprocmask(SIG_UNBLOCK, &mask, &orig) != -1);
1901d1c8bdeSchristos 	sleep(1);
191*b685d7fdSchristos 	ATF_CHECK_MSG((size_t)count == ndelivered,
1921d1c8bdeSchristos 	    "count %zu != ndelivered %zu", (size_t)count, ndelivered);
1931d1c8bdeSchristos 	for (size_t i = 0; i < ndelivered; i++)
1941d1c8bdeSchristos 		ATF_REQUIRE_MSG(ordered[i] == delivered[i],
1951d1c8bdeSchristos 		    "%zu: ordered %d != delivered %d",
1961d1c8bdeSchristos 		    i, ordered[i], delivered[i]);
1971d1c8bdeSchristos 
198*b685d7fdSchristos 	if ((size_t)count > ndelivered)
199*b685d7fdSchristos 		for (size_t i = ndelivered; i < (size_t)count; i++)
200*b685d7fdSchristos 			printf("Undelivered signal #%zu: %d\n", i, ordered[i]);
201*b685d7fdSchristos 
2021d1c8bdeSchristos 	for (size_t i = 0; i < ndelivered; i++)
2031d1c8bdeSchristos 		ATF_REQUIRE(sigaction(signals[i], &oact[i], NULL) != -1);
2041d1c8bdeSchristos }
2051d1c8bdeSchristos 
ATF_TP_ADD_TCS(tp)206615e5d6aSchristos ATF_TP_ADD_TCS(tp)
207615e5d6aSchristos {
2085167a305Sjruoho 
2095167a305Sjruoho 	ATF_TP_ADD_TC(tp, sigqueue_basic);
2105167a305Sjruoho 	ATF_TP_ADD_TC(tp, sigqueue_err);
2111d1c8bdeSchristos 	ATF_TP_ADD_TC(tp, sigqueue_rt);
212615e5d6aSchristos 
213615e5d6aSchristos 	return atf_no_error();
214615e5d6aSchristos }
215