xref: /openbsd/regress/lib/libpthread/dlopen/dlopen.c (revision 41a8fc2a)
1*41a8fc2aSguenther /*	$OpenBSD: dlopen.c,v 1.2 2017/09/07 21:35:35 guenther Exp $ */
242d9ae1fSguenther /*
342d9ae1fSguenther  * Copyright (c) 2016 Philip Guenther <guenther@openbsd.org>
442d9ae1fSguenther  *
542d9ae1fSguenther  * Permission to use, copy, modify, and distribute this software for any
642d9ae1fSguenther  * purpose with or without fee is hereby granted, provided that the above
742d9ae1fSguenther  * copyright notice and this permission notice appear in all copies.
842d9ae1fSguenther  *
942d9ae1fSguenther  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1042d9ae1fSguenther  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1142d9ae1fSguenther  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1242d9ae1fSguenther  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1342d9ae1fSguenther  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1442d9ae1fSguenther  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1542d9ae1fSguenther  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1642d9ae1fSguenther  */
1742d9ae1fSguenther 
1842d9ae1fSguenther /*
1942d9ae1fSguenther  * Test that various calls can be interrupted in a non-threaded process,
2042d9ae1fSguenther  * then dlopen() libpthread and do that again in a second thread,
2142d9ae1fSguenther  * and then verify that they're all correctly acting as cancellation points.
2242d9ae1fSguenther  */
2342d9ae1fSguenther 
2442d9ae1fSguenther #include <sys/types.h>
2542d9ae1fSguenther #include <sys/ipc.h>
2642d9ae1fSguenther #include <sys/sem.h>
2742d9ae1fSguenther #include <sys/socket.h>
2842d9ae1fSguenther #include <sys/stat.h>
2942d9ae1fSguenther #include <sys/time.h>
3042d9ae1fSguenther #include <sys/wait.h>
3142d9ae1fSguenther 
3242d9ae1fSguenther #include <arpa/inet.h>
3342d9ae1fSguenther #include <netinet/in.h>
3442d9ae1fSguenther #include <netinet/tcp.h>
3542d9ae1fSguenther 
3642d9ae1fSguenther #include <dlfcn.h>
3742d9ae1fSguenther #include <err.h>
3842d9ae1fSguenther #include <errno.h>
3942d9ae1fSguenther #include <fcntl.h>
4042d9ae1fSguenther #include <poll.h>
4142d9ae1fSguenther #include <pthread.h>
4242d9ae1fSguenther #include <signal.h>
4342d9ae1fSguenther #include <stdio.h>
4442d9ae1fSguenther #include <stdlib.h>
4542d9ae1fSguenther #include <string.h>
4642d9ae1fSguenther #include <time.h>
4742d9ae1fSguenther #include <unistd.h>
4842d9ae1fSguenther 
4942d9ae1fSguenther /* path of fifo we remove/create/open/remove */
5042d9ae1fSguenther #define FIFO_PATH	"fifo"
5142d9ae1fSguenther 
5242d9ae1fSguenther /* path of lock file remove/create/lock/remove */
5342d9ae1fSguenther #define LOCK_PATH	"lock"
5442d9ae1fSguenther 
5542d9ae1fSguenther #define TEST_ACCEPT	0x001
5642d9ae1fSguenther #define TEST_CONNECT	0x002
5742d9ae1fSguenther #define TEST_FCNTL	0x004
5842d9ae1fSguenther #define TEST_FLOCK	0x008
5942d9ae1fSguenther #define TEST_NANOSLEEP	0x010
6042d9ae1fSguenther #define TEST_OPEN_FIFO	0x020
6142d9ae1fSguenther #define TEST_POLL	0x040
6242d9ae1fSguenther #define TEST_SIGSUSPEND	0x080
6342d9ae1fSguenther #define TEST_SEMOP	0x100
6442d9ae1fSguenther 
6542d9ae1fSguenther #define TEST_ALL	0x1ff
6642d9ae1fSguenther 
6742d9ae1fSguenther struct test_spec
6842d9ae1fSguenther {
6942d9ae1fSguenther 	int flag;
7042d9ae1fSguenther 	const char *name;
7142d9ae1fSguenther 	void (*init)(void);
7242d9ae1fSguenther 	void *(*run)(void *);
7342d9ae1fSguenther 	void (*fini)(void);
7442d9ae1fSguenther };
7542d9ae1fSguenther 
7642d9ae1fSguenther 
7742d9ae1fSguenther /*
7842d9ae1fSguenther  * Functions looked up in libpthread
7942d9ae1fSguenther  */
8042d9ae1fSguenther int	(*p_attr_init)(pthread_attr_t *);
8142d9ae1fSguenther int	(*p_attr_setdetachstate)(pthread_attr_t *, int);
8242d9ae1fSguenther int	(*p_cancel)(pthread_t);
8342d9ae1fSguenther int	(*p_cond_destroy)(pthread_cond_t *);
8442d9ae1fSguenther int	(*p_cond_timedwait)(pthread_cond_t *, pthread_mutex_t *, const struct timespec *);
8542d9ae1fSguenther int	(*p_create)(pthread_t *, const pthread_attr_t *, void *(*)(void *), void *);
8642d9ae1fSguenther int	(*p_join)(pthread_t, void **);
8742d9ae1fSguenther int	(*p_mutex_destroy)(pthread_mutex_t *);
8842d9ae1fSguenther int	(*p_mutex_lock)(pthread_mutex_t *);
8942d9ae1fSguenther int	(*p_mutex_unlock)(pthread_mutex_t *);
9042d9ae1fSguenther pthread_t (*p_self)(void);
9142d9ae1fSguenther 
9242d9ae1fSguenther struct funcs
9342d9ae1fSguenther {
9442d9ae1fSguenther 	const char *name;
9542d9ae1fSguenther 	void *callback;
9642d9ae1fSguenther } functions[] =
9742d9ae1fSguenther {
9842d9ae1fSguenther #define FUNC(f)		{ "pthread_"#f, &p_##f }
9942d9ae1fSguenther 	FUNC(attr_init),
10042d9ae1fSguenther 	FUNC(attr_setdetachstate),
10142d9ae1fSguenther 	FUNC(cancel),
10242d9ae1fSguenther 	FUNC(cond_destroy),
10342d9ae1fSguenther 	FUNC(cond_timedwait),
10442d9ae1fSguenther 	FUNC(create),
10542d9ae1fSguenther 	FUNC(join),
10642d9ae1fSguenther 	FUNC(mutex_destroy),
10742d9ae1fSguenther 	FUNC(mutex_lock),
10842d9ae1fSguenther 	FUNC(mutex_unlock),
10942d9ae1fSguenther 	FUNC(self),
11042d9ae1fSguenther 	{ NULL, NULL }
11142d9ae1fSguenther #undef FUNC
11242d9ae1fSguenther };
11342d9ae1fSguenther 
11442d9ae1fSguenther /*
11542d9ae1fSguenther  * Shared cleanup
11642d9ae1fSguenther  */
11742d9ae1fSguenther void
finish(const char * msg,const int * retval,const struct timespec * tsp)11842d9ae1fSguenther finish(const char *msg, const int *retval, const struct timespec *tsp)
11942d9ae1fSguenther {
12042d9ae1fSguenther 	struct timespec after;
12142d9ae1fSguenther 	const char *fill = "\t\t\t";
12242d9ae1fSguenther 
12342d9ae1fSguenther 	clock_gettime(CLOCK_REALTIME, &after);
12442d9ae1fSguenther 	after.tv_sec -= tsp->tv_sec;
12542d9ae1fSguenther 	after.tv_nsec -= tsp->tv_nsec;
12642d9ae1fSguenther 	if (after.tv_nsec < 0) {
12742d9ae1fSguenther 		after.tv_sec--;
12842d9ae1fSguenther 		after.tv_nsec += 1000000000L;
12942d9ae1fSguenther 	}
13042d9ae1fSguenther 
13142d9ae1fSguenther 	fill += (strlen(msg) - 1) / 8;
13242d9ae1fSguenther 	if (retval[0] >= 0)
13342d9ae1fSguenther 		printf("%s: fail%s\ttime = %ld.%09lu\nr = %d\n",
13442d9ae1fSguenther 		    msg, fill, (long)after.tv_sec, after.tv_nsec, retval[0]);
13542d9ae1fSguenther 	else if (retval[1] != EINTR)
13642d9ae1fSguenther 		printf("%s: fail%s\ttime = %ld.%09lu\nr = %d\terrno = %d: %s\n",
13742d9ae1fSguenther 		    msg, fill, (long)after.tv_sec, after.tv_nsec,
13842d9ae1fSguenther 		    retval[0], retval[1], strerror(retval[1]));
13942d9ae1fSguenther 	else
14042d9ae1fSguenther 		printf("%s: pass%s\ttime = %ld.%09lu\n",
14142d9ae1fSguenther 		    msg, fill, (long)after.tv_sec, after.tv_nsec);
14242d9ae1fSguenther }
14342d9ae1fSguenther 
14442d9ae1fSguenther /* noop signal handler */
14542d9ae1fSguenther void
sigusr1(int sig)14642d9ae1fSguenther sigusr1(int sig)
14742d9ae1fSguenther {
14842d9ae1fSguenther }
14942d9ae1fSguenther 
15042d9ae1fSguenther /*
15142d9ae1fSguenther  * Interrupt via alarm()
15242d9ae1fSguenther  */
15342d9ae1fSguenther void
sigalrm(int sig)15442d9ae1fSguenther sigalrm(int sig)
15542d9ae1fSguenther {
15642d9ae1fSguenther 	write(1, "* ", 2);
15742d9ae1fSguenther }
15842d9ae1fSguenther 
15942d9ae1fSguenther void
set_sigalrm(int restart)16042d9ae1fSguenther set_sigalrm(int restart)
16142d9ae1fSguenther {
16242d9ae1fSguenther 	struct sigaction sa;
16342d9ae1fSguenther 
16442d9ae1fSguenther 	sa.sa_handler = &sigalrm;
16542d9ae1fSguenther 	sa.sa_flags = restart ? SA_RESTART : 0;
16642d9ae1fSguenther 	sigemptyset(&sa.sa_mask);
16742d9ae1fSguenther 	sigaction(SIGALRM, &sa, NULL);
16842d9ae1fSguenther }
16942d9ae1fSguenther 
17042d9ae1fSguenther void
run_sig(const struct test_spec * test)17142d9ae1fSguenther run_sig(const struct test_spec *test)
17242d9ae1fSguenther {
17342d9ae1fSguenther 	struct timespec before;
17442d9ae1fSguenther 	int retval[2];
17542d9ae1fSguenther 
17642d9ae1fSguenther 	if (test->init != NULL)
17742d9ae1fSguenther 		test->init();
17842d9ae1fSguenther 	if (clock_gettime(CLOCK_REALTIME, &before))
17942d9ae1fSguenther 		err(1, "clock_gettime");
18042d9ae1fSguenther 	alarm(1);
18142d9ae1fSguenther 	test->run(retval);
18242d9ae1fSguenther 	finish(test->name, retval, &before);
18342d9ae1fSguenther 	if (test->fini != NULL)
18442d9ae1fSguenther 		test->fini();
18542d9ae1fSguenther }
18642d9ae1fSguenther 
18742d9ae1fSguenther 
18842d9ae1fSguenther /*
18942d9ae1fSguenther  * Interrupt via cancellation
19042d9ae1fSguenther  */
19142d9ae1fSguenther 
19242d9ae1fSguenther 
19342d9ae1fSguenther void
run_cancel(const struct test_spec * test)19442d9ae1fSguenther run_cancel(const struct test_spec *test)
19542d9ae1fSguenther {
19642d9ae1fSguenther 	struct timespec before, target_time;
19742d9ae1fSguenther 	pthread_t tester;
19842d9ae1fSguenther 	pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER;
19942d9ae1fSguenther 	pthread_cond_t c = PTHREAD_COND_INITIALIZER;
20042d9ae1fSguenther 	int retval[2];
20142d9ae1fSguenther 	int r;
20242d9ae1fSguenther 
20342d9ae1fSguenther 	if (test->init != NULL)
20442d9ae1fSguenther 		test->init();
20542d9ae1fSguenther 
20642d9ae1fSguenther 	if ((r = p_mutex_lock(&m)))
20742d9ae1fSguenther 		errc(1, r, "pthread_mutex_lock");
20842d9ae1fSguenther 
20942d9ae1fSguenther 	if (clock_gettime(CLOCK_REALTIME, &before))
21042d9ae1fSguenther 		err(1, "clock_gettime");
21142d9ae1fSguenther 
21242d9ae1fSguenther 	target_time.tv_sec = before.tv_sec + 1;
21342d9ae1fSguenther 	target_time.tv_nsec = before.tv_nsec;
21442d9ae1fSguenther 
21542d9ae1fSguenther 	retval[0] = -2;
21642d9ae1fSguenther 	if ((r = p_create(&tester, NULL, test->run, retval)))
21742d9ae1fSguenther 		errc(1, r, "pthread_create");
21842d9ae1fSguenther 
21942d9ae1fSguenther 	/* overkill: could have done it with pthread_mutex_timedlock */
22042d9ae1fSguenther 	do
22142d9ae1fSguenther 		r = p_cond_timedwait(&c, &m, &target_time);
22242d9ae1fSguenther 	while (r == 0);
22342d9ae1fSguenther 	if (r != ETIMEDOUT)
22442d9ae1fSguenther 		errc(1, r, "pthread_cond_timedwait");
22542d9ae1fSguenther 	write(1, "* ", 2);
22642d9ae1fSguenther 	if (retval[0] == -2) {
22742d9ae1fSguenther 		retval[0] = -1;
22842d9ae1fSguenther 		retval[1] = EINTR;
22942d9ae1fSguenther 	}
23042d9ae1fSguenther 	if ((r = p_cancel(tester)))
23142d9ae1fSguenther 		errc(1, r, "pthread_cancel");
23242d9ae1fSguenther 	if ((r = p_mutex_unlock(&m)))
23342d9ae1fSguenther 		errc(1, r, "pthread_mutex_unlock");
23442d9ae1fSguenther 	if ((r = p_mutex_destroy(&m)))
23542d9ae1fSguenther 		errc(1, r, "pthread_mutex_destroy");
23642d9ae1fSguenther 	if ((r = p_cond_destroy(&c)))
23742d9ae1fSguenther 		errc(1, r, "pthread_cond_destroy");
23842d9ae1fSguenther 
23942d9ae1fSguenther 	finish(test->name, retval, &before);
24042d9ae1fSguenther 	if (test->fini != NULL)
24142d9ae1fSguenther 		test->fini();
24242d9ae1fSguenther }
24342d9ae1fSguenther 
24442d9ae1fSguenther void (*run)(const struct test_spec *_test) = run_sig;
24542d9ae1fSguenther 
24642d9ae1fSguenther 
24742d9ae1fSguenther /*
24842d9ae1fSguenther  * The operations that are exercised in the tests
24942d9ae1fSguenther  */
25042d9ae1fSguenther 
25142d9ae1fSguenther /*
25242d9ae1fSguenther  * POLL
25342d9ae1fSguenther  */
25442d9ae1fSguenther void *
poll_run(void * arg)25542d9ae1fSguenther poll_run(void *arg)
25642d9ae1fSguenther {
25742d9ae1fSguenther 	struct pollfd pfd;
25842d9ae1fSguenther 	int *retval = arg;
25942d9ae1fSguenther 
26042d9ae1fSguenther 	pfd.fd = 0;
26142d9ae1fSguenther 	pfd.events = POLLIN;
26242d9ae1fSguenther 	retval[0] = poll(&pfd, 1, 3 * 1000);
26342d9ae1fSguenther 	retval[1] = errno;
26442d9ae1fSguenther 	return NULL;
26542d9ae1fSguenther }
26642d9ae1fSguenther 
26742d9ae1fSguenther /*
26842d9ae1fSguenther  * NANOSLEEP
26942d9ae1fSguenther  */
27042d9ae1fSguenther void *
nanosleep_run(void * arg)27142d9ae1fSguenther nanosleep_run(void *arg)
27242d9ae1fSguenther {
27342d9ae1fSguenther 	struct timespec ts;
27442d9ae1fSguenther 	int *retval = arg;
27542d9ae1fSguenther 
27642d9ae1fSguenther 	ts.tv_sec = 2;
27742d9ae1fSguenther 	ts.tv_nsec = 0;
27842d9ae1fSguenther 	retval[0] = nanosleep(&ts, &ts);
27942d9ae1fSguenther 	retval[1] = errno;
28042d9ae1fSguenther 	return NULL;
28142d9ae1fSguenther }
28242d9ae1fSguenther 
28342d9ae1fSguenther /*
28442d9ae1fSguenther  * FCNTL
28542d9ae1fSguenther  */
28642d9ae1fSguenther struct flock fcntl_fl = {
28742d9ae1fSguenther 	.l_start = 0,
28842d9ae1fSguenther 	.l_len = 0,
28942d9ae1fSguenther 	.l_type = F_WRLCK,
29042d9ae1fSguenther 	.l_whence = SEEK_SET,
29142d9ae1fSguenther };
29242d9ae1fSguenther static int fcntl_fd = -1;
29342d9ae1fSguenther static pid_t fcntl_pid = 0;
29442d9ae1fSguenther void
fcntl_init(void)29542d9ae1fSguenther fcntl_init(void)
29642d9ae1fSguenther {
29742d9ae1fSguenther 	int fds[2];
29842d9ae1fSguenther 	char buf[1];
29942d9ae1fSguenther 
30042d9ae1fSguenther 	if (unlink(LOCK_PATH) && errno != ENOENT)
30142d9ae1fSguenther 		err(1, "unlink %s", LOCK_PATH);
30242d9ae1fSguenther 	if (pipe(fds))
30342d9ae1fSguenther 		err(1, "pipe");
30442d9ae1fSguenther 	fcntl_fd = open(LOCK_PATH, O_RDWR | O_CREAT, 0666);
30542d9ae1fSguenther 	fcntl_pid = fork();
30642d9ae1fSguenther 	if (fcntl_pid == 0) {
30742d9ae1fSguenther 		fcntl(fcntl_fd, F_SETLKW, &fcntl_fl);
30842d9ae1fSguenther 		close(fds[0]);
30942d9ae1fSguenther 		close(fds[1]);
31042d9ae1fSguenther 		sleep(1000);
31142d9ae1fSguenther 		_exit(0);
31242d9ae1fSguenther 	}
31342d9ae1fSguenther 	close(fds[1]);
31442d9ae1fSguenther 	read(fds[0], buf, 1);
31542d9ae1fSguenther 	close(fds[0]);
31642d9ae1fSguenther }
31742d9ae1fSguenther void *
fcntl_run(void * arg)31842d9ae1fSguenther fcntl_run(void *arg)
31942d9ae1fSguenther {
32042d9ae1fSguenther 	int *retval = arg;
32142d9ae1fSguenther 
32242d9ae1fSguenther 	retval[0] = fcntl(fcntl_fd, F_SETLKW, &fcntl_fl);
32342d9ae1fSguenther 	retval[1] = errno;
32442d9ae1fSguenther 	return NULL;
32542d9ae1fSguenther }
32642d9ae1fSguenther void
fcntl_fini(void)32742d9ae1fSguenther fcntl_fini(void)
32842d9ae1fSguenther {
32942d9ae1fSguenther 	if (fcntl_fd >= 0) {
33042d9ae1fSguenther 		close(fcntl_fd);
33142d9ae1fSguenther 		fcntl_fd = -1;
33242d9ae1fSguenther 	}
33342d9ae1fSguenther 	if (fcntl_pid > 0) {
33442d9ae1fSguenther 		kill(fcntl_pid, SIGINT);
33542d9ae1fSguenther 		waitpid(fcntl_pid, NULL, 0);
33642d9ae1fSguenther 		fcntl_pid = 0;
33742d9ae1fSguenther 	}
33842d9ae1fSguenther 	if (unlink(LOCK_PATH))
33942d9ae1fSguenther 		err(1, "unlink %s", LOCK_PATH);
34042d9ae1fSguenther }
34142d9ae1fSguenther 
34242d9ae1fSguenther /*
34342d9ae1fSguenther  * FLOCK
34442d9ae1fSguenther  */
34542d9ae1fSguenther static int flock_fd = -1;
34642d9ae1fSguenther static pid_t flock_pid = 0;
34742d9ae1fSguenther void
flock_init(void)34842d9ae1fSguenther flock_init(void)
34942d9ae1fSguenther {
35042d9ae1fSguenther 	int fds[2];
35142d9ae1fSguenther 	char buf[1];
35242d9ae1fSguenther 
35342d9ae1fSguenther 	if (unlink(LOCK_PATH) && errno != ENOENT)
35442d9ae1fSguenther 		err(1, "unlink %s", LOCK_PATH);
35542d9ae1fSguenther 	if (pipe(fds))
35642d9ae1fSguenther 		err(1, "pipe");
35742d9ae1fSguenther 	flock_pid = fork();
35842d9ae1fSguenther 	flock_fd = open(LOCK_PATH, O_RDWR | O_CREAT, 0666);
35942d9ae1fSguenther 	if (flock_pid == 0) {
36042d9ae1fSguenther 		flock(flock_fd, LOCK_EX);
36142d9ae1fSguenther 		close(fds[0]);
36242d9ae1fSguenther 		close(fds[1]);
36342d9ae1fSguenther 		sleep(1000);
36442d9ae1fSguenther 		_exit(0);
36542d9ae1fSguenther 	}
36642d9ae1fSguenther 	close(fds[1]);
36742d9ae1fSguenther 	read(fds[0], buf, 1);
36842d9ae1fSguenther 	close(fds[0]);
36942d9ae1fSguenther }
37042d9ae1fSguenther void *
flock_run(void * arg)37142d9ae1fSguenther flock_run(void *arg)
37242d9ae1fSguenther {
37342d9ae1fSguenther 	int *retval = arg;
37442d9ae1fSguenther 
37542d9ae1fSguenther 	retval[0] = flock(flock_fd, LOCK_EX);
37642d9ae1fSguenther 	retval[1] = errno;
37742d9ae1fSguenther 	return NULL;
37842d9ae1fSguenther }
37942d9ae1fSguenther void
flock_fini(void)38042d9ae1fSguenther flock_fini(void)
38142d9ae1fSguenther {
38242d9ae1fSguenther 	if (flock_fd >= 0) {
38342d9ae1fSguenther 		close(flock_fd);
38442d9ae1fSguenther 		flock_fd = -1;
38542d9ae1fSguenther 	}
38642d9ae1fSguenther 	if (flock_pid > 0) {
38742d9ae1fSguenther 		kill(flock_pid, SIGINT);
38842d9ae1fSguenther 		waitpid(flock_pid, NULL, 0);
38942d9ae1fSguenther 		flock_pid = 0;
39042d9ae1fSguenther 	}
39142d9ae1fSguenther 	if (unlink(LOCK_PATH) && errno != ENOENT)
39242d9ae1fSguenther 		err(1, "unlink %s", LOCK_PATH);
39342d9ae1fSguenther }
39442d9ae1fSguenther 
39542d9ae1fSguenther /*
39642d9ae1fSguenther  * SIGSUSPEND
39742d9ae1fSguenther  */
39842d9ae1fSguenther void *
sigsuspend_run(void * arg)39942d9ae1fSguenther sigsuspend_run(void *arg)
40042d9ae1fSguenther {
40142d9ae1fSguenther 	sigset_t set;
40242d9ae1fSguenther 	int *retval = arg;
40342d9ae1fSguenther 
40442d9ae1fSguenther 	sigemptyset(&set);
40542d9ae1fSguenther 	retval[0] = sigsuspend(&set);
40642d9ae1fSguenther 	retval[1] = errno;
40742d9ae1fSguenther 	return NULL;
40842d9ae1fSguenther }
40942d9ae1fSguenther 
41042d9ae1fSguenther /*
41142d9ae1fSguenther  * CONNECT
41242d9ae1fSguenther  */
41342d9ae1fSguenther static int connect_fd = -1;
41442d9ae1fSguenther void
connect_init(void)41542d9ae1fSguenther connect_init(void)
41642d9ae1fSguenther {
41742d9ae1fSguenther 	int on = 1;
41842d9ae1fSguenther 
41942d9ae1fSguenther 	connect_fd = socket(AF_INET, SOCK_STREAM, 0);
42042d9ae1fSguenther 	setsockopt(connect_fd, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on));
42142d9ae1fSguenther 	setsockopt(connect_fd, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof(on));
42242d9ae1fSguenther }
42342d9ae1fSguenther void *
connect_run(void * arg)42442d9ae1fSguenther connect_run(void *arg)
42542d9ae1fSguenther {
42642d9ae1fSguenther 	struct sockaddr_in sin;
42742d9ae1fSguenther 	int *retval = arg;
42842d9ae1fSguenther 
42942d9ae1fSguenther 	sin.sin_family = AF_INET;
43042d9ae1fSguenther 	inet_pton(AF_INET, "223.255.255.255", &sin.sin_addr);
43142d9ae1fSguenther 	sin.sin_port = 25;
43242d9ae1fSguenther 	retval[0] = connect(connect_fd, (struct sockaddr *)&sin, sizeof(sin));
43342d9ae1fSguenther 	retval[1] = errno;
43442d9ae1fSguenther 	return NULL;
43542d9ae1fSguenther }
43642d9ae1fSguenther void
connect_fini(void)43742d9ae1fSguenther connect_fini(void)
43842d9ae1fSguenther {
43942d9ae1fSguenther 	if (connect_fd >= 0) {
44042d9ae1fSguenther 		close(connect_fd);
44142d9ae1fSguenther 		connect_fd = -1;
44242d9ae1fSguenther 	}
44342d9ae1fSguenther }
44442d9ae1fSguenther 
44542d9ae1fSguenther /*
44642d9ae1fSguenther  * ACCEPT
44742d9ae1fSguenther  */
44842d9ae1fSguenther static int accept_fd = -1;
44942d9ae1fSguenther void
accept_init(void)45042d9ae1fSguenther accept_init(void)
45142d9ae1fSguenther {
45242d9ae1fSguenther 	accept_fd = socket(AF_INET, SOCK_STREAM, 0);
45342d9ae1fSguenther 	listen(accept_fd, 2);
45442d9ae1fSguenther }
45542d9ae1fSguenther void *
accept_run(void * arg)45642d9ae1fSguenther accept_run(void *arg)
45742d9ae1fSguenther {
45842d9ae1fSguenther 	struct sockaddr_in sin;
45942d9ae1fSguenther 	socklen_t sl;
46042d9ae1fSguenther 	int *retval = arg;
46142d9ae1fSguenther 
46242d9ae1fSguenther 	sl = sizeof(sin);
46342d9ae1fSguenther 	retval[0] = accept(accept_fd, (struct sockaddr *)&sin, &sl);
46442d9ae1fSguenther 	retval[1] = errno;
46542d9ae1fSguenther 	return NULL;
46642d9ae1fSguenther }
46742d9ae1fSguenther void
accept_fini(void)46842d9ae1fSguenther accept_fini(void)
46942d9ae1fSguenther {
47042d9ae1fSguenther 	if (accept_fd >= 0) {
47142d9ae1fSguenther 		close(accept_fd);
47242d9ae1fSguenther 		accept_fd = -1;
47342d9ae1fSguenther 	}
47442d9ae1fSguenther }
47542d9ae1fSguenther 
47642d9ae1fSguenther /*
47742d9ae1fSguenther  * OPEN FIFO
47842d9ae1fSguenther  */
47942d9ae1fSguenther void
open_fifo_init(void)48042d9ae1fSguenther open_fifo_init(void)
48142d9ae1fSguenther {
48242d9ae1fSguenther 	/* let's get a fresh fifo */
48342d9ae1fSguenther 	if (unlink(FIFO_PATH) && errno != ENOENT)
48442d9ae1fSguenther 		err(1, "unlink %s", FIFO_PATH);
48542d9ae1fSguenther 	if (mkfifo(FIFO_PATH, 0600))
48642d9ae1fSguenther 		err(1, "mkfifo %s", FIFO_PATH);
48742d9ae1fSguenther }
48842d9ae1fSguenther void *
open_fifo_run(void * arg)48942d9ae1fSguenther open_fifo_run(void *arg)
49042d9ae1fSguenther {
49142d9ae1fSguenther 	int *retval = arg;
49242d9ae1fSguenther 
49342d9ae1fSguenther 	retval[0] = open(FIFO_PATH, O_RDONLY);
49442d9ae1fSguenther 	retval[1] = errno;
49542d9ae1fSguenther 	return NULL;
49642d9ae1fSguenther }
49742d9ae1fSguenther void
open_fifo_fini(void)49842d9ae1fSguenther open_fifo_fini(void)
49942d9ae1fSguenther {
50042d9ae1fSguenther 	if (unlink(FIFO_PATH) && errno != ENOENT)
50142d9ae1fSguenther 		err(1, "unlink %s", FIFO_PATH);
50242d9ae1fSguenther }
50342d9ae1fSguenther 
50442d9ae1fSguenther /*
50542d9ae1fSguenther  * SEMOP
50642d9ae1fSguenther  */
50742d9ae1fSguenther static int semid = -1;
50842d9ae1fSguenther void
semop_init(void)50942d9ae1fSguenther semop_init(void)
51042d9ae1fSguenther {
51142d9ae1fSguenther 	union {
51242d9ae1fSguenther 		int val;
51342d9ae1fSguenther 		struct semid_ds *buf;
51442d9ae1fSguenther 		unsigned short *array;
51542d9ae1fSguenther 	} semarg;
51642d9ae1fSguenther 	unsigned short val;
51742d9ae1fSguenther 
51842d9ae1fSguenther 	semid = semget(IPC_PRIVATE, 1, 0600);
51942d9ae1fSguenther 	semarg.array = &val;
52042d9ae1fSguenther 	val = 0;
52142d9ae1fSguenther 	semctl(semid, 0, SETALL, semarg);
52242d9ae1fSguenther }
52342d9ae1fSguenther void *
semop_run(void * arg)52442d9ae1fSguenther semop_run(void *arg)
52542d9ae1fSguenther {
52642d9ae1fSguenther 	struct sembuf op;
52742d9ae1fSguenther 	int *retval = arg;
52842d9ae1fSguenther 
52942d9ae1fSguenther 	op.sem_num = 0;
53042d9ae1fSguenther 	op.sem_op = -1;
53142d9ae1fSguenther 	op.sem_flg = 0;
53242d9ae1fSguenther 	retval[0] = semop(semid, &op, 1);
53342d9ae1fSguenther 	retval[1] = errno;
53442d9ae1fSguenther 	return NULL;
53542d9ae1fSguenther }
53642d9ae1fSguenther void
semop_fini(void)53742d9ae1fSguenther semop_fini(void)
53842d9ae1fSguenther {
53942d9ae1fSguenther 	if (semid >= 0) {
54042d9ae1fSguenther 		semctl(semid, 0, IPC_RMID, NULL);
54142d9ae1fSguenther 		semid = -1;
54242d9ae1fSguenther 	}
54342d9ae1fSguenther }
54442d9ae1fSguenther 
54542d9ae1fSguenther #define TESTSPEC_FULL(flag, name, prefix)				\
54642d9ae1fSguenther 	{ flag, name, prefix##_init, prefix##_run, prefix##_fini }
54742d9ae1fSguenther #define TESTSPEC(flag, name, prefix)					\
54842d9ae1fSguenther 	{ flag, name, NULL, prefix##_run, NULL }
54942d9ae1fSguenther struct test_spec test_specs[] = {
55042d9ae1fSguenther 	TESTSPEC_FULL(TEST_ACCEPT,	"accept",		accept),
55142d9ae1fSguenther 	TESTSPEC_FULL(TEST_CONNECT,	"connect",		connect),
55242d9ae1fSguenther 	TESTSPEC_FULL(TEST_FCNTL,	"fcntl(F_SETLKW)",	fcntl),
55342d9ae1fSguenther 	TESTSPEC_FULL(TEST_SEMOP,	"semop",		semop),
55442d9ae1fSguenther 	TESTSPEC_FULL(TEST_FLOCK,	"flock",		flock),
55542d9ae1fSguenther 	TESTSPEC_FULL(TEST_OPEN_FIFO,	"open_fifo",		open_fifo),
55642d9ae1fSguenther 
55742d9ae1fSguenther 	TESTSPEC(TEST_NANOSLEEP,	"nanosleep",		nanosleep),
55842d9ae1fSguenther 	TESTSPEC(TEST_POLL,		"poll",			poll),
55942d9ae1fSguenther 	TESTSPEC(TEST_SIGSUSPEND,	"sigsuspend",		sigsuspend),
56042d9ae1fSguenther 	{ 0 }
56142d9ae1fSguenther };
56242d9ae1fSguenther 
56342d9ae1fSguenther 
56442d9ae1fSguenther void *
run_tests(void * arg)56542d9ae1fSguenther run_tests(void *arg)
56642d9ae1fSguenther {
56742d9ae1fSguenther 	int tests = *(int *)arg;
56842d9ae1fSguenther 	int flag;
56942d9ae1fSguenther 	struct test_spec *test;
57042d9ae1fSguenther 	sigset_t mask;
57142d9ae1fSguenther 
57242d9ae1fSguenther 	/* make sure SIGALRM is unblocked for the tests */
57342d9ae1fSguenther 	sigemptyset(&mask);
57442d9ae1fSguenther 	sigaddset(&mask, SIGALRM);
57542d9ae1fSguenther 	sigprocmask(SIG_UNBLOCK, &mask, NULL);
57642d9ae1fSguenther 
57742d9ae1fSguenther 	while (tests > 0) {
57842d9ae1fSguenther 		flag = tests & ~(tests >> 1);
57942d9ae1fSguenther 		tests &= ~flag;
58042d9ae1fSguenther 		for (test = test_specs; test->flag; test++)
58142d9ae1fSguenther 			if (test->flag == flag) {
58242d9ae1fSguenther 				run(test);
58342d9ae1fSguenther 				break;
58442d9ae1fSguenther 			}
58542d9ae1fSguenther 	}
58642d9ae1fSguenther 
58742d9ae1fSguenther 	return arg;
58842d9ae1fSguenther }
58942d9ae1fSguenther 
59042d9ae1fSguenther int
main(int argc,char ** argv)59142d9ae1fSguenther main(int argc, char **argv)
59242d9ae1fSguenther {
59342d9ae1fSguenther 	int ch, tests;
59442d9ae1fSguenther 	sigset_t mask;
59542d9ae1fSguenther 	int r;
59642d9ae1fSguenther 	void *handle;
59742d9ae1fSguenther 	struct funcs *f;
59842d9ae1fSguenther 	pthread_t t;
59942d9ae1fSguenther 	void *ret;
60042d9ae1fSguenther 
60142d9ae1fSguenther 	set_sigalrm(0);
60242d9ae1fSguenther 
60342d9ae1fSguenther 	tests = 0;
60442d9ae1fSguenther 	while ((ch = getopt(argc, argv, "AacFfinoprSs")) != -1)
60542d9ae1fSguenther 		switch (ch) {
60642d9ae1fSguenther 		  case 'A':
60742d9ae1fSguenther 			tests |= TEST_ALL;
60842d9ae1fSguenther 			break;
60942d9ae1fSguenther 		  case 'a':
61042d9ae1fSguenther 			tests |= TEST_ACCEPT;
61142d9ae1fSguenther 			break;
61242d9ae1fSguenther 		  case 'c':
61342d9ae1fSguenther 			tests |= TEST_CONNECT;
61442d9ae1fSguenther 			break;
61542d9ae1fSguenther 		  case 'F':
61642d9ae1fSguenther 			tests |= TEST_FCNTL;
61742d9ae1fSguenther 			break;
61842d9ae1fSguenther 		  case 'f':
61942d9ae1fSguenther 			tests |= TEST_FLOCK;
62042d9ae1fSguenther 			break;
62142d9ae1fSguenther 		  case 'i':
62242d9ae1fSguenther 			set_sigalrm(0);
62342d9ae1fSguenther 			break;
62442d9ae1fSguenther 		  case 'n':
62542d9ae1fSguenther 			tests |= TEST_NANOSLEEP;
62642d9ae1fSguenther 			break;
62742d9ae1fSguenther 		  case 'o':
62842d9ae1fSguenther 			tests |= TEST_OPEN_FIFO;
62942d9ae1fSguenther 			break;
63042d9ae1fSguenther 		  case 'p':
63142d9ae1fSguenther 			tests |= TEST_POLL;
63242d9ae1fSguenther 			break;
63342d9ae1fSguenther 		  case 'r':
63442d9ae1fSguenther 			set_sigalrm(1);
63542d9ae1fSguenther 			break;
63642d9ae1fSguenther 		  case 's':
63742d9ae1fSguenther 			tests |= TEST_SIGSUSPEND;
63842d9ae1fSguenther 			break;
63942d9ae1fSguenther 		  case 'S':
64042d9ae1fSguenther 			tests |= TEST_SEMOP;
64142d9ae1fSguenther 			break;
64242d9ae1fSguenther 		}
64342d9ae1fSguenther 	if (tests == 0)
64442d9ae1fSguenther 		tests = TEST_ALL;
64542d9ae1fSguenther 
64642d9ae1fSguenther 	/* make sure SIGTERM is unblocked */
64742d9ae1fSguenther 	sigemptyset(&mask);
64842d9ae1fSguenther 	sigaddset(&mask, SIGTERM);
64942d9ae1fSguenther 	sigprocmask(SIG_UNBLOCK, &mask, NULL);
65042d9ae1fSguenther 
65142d9ae1fSguenther 	/*
65242d9ae1fSguenther 	 * Run them in the original thread
65342d9ae1fSguenther 	 */
65442d9ae1fSguenther 	printf("single threaded\n");
65542d9ae1fSguenther 	run_tests(&tests);
65642d9ae1fSguenther 
65742d9ae1fSguenther 
65842d9ae1fSguenther 	/*
65942d9ae1fSguenther 	 * Open libpthread, create a thread and run them in *that*
66042d9ae1fSguenther 	 */
66142d9ae1fSguenther 	if ((handle = dlopen("libpthread.so", RTLD_LAZY)) == NULL)
66242d9ae1fSguenther 		errx(1, "dlopen: %s", dlerror());
66342d9ae1fSguenther 
66442d9ae1fSguenther 	/* look up all the functions.  The cast here isn't strictly portable */
66542d9ae1fSguenther 	for (f = functions; f->name != NULL; f++) {
666*41a8fc2aSguenther 		if ((*(void **)f->callback = dlsym(handle, f->name)) == NULL &&
667*41a8fc2aSguenther 		    (*(void **)f->callback = dlsym(RTLD_DEFAULT, f->name)) == NULL)
66842d9ae1fSguenther 			errx(1, "dlsym %s: %s", f->name, dlerror());
66942d9ae1fSguenther 	}
67042d9ae1fSguenther 
67142d9ae1fSguenther 	/* block SIGALRM in the original thread */
67242d9ae1fSguenther 	sigemptyset(&mask);
67342d9ae1fSguenther 	sigaddset(&mask, SIGALRM);
67442d9ae1fSguenther 	sigprocmask(SIG_BLOCK, &mask, NULL);
67542d9ae1fSguenther 
67642d9ae1fSguenther 	printf("in thread after dlopen(pthread)\n");
67742d9ae1fSguenther 	if ((r = p_create(&t, NULL, run_tests, &tests)))
67842d9ae1fSguenther 		errc(1, r, "pthread_create");
67942d9ae1fSguenther 	if ((r = p_join(t, &ret)))
68042d9ae1fSguenther 		errc(1, r, "pthread_join");
68142d9ae1fSguenther 	if (ret != &tests)
68242d9ae1fSguenther 		errx(1, "bad return by thread: %p != %p", ret, (void *)&tests);
68342d9ae1fSguenther 
68442d9ae1fSguenther 
68542d9ae1fSguenther 	/*
68642d9ae1fSguenther 	 * Run the tests again, this time using cancellation
68742d9ae1fSguenther 	 */
68842d9ae1fSguenther 	printf("using cancellation\n");
68942d9ae1fSguenther 	run = run_cancel;
69042d9ae1fSguenther 	run_tests(&tests);
69142d9ae1fSguenther 
69242d9ae1fSguenther 	if (dlclose(handle))
69342d9ae1fSguenther 		errx(1, "dlclose: %s", dlerror());
69442d9ae1fSguenther 
69542d9ae1fSguenther 	return 0;
69642d9ae1fSguenther }
697