Index | Thread | Search

From:
Vitaliy Makkoveev <mvs@openbsd.org>
Subject:
Re: Relax sockets splicing locking
To:
Alexander Bluhm <bluhm@openbsd.org>
Cc:
tech@openbsd.org
Date:
Sat, 4 Jan 2025 20:07:14 +0300

Download raw body.

Thread
On Sat, Jan 04, 2025 at 06:39:26PM +0300, Vitaliy Makkoveev wrote:
> > On 4 Jan 2025, at 16:34, Alexander Bluhm <bluhm@openbsd.org> wrote:
> > 

> > [skip]

> > I have tested it with my regress and netlink setup.  My perform
> > testing machines are currently busy with other tests.
> > 
> > We have no propper regression tests for splicing and unsplicing
> > under heavy load.  I am currently trying to write a test.
> > 
> 
> We need something like multithreaded attempts of simultaneous
> splicing and unsplicing one socket to itself. Or the same but
> for two sockets.
> 

The simplest test to concurrently splice/unsplice socket.

#include <sys/types.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/sysctl.h>
#include <stdio.h>
#include <err.h>
#include <errno.h>
#include <pthread.h>
#include <string.h>
#include <time.h>
#include <unistd.h>

#include <netinet/in.h>

static int s;

static int spliced = 0;
static int unspliced = 0;

static void *
thr_splice(void *arg)
{
	while (1) {
		if (setsockopt(s, SOL_SOCKET, SO_SPLICE, &s, sizeof(s)) == 0)
			spliced = 1;
	}

	return NULL;
}

static void *
thr_unsplice(void *arg)
{
	while (1) {
		if (setsockopt(s, SOL_SOCKET, SO_SPLICE, NULL, 0) == 0)
			unspliced = 1;
	}

	return NULL;
}

int
main(int argc, char *argv[])
{
	struct timespec testtime = {
		.tv_sec = 60,
		.tv_nsec = 0,
	};

	int mib[2], ncpu;
	size_t len;

	struct sockaddr_in sin;
	socklen_t slen;

	pthread_t thr;
	int i, error;

	if (argc == 2 && !strcmp(argv[1], "--infinite"))
		testtime.tv_sec = (10 * 365 * 86400);

	mib[0] = CTL_HW;
	mib[1] = HW_NCPUONLINE;
	len = sizeof(ncpu);

	if (sysctl(mib, 2, &ncpu, &len, NULL, 0) < 0)
		err(1, "sysctl");
	if (ncpu <= 0)
		errx(1, "Wrong number of CPUs online: %d", ncpu);
	if (ncpu == 1)
		ncpu = 2;

	if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
		err(1, "socket");

	memset(&sin, 0, sizeof(sin));
	sin.sin_family = AF_INET;
	sin.sin_addr.s_addr = INADDR_ANY;

	if (bind(s, (struct sockaddr *)&sin, sizeof(sin)) < 0)
		err(1, "bind");

	slen = sizeof(sin);
	if (getsockname(s, (struct sockaddr *)&sin, &slen) < 0)
		err(1, "getsockname");

	if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) < 0)
		err(1, "connect");

	for (i = 0; i < ncpu; ++i) {
		error = pthread_create(&thr, NULL, thr_splice, NULL);
		if (error)
			errc(1, error, "pthread_create");
		error = pthread_create(&thr, NULL, thr_unsplice, NULL);
		if (error)
			errc(1, error, "pthread_create");
	}

	nanosleep(&testtime, NULL);

	if (!(spliced && unspliced))
		errx(1, "was %sspliced, was %sunspliced",
		    spliced ? "" : "not ", unspliced ? "" : "not ");

	return 0;
}