summaryrefslogtreecommitdiff
path: root/tools/test/stress2/misc/socketpair3.sh
blob: d96719cc6e0abc5c939936a7f26f241f8fbfaf64 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
#!/bin/sh

# Bug 227285 - File descriptor passing does not work reliably on SMP system
# (cache coherency issue?)
# "socketpair3: read failed in parent: 0, so_error: No error: 0 (0), ret2: 0"
# seen.

# Original test scenario by: jan.kokemueller@gmail.com

# Page fault seen in WiP socket code.

. ../default.cfg
dir=/tmp
odir=`pwd`
cd $dir
sed '1,/^EOF/d' < $odir/$0 > $dir/socketpair3.c
mycc -o socketpair3 -Wall -Wextra -O0 -g socketpair3.c -lnv || exit 1
rm -f socketpair3.c
cd $odir

for i in `jot 6`; do
	$dir/socketpair3 &
	pids="$pids $!"
done
s=0
for i in $pids; do
	wait $i
	[ $? -ne 0 ] && s=1
done
[ -f socketpair3.core -a $s -eq 0 ] &&
    { ls -l socketpair3.core; mv socketpair3.core /tmp; s=1; }

rm -rf $dir/socketpair3
exit $s

EOF
#include <sys/types.h>

#include <sys/procdesc.h>
#include <sys/socket.h>
#include <sys/wait.h>

#include <err.h>
#include <poll.h>
#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <unistd.h>

// From libnv.
extern int fd_send(int sock, const int *fds, size_t nfds);
extern int fd_recv(int sock, int *fds, size_t nfds);

int main(void)
{
	pid_t pid;
	time_t start;
	int child_fd;
	int sock[2];

	start = time(NULL);
	while (time(NULL) - start < 60) {
		if (socketpair(PF_UNIX, SOCK_STREAM, 0, sock) < 0)
			err(1, "socketpair");

		pid = pdfork(&child_fd, PD_CLOEXEC);
		if (pid < 0)
			err(1, "pdfork");

		if (pid == 0) {
			ssize_t ret;
			int sock_child[2];
			int dummy = 0;

			close(sock[0]);
			if (socketpair(PF_UNIX, SOCK_STREAM, /**/
			    0, sock_child) < 0)
				err(1, "socketpair");

			if (fd_send(sock[1], &sock_child[0], 1) != 0)
				errx(1, "fd_send failed");
#ifdef WORKAROUND
			if (read(sock[1], &dummy, 1) != 1)
				err(1, "write");
#endif

			close(sock_child[0]);

			if (write(sock_child[1], &dummy, 1) != 1)
				err(1, "write");

			if ((ret = read(sock_child[1], &dummy, 1)) != 1)
				errx(1, "read failed in child: %d",
				    (int)ret);

			close(sock_child[1]);

			_exit(0);
		}

		close(sock[1]);

		int sock_child;
		uint8_t dummy;

		if (fd_recv(sock[0], &sock_child, 1) != 0)
			errx(1, "fd_recv failed");
#ifdef WORKAROUND
		if (write(sock[0], &dummy, 1) != 1)
			err(1, "write");
#endif

		ssize_t ret;
		if ((ret = read(sock_child, &dummy, 1)) != 1) {
			int error;
			socklen_t err_len = sizeof(error);

			if (getsockopt(sock_child, SOL_SOCKET, SO_ERROR,
			    &error, &err_len) < 0)
				err(1, "getsockopt");

			ssize_t ret2 = read(sock_child, &dummy, 1);

			errx(1,
			    "read failed in parent: %d, so_error: %s (%d), "
			    "ret2: %d", (int)ret, strerror(error), error,
			    (int)ret2);
		}

		if (write(sock_child, &dummy, 1) != 1)
			err(1, "write");

		close(sock_child);

		struct pollfd pfd = { .fd = child_fd };
		poll(&pfd, 1, -1);

		close(child_fd);
		close(sock[0]);
	}

	return (0);
}