aboutsummaryrefslogtreecommitdiffstats
path: root/tools/xenstore/xs_watch_stress.c
blob: 91431e2376326bf601cbd347e995e3feecfbd9f9 (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
/* Stress test for watch code: two processes communicating by watches */
#include "xs.h"
#include "utils.h"
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

int main(int argc __attribute__((unused)), char *argv[])
{
	int childpid, status, fds[2];
	bool parent;
	unsigned int i, acks = 0;
	struct xs_handle *h;
	char *data;
	unsigned int len;
	const char *path, *otherpath;

	pipe(fds);
	childpid = fork();
	if (childpid == -1)
		barf_perror("Failed fork");
	parent = (childpid != 0);

	h = xs_daemon_open();
	if (!h)
		barf_perror("Could not connect to daemon");

	if (!xs_watch(h, "/", "token", 0))
		barf_perror("Could not set watch");

	if (parent) {
		char c;

		if (read(fds[0], &c, 1) != 1)
			barf("Child exited");

		path = "/parent";
		otherpath = "/child";
		/* Create initial node. */
		if (!xs_write(h, path, "0", 2, O_CREAT))
			barf_perror("Write to %s failed", path);
	} else {
		path = "/child";
		otherpath = "/parent";

		if (write(fds[1], "", 1) != 1)
			barf_perror("Write to parent failed");
	}

	for (i = 0; i < (argv[1] ? (unsigned)atoi(argv[1]) : 100);) {
		char **vec;

		vec = xs_read_watch(h);
		if (!vec)
			barf_perror("Read watch failed");

		if (!streq(vec[1], "token"))
			barf("Watch token %s bad", vec[1]);
		if (streq(vec[0], otherpath)) {
			char number[32];

			data = xs_read(h, otherpath, &len);
			if (!data)
				barf_perror("reading %s", otherpath);
			sprintf(number, "%i", atoi(data) + 1);
			free(data);
			if (!xs_write(h, path, number, strlen(number) + 1,
				      O_CREAT))
				barf_perror("writing %s", path);
			i++;
		} else if (!streq(vec[0], path))
			barf_perror("Watch fired on unknown path %s", vec[0]);
		xs_acknowledge_watch(h, vec[1]);
		acks++;
		free(vec);
	}

	if (!parent) {
		while (acks != 2 * i - 1) {
			char **vec;
			vec = xs_read_watch(h);
			if (!vec)
				barf_perror("Watch failed");
			if (!streq(vec[0], path))
				barf_perror("Watch fired path %s", vec[0]);
			if (!streq(vec[1], "token"))
				barf("Watch token %s bad", vec[1]);
			free(vec);

			printf("Expect %i events, only got %i\n",
			       2 * i - 1, acks);
			acks++;
		}
		exit(0);
	}

	if (acks != 2 * i)
		barf("Parent got %i watch events\n", acks);

	printf("Waiting for %i\n", childpid);
	if (waitpid(childpid, &status, 0) != childpid)
		barf_perror("Child wait failed");
	if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
		barf_perror("Child status %i", status);

	data = xs_read(h, path, &len);
	if (atoi(data) != 2 * (int)i)
		barf("%s count is %s\n", path, data);
	free(data);
	data = xs_read(h, otherpath, &len);
	if (atoi(data) != 2 * (int)i - 1)
		barf("%s count is %s\n", otherpath, data);
	free(data);
	printf("Success!\n");
	exit(0);
}