xref: /openbsd-src/regress/sys/kern/unixsockets/unsendrecvthr.c (revision 63cd6ed3906b495e90f1710ea58c012bc61429dc)
1*63cd6ed3Sbluhm /* $OpenBSD: unsendrecvthr.c,v 1.2 2023/07/09 09:33:30 bluhm Exp $ */
24890ac77Smvs 
34890ac77Smvs /*
44890ac77Smvs  * Copyright (c) 2021 Vitaliy Makkoveev <mvs@openbsd.org>
54890ac77Smvs  *
64890ac77Smvs  * Permission to use, copy, modify, and distribute this software for any
74890ac77Smvs  * purpose with or without fee is hereby granted, provided that the above
84890ac77Smvs  * copyright notice and this permission notice appear in all copies.
94890ac77Smvs  *
104890ac77Smvs  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
114890ac77Smvs  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
124890ac77Smvs  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
134890ac77Smvs  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
144890ac77Smvs  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
154890ac77Smvs  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
164890ac77Smvs  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
174890ac77Smvs  */
184890ac77Smvs 
194890ac77Smvs /*
204890ac77Smvs  * Create the pair of SOCK_SEQPACKET sockets and perform #count_of_cpus
214890ac77Smvs  * simultaneous writes on each of them. In half of transmissions the
224890ac77Smvs  * sockets will be re-locked in kernel space. Be sure no data corruption
234890ac77Smvs  * or loss.
244890ac77Smvs  */
254890ac77Smvs 
264890ac77Smvs #include <sys/types.h>
274890ac77Smvs #include <sys/select.h>
284890ac77Smvs #include <sys/socket.h>
294890ac77Smvs #include <sys/sysctl.h>
304890ac77Smvs #include <sys/un.h>
314890ac77Smvs #include <stdarg.h>
324890ac77Smvs #include <stdio.h>
334890ac77Smvs #include <stdlib.h>
344890ac77Smvs #include <err.h>
354890ac77Smvs #include <pthread.h>
364890ac77Smvs #include <string.h>
374890ac77Smvs #include <time.h>
384890ac77Smvs #include <unistd.h>
394890ac77Smvs 
404890ac77Smvs static pthread_mutex_t therr_mtx = PTHREAD_MUTEX_INITIALIZER;
414890ac77Smvs 
424890ac77Smvs static void
therr(int eval,const char * fmt,...)434890ac77Smvs therr(int eval, const char *fmt, ...)
444890ac77Smvs {
454890ac77Smvs 	va_list ap;
464890ac77Smvs 
474890ac77Smvs 	pthread_mutex_lock(&therr_mtx);
484890ac77Smvs 
494890ac77Smvs 	va_start(ap, fmt);
504890ac77Smvs 	verr(eval, fmt, ap);
514890ac77Smvs 	va_end(ap);
524890ac77Smvs }
534890ac77Smvs 
544890ac77Smvs static void
therrx(int eval,const char * fmt,...)554890ac77Smvs therrx(int eval, const char *fmt, ...)
564890ac77Smvs {
574890ac77Smvs 	va_list ap;
584890ac77Smvs 
594890ac77Smvs 	pthread_mutex_lock(&therr_mtx);
604890ac77Smvs 
614890ac77Smvs 	va_start(ap, fmt);
624890ac77Smvs 	verrx(eval, fmt, ap);
634890ac77Smvs 	va_end(ap);
644890ac77Smvs }
654890ac77Smvs 
664890ac77Smvs static void
therrc(int eval,int code,const char * fmt,...)674890ac77Smvs therrc(int eval, int code, const char *fmt, ...)
684890ac77Smvs {
694890ac77Smvs 	va_list ap;
704890ac77Smvs 
714890ac77Smvs 	pthread_mutex_lock(&therr_mtx);
724890ac77Smvs 
734890ac77Smvs 	va_start(ap, fmt);
744890ac77Smvs 	verrc(eval, code, fmt, ap);
754890ac77Smvs 	va_end(ap);
764890ac77Smvs }
774890ac77Smvs 
784890ac77Smvs struct data {
794890ac77Smvs 	int id;
804890ac77Smvs 	unsigned int cnt;
814890ac77Smvs };
824890ac77Smvs 
834890ac77Smvs struct thr_tx_arg {
844890ac77Smvs 	int s;
854890ac77Smvs 	int id;
864890ac77Smvs };
874890ac77Smvs 
884890ac77Smvs struct rx_data {
894890ac77Smvs 	unsigned int cnt;
904890ac77Smvs };
914890ac77Smvs 
924890ac77Smvs struct thr_rx_arg {
934890ac77Smvs 	int s;
944890ac77Smvs 	int rx_data_num;
954890ac77Smvs 	struct rx_data *rx_data;
964890ac77Smvs };
974890ac77Smvs 
984890ac77Smvs static void *
thr_tx(void * arg)994890ac77Smvs thr_tx(void *arg)
1004890ac77Smvs {
1014890ac77Smvs 	struct data data;
1024890ac77Smvs 	int s = ((struct thr_tx_arg *)arg)->s;
1034890ac77Smvs 
1044890ac77Smvs 	data.id = ((struct thr_tx_arg *)arg)->id;
1054890ac77Smvs 	data.cnt = 1;
1064890ac77Smvs 
1074890ac77Smvs 	while (1) {
1084890ac77Smvs 		ssize_t ret;
1094890ac77Smvs 
1104890ac77Smvs 		if ((ret = send(s, &data, sizeof(data), 0)) < 0)
1114890ac77Smvs 			therr(1, "send");
1124890ac77Smvs 		if (ret != sizeof(data))
1134890ac77Smvs 			therrx(1, "send: wrong data size");
1144890ac77Smvs 
1154890ac77Smvs 		data.cnt++;
1164890ac77Smvs 	}
1174890ac77Smvs 
1184890ac77Smvs 	return NULL;
1194890ac77Smvs }
1204890ac77Smvs 
1214890ac77Smvs static void *
thr_rx(void * arg)1224890ac77Smvs thr_rx(void *arg)
1234890ac77Smvs {
1244890ac77Smvs 	int s = ((struct thr_rx_arg *)arg)->s;
1254890ac77Smvs 	int rx_data_num = ((struct thr_rx_arg *)arg)->rx_data_num;
1264890ac77Smvs 	struct rx_data *rx_data = ((struct thr_rx_arg *)arg)->rx_data;
1274890ac77Smvs 
1284890ac77Smvs 	while (1) {
1294890ac77Smvs 		struct data data;
1304890ac77Smvs 		ssize_t ret;
1314890ac77Smvs 
1324890ac77Smvs 		if ((ret = recv(s, &data, sizeof(data), 0)) < 0)
1334890ac77Smvs 			therr(1, "recv");
1344890ac77Smvs 		if (ret != sizeof(data))
1354890ac77Smvs 			therrx(1, "recv: wrong data size");
1364890ac77Smvs 
1374890ac77Smvs 		if (data.id >= rx_data_num)
1384890ac77Smvs 			therrx(1, "recv: wrong id");
1394890ac77Smvs 
1404890ac77Smvs 		if (data.cnt != (unsigned int)(rx_data[data.id].cnt + 1)) {
1414890ac77Smvs 			therrx(1, "recv: data loss %d -> %d",
1424890ac77Smvs 			    rx_data[data.id].cnt, data.cnt);
1434890ac77Smvs 		}
1444890ac77Smvs 		rx_data[data.id].cnt = data.cnt;
1454890ac77Smvs 	}
1464890ac77Smvs 
1474890ac77Smvs 	return NULL;
1484890ac77Smvs }
1494890ac77Smvs 
1504890ac77Smvs int
main(int argc,char * argv[])1514890ac77Smvs main(int argc, char *argv[])
1524890ac77Smvs {
1534890ac77Smvs 	struct timespec testtime = {
1544890ac77Smvs 		.tv_sec = 60,
1554890ac77Smvs 		.tv_nsec = 0,
1564890ac77Smvs 	};
1574890ac77Smvs 
1584890ac77Smvs 	int mib[2], ncpu;
1594890ac77Smvs 	size_t len;
1604890ac77Smvs 
1614890ac77Smvs 	struct rx_data *rx_data[2];
1624890ac77Smvs 	struct thr_rx_arg rx_args[2];
1634890ac77Smvs 	struct thr_tx_arg *tx_args[2];
1644890ac77Smvs 
1654890ac77Smvs 	int s[2], i, j;
1664890ac77Smvs 
1674890ac77Smvs 	if (argc == 2 && !strcmp(argv[1], "--infinite"))
1684890ac77Smvs 		testtime.tv_sec = (10 * 365 * 86400);
1694890ac77Smvs 
1704890ac77Smvs 	mib[0] = CTL_HW;
1714890ac77Smvs 	mib[1] = HW_NCPUONLINE;
1724890ac77Smvs 	len = sizeof(ncpu);
1734890ac77Smvs 
1744890ac77Smvs 	if (sysctl(mib, 2, &ncpu, &len, NULL, 0) < 0)
1754890ac77Smvs 		err(1, "sysctl");
1764890ac77Smvs 	if (ncpu <= 0)
1774890ac77Smvs 		errx(1, "Wrong number of CPUs online: %d", ncpu);
1784890ac77Smvs 
1794890ac77Smvs 	if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, s) < 0)
1804890ac77Smvs 		err(1, "socketpair");
1814890ac77Smvs 
1824890ac77Smvs 	for (i = 0; i < 2; ++i) {
183*63cd6ed3Sbluhm 		if (!(rx_data[i] = calloc(ncpu, sizeof(struct rx_data))))
1844890ac77Smvs 			err(1, "calloc");
1854890ac77Smvs 
1864890ac77Smvs 		for (j = 0; j < ncpu; ++j)
1874890ac77Smvs 			rx_data[i][j].cnt = 0;
1884890ac77Smvs 	}
1894890ac77Smvs 
1904890ac77Smvs 	for (i = 0; i < 2; ++i) {
1914890ac77Smvs 		rx_args[i].s = s[i];
1924890ac77Smvs 		rx_args[i].rx_data_num = ncpu;
1934890ac77Smvs 		rx_args[i].rx_data = rx_data[i];
1944890ac77Smvs 	}
1954890ac77Smvs 
1964890ac77Smvs 	for (i = 0; i < 2; ++i) {
197*63cd6ed3Sbluhm 		if (!(tx_args[i] = calloc(ncpu, sizeof(struct thr_tx_arg))))
1984890ac77Smvs 			err(1, "calloc");
1994890ac77Smvs 
2004890ac77Smvs 		for (j = 0; j < ncpu; ++j) {
2014890ac77Smvs 			tx_args[i][j].s = s[i];
2024890ac77Smvs 			tx_args[i][j].id = j;
2034890ac77Smvs 		}
2044890ac77Smvs 	}
2054890ac77Smvs 
2064890ac77Smvs 	for (i = 0; i < 2; ++i) {
2074890ac77Smvs 		pthread_t thr;
2084890ac77Smvs 		int error;
2094890ac77Smvs 
2104890ac77Smvs 		error = pthread_create(&thr, NULL, thr_rx, &rx_args[i]);
2114890ac77Smvs 		if (error)
2124890ac77Smvs 			therrc(1, error, "pthread_create");
2134890ac77Smvs 	}
2144890ac77Smvs 
2154890ac77Smvs 	for (i = 0; i < 2; ++i) {
2164890ac77Smvs 		pthread_t thr;
2174890ac77Smvs 		int error;
2184890ac77Smvs 
2194890ac77Smvs 		for (j = 0; j < ncpu; ++j) {
2204890ac77Smvs 			error = pthread_create(&thr, NULL,
2214890ac77Smvs 			    thr_tx, &tx_args[i][j]);
2224890ac77Smvs 			if (error)
2234890ac77Smvs 				therrc(1, error, "pthread_create");
2244890ac77Smvs 		}
2254890ac77Smvs 	}
2264890ac77Smvs 
2274890ac77Smvs 	nanosleep(&testtime, NULL);
2284890ac77Smvs 
2294890ac77Smvs 	return 0;
2304890ac77Smvs }
231