xref: /linux/tools/virtio/ringtest/main.c (revision 0181f8c809d6116a8347d8beb25a8c35ed22f7d7)
17a338472SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2481eaec3SMichael S. Tsirkin /*
3481eaec3SMichael S. Tsirkin  * Copyright (C) 2016 Red Hat, Inc.
4481eaec3SMichael S. Tsirkin  * Author: Michael S. Tsirkin <mst@redhat.com>
5481eaec3SMichael S. Tsirkin  *
6481eaec3SMichael S. Tsirkin  * Command line processing and common functions for ring benchmarking.
7481eaec3SMichael S. Tsirkin  */
8481eaec3SMichael S. Tsirkin #define _GNU_SOURCE
9481eaec3SMichael S. Tsirkin #include <getopt.h>
10481eaec3SMichael S. Tsirkin #include <pthread.h>
11481eaec3SMichael S. Tsirkin #include <assert.h>
12481eaec3SMichael S. Tsirkin #include <sched.h>
13481eaec3SMichael S. Tsirkin #include "main.h"
14481eaec3SMichael S. Tsirkin #include <sys/eventfd.h>
15481eaec3SMichael S. Tsirkin #include <stdlib.h>
16481eaec3SMichael S. Tsirkin #include <stdio.h>
17481eaec3SMichael S. Tsirkin #include <unistd.h>
18481eaec3SMichael S. Tsirkin #include <limits.h>
19481eaec3SMichael S. Tsirkin 
20481eaec3SMichael S. Tsirkin int runcycles = 10000000;
21481eaec3SMichael S. Tsirkin int max_outstanding = INT_MAX;
22481eaec3SMichael S. Tsirkin int batch = 1;
23a4979505SMichael S. Tsirkin int param = 0;
24481eaec3SMichael S. Tsirkin 
25481eaec3SMichael S. Tsirkin bool do_sleep = false;
26481eaec3SMichael S. Tsirkin bool do_relax = false;
27481eaec3SMichael S. Tsirkin bool do_exit = true;
28481eaec3SMichael S. Tsirkin 
29481eaec3SMichael S. Tsirkin unsigned ring_size = 256;
30481eaec3SMichael S. Tsirkin 
31481eaec3SMichael S. Tsirkin static int kickfd = -1;
32481eaec3SMichael S. Tsirkin static int callfd = -1;
33481eaec3SMichael S. Tsirkin 
34481eaec3SMichael S. Tsirkin void notify(int fd)
35481eaec3SMichael S. Tsirkin {
36481eaec3SMichael S. Tsirkin 	unsigned long long v = 1;
37481eaec3SMichael S. Tsirkin 	int r;
38481eaec3SMichael S. Tsirkin 
39481eaec3SMichael S. Tsirkin 	vmexit();
40481eaec3SMichael S. Tsirkin 	r = write(fd, &v, sizeof v);
41481eaec3SMichael S. Tsirkin 	assert(r == sizeof v);
42481eaec3SMichael S. Tsirkin 	vmentry();
43481eaec3SMichael S. Tsirkin }
44481eaec3SMichael S. Tsirkin 
45481eaec3SMichael S. Tsirkin void wait_for_notify(int fd)
46481eaec3SMichael S. Tsirkin {
47481eaec3SMichael S. Tsirkin 	unsigned long long v = 1;
48481eaec3SMichael S. Tsirkin 	int r;
49481eaec3SMichael S. Tsirkin 
50481eaec3SMichael S. Tsirkin 	vmexit();
51481eaec3SMichael S. Tsirkin 	r = read(fd, &v, sizeof v);
52481eaec3SMichael S. Tsirkin 	assert(r == sizeof v);
53481eaec3SMichael S. Tsirkin 	vmentry();
54481eaec3SMichael S. Tsirkin }
55481eaec3SMichael S. Tsirkin 
56481eaec3SMichael S. Tsirkin void kick(void)
57481eaec3SMichael S. Tsirkin {
58481eaec3SMichael S. Tsirkin 	notify(kickfd);
59481eaec3SMichael S. Tsirkin }
60481eaec3SMichael S. Tsirkin 
61481eaec3SMichael S. Tsirkin void wait_for_kick(void)
62481eaec3SMichael S. Tsirkin {
63481eaec3SMichael S. Tsirkin 	wait_for_notify(kickfd);
64481eaec3SMichael S. Tsirkin }
65481eaec3SMichael S. Tsirkin 
66481eaec3SMichael S. Tsirkin void call(void)
67481eaec3SMichael S. Tsirkin {
68481eaec3SMichael S. Tsirkin 	notify(callfd);
69481eaec3SMichael S. Tsirkin }
70481eaec3SMichael S. Tsirkin 
71481eaec3SMichael S. Tsirkin void wait_for_call(void)
72481eaec3SMichael S. Tsirkin {
73481eaec3SMichael S. Tsirkin 	wait_for_notify(callfd);
74481eaec3SMichael S. Tsirkin }
75481eaec3SMichael S. Tsirkin 
76481eaec3SMichael S. Tsirkin void set_affinity(const char *arg)
77481eaec3SMichael S. Tsirkin {
78481eaec3SMichael S. Tsirkin 	cpu_set_t cpuset;
79481eaec3SMichael S. Tsirkin 	int ret;
80481eaec3SMichael S. Tsirkin 	pthread_t self;
81481eaec3SMichael S. Tsirkin 	long int cpu;
82481eaec3SMichael S. Tsirkin 	char *endptr;
83481eaec3SMichael S. Tsirkin 
84481eaec3SMichael S. Tsirkin 	if (!arg)
85481eaec3SMichael S. Tsirkin 		return;
86481eaec3SMichael S. Tsirkin 
87481eaec3SMichael S. Tsirkin 	cpu = strtol(arg, &endptr, 0);
88481eaec3SMichael S. Tsirkin 	assert(!*endptr);
89481eaec3SMichael S. Tsirkin 
904f6d9bfcSDan Carpenter 	assert(cpu >= 0 && cpu < CPU_SETSIZE);
91481eaec3SMichael S. Tsirkin 
92481eaec3SMichael S. Tsirkin 	self = pthread_self();
93481eaec3SMichael S. Tsirkin 	CPU_ZERO(&cpuset);
94481eaec3SMichael S. Tsirkin 	CPU_SET(cpu, &cpuset);
95481eaec3SMichael S. Tsirkin 
96481eaec3SMichael S. Tsirkin 	ret = pthread_setaffinity_np(self, sizeof(cpu_set_t), &cpuset);
97481eaec3SMichael S. Tsirkin 	assert(!ret);
98481eaec3SMichael S. Tsirkin }
99481eaec3SMichael S. Tsirkin 
100d3c3589bSPaolo Bonzini void poll_used(void)
101d3c3589bSPaolo Bonzini {
102d3c3589bSPaolo Bonzini 	while (used_empty())
103d3c3589bSPaolo Bonzini 		busy_wait();
104d3c3589bSPaolo Bonzini }
105d3c3589bSPaolo Bonzini 
10644d65ea1SPaolo Bonzini static void __attribute__((__flatten__)) run_guest(void)
107481eaec3SMichael S. Tsirkin {
108481eaec3SMichael S. Tsirkin 	int completed_before;
109481eaec3SMichael S. Tsirkin 	int completed = 0;
110481eaec3SMichael S. Tsirkin 	int started = 0;
111481eaec3SMichael S. Tsirkin 	int bufs = runcycles;
112481eaec3SMichael S. Tsirkin 	int spurious = 0;
113481eaec3SMichael S. Tsirkin 	int r;
114481eaec3SMichael S. Tsirkin 	unsigned len;
115481eaec3SMichael S. Tsirkin 	void *buf;
116481eaec3SMichael S. Tsirkin 	int tokick = batch;
117481eaec3SMichael S. Tsirkin 
118481eaec3SMichael S. Tsirkin 	for (;;) {
119481eaec3SMichael S. Tsirkin 		if (do_sleep)
120481eaec3SMichael S. Tsirkin 			disable_call();
121481eaec3SMichael S. Tsirkin 		completed_before = completed;
122481eaec3SMichael S. Tsirkin 		do {
123481eaec3SMichael S. Tsirkin 			if (started < bufs &&
124481eaec3SMichael S. Tsirkin 			    started - completed < max_outstanding) {
125bb991288SMichael S. Tsirkin 				r = add_inbuf(0, "Buffer\n", "Hello, world!");
126481eaec3SMichael S. Tsirkin 				if (__builtin_expect(r == 0, true)) {
127481eaec3SMichael S. Tsirkin 					++started;
128481eaec3SMichael S. Tsirkin 					if (!--tokick) {
129481eaec3SMichael S. Tsirkin 						tokick = batch;
130481eaec3SMichael S. Tsirkin 						if (do_sleep)
131481eaec3SMichael S. Tsirkin 							kick_available();
132481eaec3SMichael S. Tsirkin 					}
133481eaec3SMichael S. Tsirkin 
134481eaec3SMichael S. Tsirkin 				}
135481eaec3SMichael S. Tsirkin 			} else
136481eaec3SMichael S. Tsirkin 				r = -1;
137481eaec3SMichael S. Tsirkin 
138481eaec3SMichael S. Tsirkin 			/* Flush out completed bufs if any */
139481eaec3SMichael S. Tsirkin 			if (get_buf(&len, &buf)) {
140481eaec3SMichael S. Tsirkin 				++completed;
141481eaec3SMichael S. Tsirkin 				if (__builtin_expect(completed == bufs, false))
142481eaec3SMichael S. Tsirkin 					return;
143481eaec3SMichael S. Tsirkin 				r = 0;
144481eaec3SMichael S. Tsirkin 			}
145481eaec3SMichael S. Tsirkin 		} while (r == 0);
146481eaec3SMichael S. Tsirkin 		if (completed == completed_before)
147481eaec3SMichael S. Tsirkin 			++spurious;
148481eaec3SMichael S. Tsirkin 		assert(completed <= bufs);
149481eaec3SMichael S. Tsirkin 		assert(started <= bufs);
150481eaec3SMichael S. Tsirkin 		if (do_sleep) {
151948a8ac2SPaolo Bonzini 			if (used_empty() && enable_call())
152481eaec3SMichael S. Tsirkin 				wait_for_call();
153481eaec3SMichael S. Tsirkin 		} else {
154481eaec3SMichael S. Tsirkin 			poll_used();
155481eaec3SMichael S. Tsirkin 		}
156481eaec3SMichael S. Tsirkin 	}
157481eaec3SMichael S. Tsirkin }
158481eaec3SMichael S. Tsirkin 
159d3c3589bSPaolo Bonzini void poll_avail(void)
160d3c3589bSPaolo Bonzini {
161d3c3589bSPaolo Bonzini 	while (avail_empty())
162d3c3589bSPaolo Bonzini 		busy_wait();
163d3c3589bSPaolo Bonzini }
164d3c3589bSPaolo Bonzini 
16544d65ea1SPaolo Bonzini static void __attribute__((__flatten__)) run_host(void)
166481eaec3SMichael S. Tsirkin {
167481eaec3SMichael S. Tsirkin 	int completed_before;
168481eaec3SMichael S. Tsirkin 	int completed = 0;
169481eaec3SMichael S. Tsirkin 	int spurious = 0;
170481eaec3SMichael S. Tsirkin 	int bufs = runcycles;
171481eaec3SMichael S. Tsirkin 	unsigned len;
172481eaec3SMichael S. Tsirkin 	void *buf;
173481eaec3SMichael S. Tsirkin 
174481eaec3SMichael S. Tsirkin 	for (;;) {
175481eaec3SMichael S. Tsirkin 		if (do_sleep) {
176948a8ac2SPaolo Bonzini 			if (avail_empty() && enable_kick())
177481eaec3SMichael S. Tsirkin 				wait_for_kick();
178481eaec3SMichael S. Tsirkin 		} else {
179481eaec3SMichael S. Tsirkin 			poll_avail();
180481eaec3SMichael S. Tsirkin 		}
181481eaec3SMichael S. Tsirkin 		if (do_sleep)
182481eaec3SMichael S. Tsirkin 			disable_kick();
183481eaec3SMichael S. Tsirkin 		completed_before = completed;
184481eaec3SMichael S. Tsirkin 		while (__builtin_expect(use_buf(&len, &buf), true)) {
185481eaec3SMichael S. Tsirkin 			if (do_sleep)
186481eaec3SMichael S. Tsirkin 				call_used();
187481eaec3SMichael S. Tsirkin 			++completed;
188481eaec3SMichael S. Tsirkin 			if (__builtin_expect(completed == bufs, false))
189481eaec3SMichael S. Tsirkin 				return;
190481eaec3SMichael S. Tsirkin 		}
191481eaec3SMichael S. Tsirkin 		if (completed == completed_before)
192481eaec3SMichael S. Tsirkin 			++spurious;
193481eaec3SMichael S. Tsirkin 		assert(completed <= bufs);
194481eaec3SMichael S. Tsirkin 		if (completed == bufs)
195481eaec3SMichael S. Tsirkin 			break;
196481eaec3SMichael S. Tsirkin 	}
197481eaec3SMichael S. Tsirkin }
198481eaec3SMichael S. Tsirkin 
199481eaec3SMichael S. Tsirkin void *start_guest(void *arg)
200481eaec3SMichael S. Tsirkin {
201481eaec3SMichael S. Tsirkin 	set_affinity(arg);
202481eaec3SMichael S. Tsirkin 	run_guest();
203481eaec3SMichael S. Tsirkin 	pthread_exit(NULL);
204481eaec3SMichael S. Tsirkin }
205481eaec3SMichael S. Tsirkin 
206481eaec3SMichael S. Tsirkin void *start_host(void *arg)
207481eaec3SMichael S. Tsirkin {
208481eaec3SMichael S. Tsirkin 	set_affinity(arg);
209481eaec3SMichael S. Tsirkin 	run_host();
210481eaec3SMichael S. Tsirkin 	pthread_exit(NULL);
211481eaec3SMichael S. Tsirkin }
212481eaec3SMichael S. Tsirkin 
213481eaec3SMichael S. Tsirkin static const char optstring[] = "";
214481eaec3SMichael S. Tsirkin static const struct option longopts[] = {
215481eaec3SMichael S. Tsirkin 	{
216481eaec3SMichael S. Tsirkin 		.name = "help",
217481eaec3SMichael S. Tsirkin 		.has_arg = no_argument,
218481eaec3SMichael S. Tsirkin 		.val = 'h',
219481eaec3SMichael S. Tsirkin 	},
220481eaec3SMichael S. Tsirkin 	{
221481eaec3SMichael S. Tsirkin 		.name = "host-affinity",
222481eaec3SMichael S. Tsirkin 		.has_arg = required_argument,
223481eaec3SMichael S. Tsirkin 		.val = 'H',
224481eaec3SMichael S. Tsirkin 	},
225481eaec3SMichael S. Tsirkin 	{
226481eaec3SMichael S. Tsirkin 		.name = "guest-affinity",
227481eaec3SMichael S. Tsirkin 		.has_arg = required_argument,
228481eaec3SMichael S. Tsirkin 		.val = 'G',
229481eaec3SMichael S. Tsirkin 	},
230481eaec3SMichael S. Tsirkin 	{
231481eaec3SMichael S. Tsirkin 		.name = "ring-size",
232481eaec3SMichael S. Tsirkin 		.has_arg = required_argument,
233481eaec3SMichael S. Tsirkin 		.val = 'R',
234481eaec3SMichael S. Tsirkin 	},
235481eaec3SMichael S. Tsirkin 	{
236481eaec3SMichael S. Tsirkin 		.name = "run-cycles",
237481eaec3SMichael S. Tsirkin 		.has_arg = required_argument,
238481eaec3SMichael S. Tsirkin 		.val = 'C',
239481eaec3SMichael S. Tsirkin 	},
240481eaec3SMichael S. Tsirkin 	{
241481eaec3SMichael S. Tsirkin 		.name = "outstanding",
242481eaec3SMichael S. Tsirkin 		.has_arg = required_argument,
243481eaec3SMichael S. Tsirkin 		.val = 'o',
244481eaec3SMichael S. Tsirkin 	},
245481eaec3SMichael S. Tsirkin 	{
246481eaec3SMichael S. Tsirkin 		.name = "batch",
247481eaec3SMichael S. Tsirkin 		.has_arg = required_argument,
248481eaec3SMichael S. Tsirkin 		.val = 'b',
249481eaec3SMichael S. Tsirkin 	},
250481eaec3SMichael S. Tsirkin 	{
251a4979505SMichael S. Tsirkin 		.name = "param",
252a4979505SMichael S. Tsirkin 		.has_arg = required_argument,
253a4979505SMichael S. Tsirkin 		.val = 'p',
254a4979505SMichael S. Tsirkin 	},
255a4979505SMichael S. Tsirkin 	{
256481eaec3SMichael S. Tsirkin 		.name = "sleep",
257481eaec3SMichael S. Tsirkin 		.has_arg = no_argument,
258481eaec3SMichael S. Tsirkin 		.val = 's',
259481eaec3SMichael S. Tsirkin 	},
260481eaec3SMichael S. Tsirkin 	{
261481eaec3SMichael S. Tsirkin 		.name = "relax",
262481eaec3SMichael S. Tsirkin 		.has_arg = no_argument,
263481eaec3SMichael S. Tsirkin 		.val = 'x',
264481eaec3SMichael S. Tsirkin 	},
265481eaec3SMichael S. Tsirkin 	{
266481eaec3SMichael S. Tsirkin 		.name = "exit",
267481eaec3SMichael S. Tsirkin 		.has_arg = no_argument,
268481eaec3SMichael S. Tsirkin 		.val = 'e',
269481eaec3SMichael S. Tsirkin 	},
270481eaec3SMichael S. Tsirkin 	{
271481eaec3SMichael S. Tsirkin 	}
272481eaec3SMichael S. Tsirkin };
273481eaec3SMichael S. Tsirkin 
274481eaec3SMichael S. Tsirkin static void help(void)
275481eaec3SMichael S. Tsirkin {
276481eaec3SMichael S. Tsirkin 	fprintf(stderr, "Usage: <test> [--help]"
277481eaec3SMichael S. Tsirkin 		" [--host-affinity H]"
278481eaec3SMichael S. Tsirkin 		" [--guest-affinity G]"
279*a8927f69SZhu Jun 		" [--ring-size R (default: %u)]"
280481eaec3SMichael S. Tsirkin 		" [--run-cycles C (default: %d)]"
281481eaec3SMichael S. Tsirkin 		" [--batch b]"
282481eaec3SMichael S. Tsirkin 		" [--outstanding o]"
283a4979505SMichael S. Tsirkin 		" [--param p]"
284481eaec3SMichael S. Tsirkin 		" [--sleep]"
285481eaec3SMichael S. Tsirkin 		" [--relax]"
286481eaec3SMichael S. Tsirkin 		" [--exit]"
287481eaec3SMichael S. Tsirkin 		"\n",
288481eaec3SMichael S. Tsirkin 		ring_size,
289481eaec3SMichael S. Tsirkin 		runcycles);
290481eaec3SMichael S. Tsirkin }
291481eaec3SMichael S. Tsirkin 
292481eaec3SMichael S. Tsirkin int main(int argc, char **argv)
293481eaec3SMichael S. Tsirkin {
294481eaec3SMichael S. Tsirkin 	int ret;
295481eaec3SMichael S. Tsirkin 	pthread_t host, guest;
296481eaec3SMichael S. Tsirkin 	void *tret;
297481eaec3SMichael S. Tsirkin 	char *host_arg = NULL;
298481eaec3SMichael S. Tsirkin 	char *guest_arg = NULL;
299481eaec3SMichael S. Tsirkin 	char *endptr;
300481eaec3SMichael S. Tsirkin 	long int c;
301481eaec3SMichael S. Tsirkin 
302481eaec3SMichael S. Tsirkin 	kickfd = eventfd(0, 0);
303481eaec3SMichael S. Tsirkin 	assert(kickfd >= 0);
304481eaec3SMichael S. Tsirkin 	callfd = eventfd(0, 0);
305481eaec3SMichael S. Tsirkin 	assert(callfd >= 0);
306481eaec3SMichael S. Tsirkin 
307481eaec3SMichael S. Tsirkin 	for (;;) {
308481eaec3SMichael S. Tsirkin 		int o = getopt_long(argc, argv, optstring, longopts, NULL);
309481eaec3SMichael S. Tsirkin 		switch (o) {
310481eaec3SMichael S. Tsirkin 		case -1:
311481eaec3SMichael S. Tsirkin 			goto done;
312481eaec3SMichael S. Tsirkin 		case '?':
313481eaec3SMichael S. Tsirkin 			help();
314481eaec3SMichael S. Tsirkin 			exit(2);
315481eaec3SMichael S. Tsirkin 		case 'H':
316481eaec3SMichael S. Tsirkin 			host_arg = optarg;
317481eaec3SMichael S. Tsirkin 			break;
318481eaec3SMichael S. Tsirkin 		case 'G':
319481eaec3SMichael S. Tsirkin 			guest_arg = optarg;
320481eaec3SMichael S. Tsirkin 			break;
321481eaec3SMichael S. Tsirkin 		case 'R':
322481eaec3SMichael S. Tsirkin 			ring_size = strtol(optarg, &endptr, 0);
323481eaec3SMichael S. Tsirkin 			assert(ring_size && !(ring_size & (ring_size - 1)));
324481eaec3SMichael S. Tsirkin 			assert(!*endptr);
325481eaec3SMichael S. Tsirkin 			break;
326481eaec3SMichael S. Tsirkin 		case 'C':
327481eaec3SMichael S. Tsirkin 			c = strtol(optarg, &endptr, 0);
328481eaec3SMichael S. Tsirkin 			assert(!*endptr);
329481eaec3SMichael S. Tsirkin 			assert(c > 0 && c < INT_MAX);
330481eaec3SMichael S. Tsirkin 			runcycles = c;
331481eaec3SMichael S. Tsirkin 			break;
332481eaec3SMichael S. Tsirkin 		case 'o':
333481eaec3SMichael S. Tsirkin 			c = strtol(optarg, &endptr, 0);
334481eaec3SMichael S. Tsirkin 			assert(!*endptr);
335481eaec3SMichael S. Tsirkin 			assert(c > 0 && c < INT_MAX);
336481eaec3SMichael S. Tsirkin 			max_outstanding = c;
337481eaec3SMichael S. Tsirkin 			break;
338a4979505SMichael S. Tsirkin 		case 'p':
339a4979505SMichael S. Tsirkin 			c = strtol(optarg, &endptr, 0);
340a4979505SMichael S. Tsirkin 			assert(!*endptr);
341a4979505SMichael S. Tsirkin 			assert(c > 0 && c < INT_MAX);
342a4979505SMichael S. Tsirkin 			param = c;
343a4979505SMichael S. Tsirkin 			break;
344481eaec3SMichael S. Tsirkin 		case 'b':
345481eaec3SMichael S. Tsirkin 			c = strtol(optarg, &endptr, 0);
346481eaec3SMichael S. Tsirkin 			assert(!*endptr);
347481eaec3SMichael S. Tsirkin 			assert(c > 0 && c < INT_MAX);
348481eaec3SMichael S. Tsirkin 			batch = c;
349481eaec3SMichael S. Tsirkin 			break;
350481eaec3SMichael S. Tsirkin 		case 's':
351481eaec3SMichael S. Tsirkin 			do_sleep = true;
352481eaec3SMichael S. Tsirkin 			break;
353481eaec3SMichael S. Tsirkin 		case 'x':
354481eaec3SMichael S. Tsirkin 			do_relax = true;
355481eaec3SMichael S. Tsirkin 			break;
356481eaec3SMichael S. Tsirkin 		case 'e':
357481eaec3SMichael S. Tsirkin 			do_exit = true;
358481eaec3SMichael S. Tsirkin 			break;
359481eaec3SMichael S. Tsirkin 		default:
360481eaec3SMichael S. Tsirkin 			help();
361481eaec3SMichael S. Tsirkin 			exit(4);
362481eaec3SMichael S. Tsirkin 			break;
363481eaec3SMichael S. Tsirkin 		}
364481eaec3SMichael S. Tsirkin 	}
365481eaec3SMichael S. Tsirkin 
366481eaec3SMichael S. Tsirkin 	/* does nothing here, used to make sure all smp APIs compile */
367481eaec3SMichael S. Tsirkin 	smp_acquire();
368481eaec3SMichael S. Tsirkin 	smp_release();
369481eaec3SMichael S. Tsirkin 	smp_mb();
370481eaec3SMichael S. Tsirkin done:
371481eaec3SMichael S. Tsirkin 
372481eaec3SMichael S. Tsirkin 	if (batch > max_outstanding)
373481eaec3SMichael S. Tsirkin 		batch = max_outstanding;
374481eaec3SMichael S. Tsirkin 
375481eaec3SMichael S. Tsirkin 	if (optind < argc) {
376481eaec3SMichael S. Tsirkin 		help();
377481eaec3SMichael S. Tsirkin 		exit(4);
378481eaec3SMichael S. Tsirkin 	}
379481eaec3SMichael S. Tsirkin 	alloc_ring();
380481eaec3SMichael S. Tsirkin 
381481eaec3SMichael S. Tsirkin 	ret = pthread_create(&host, NULL, start_host, host_arg);
382481eaec3SMichael S. Tsirkin 	assert(!ret);
383481eaec3SMichael S. Tsirkin 	ret = pthread_create(&guest, NULL, start_guest, guest_arg);
384481eaec3SMichael S. Tsirkin 	assert(!ret);
385481eaec3SMichael S. Tsirkin 
386481eaec3SMichael S. Tsirkin 	ret = pthread_join(guest, &tret);
387481eaec3SMichael S. Tsirkin 	assert(!ret);
388481eaec3SMichael S. Tsirkin 	ret = pthread_join(host, &tret);
389481eaec3SMichael S. Tsirkin 	assert(!ret);
390481eaec3SMichael S. Tsirkin 	return 0;
391481eaec3SMichael S. Tsirkin }
392