summaryrefslogtreecommitdiff
path: root/lib/ccan/failtest/test/run-locking.c
blob: da0ee70facf9a5d0fc188b677246601762fc80a4 (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
/* Include the C files directly. */
#include <ccan/failtest/failtest.c>
#include <stdlib.h>
#include <setjmp.h>
#include <stdio.h>
#include <stdarg.h>
#include <assert.h>
#include <ccan/tap/tap.h>

#define SIZE 8

/* We don't want to fork and fail; we're just testing lock recording. */
static enum failtest_result dont_fail(struct tlist_calls *history)
{
	return FAIL_DONT_FAIL;
}

static bool place_lock(int fd, char lockarr[], unsigned pos, unsigned size,
		       int type)
{
	struct flock fl;

	/* Update record keeping. */
	if (type == F_RDLCK)
		memset(lockarr+pos, 1, size);
	else if (type == F_WRLCK)
		memset(lockarr+pos, 2, size);
	else
		memset(lockarr+pos, 0, size);

	fl.l_whence = SEEK_SET;
	fl.l_type = type;
	fl.l_start = pos;
	fl.l_len = size;
	return failtest_fcntl(fd, "run-locking.c", 1, F_SETLK, &fl) == 0;
}

static char lock_lookup(int fd, unsigned pos)
{
	char ret = 0;
	unsigned int i;
	struct lock_info *l;

	for (i = 0; i < lock_num; i++) {
		l = &locks[i];

		if (l->fd != fd)
			continue;

		if (pos >= l->start && pos <= l->end) {
			if (ret)
				ret = 3;
			else if (l->type == F_RDLCK)
				ret = 1;
			else
				ret = 2;
		}
	}
	return ret;
}

static bool test(int fd,
		 unsigned p1, unsigned s1,
		 unsigned p2, unsigned s2,
		 unsigned p3, unsigned s3)
{
	unsigned int i;
	char lockarr[SIZE];

	memset(lockarr, 0, sizeof(lockarr));

	if (!place_lock(fd, lockarr, p1, s1, F_WRLCK))
		return false;

	if (!place_lock(fd, lockarr, p2, s2, F_RDLCK))
		return false;

	if (!place_lock(fd, lockarr, p3, s3, F_UNLCK))
		return false;

	for (i = 0; i < SIZE; i++) {
		if (lock_lookup(fd, i) != lockarr[i])
			return false;
	}

	/* Reset lock info. */
	lock_num = 0;
	return true;
}

int main(void)
{
	int fd;
	long flags;
	unsigned int isize;

	plan_tests(5835);
	failtest_init(0, NULL);
	failtest_hook = dont_fail;

	fd = open("run-locking-scratch", O_RDWR|O_CREAT, 0600);
	/* GETFL and SETFL wrappers should pass through. */
	flags = fcntl(fd, F_GETFL);
	ok1(failtest_fcntl(fd, "run-locking.c", 1, F_GETFL) == flags);
	flags |= O_NONBLOCK;
	ok1(failtest_fcntl(fd, "run-locking.c", 1, F_SETFL, flags) == 0);
	ok1(failtest_fcntl(fd, "run-locking.c", 1, F_GETFL) == flags);

	for (isize = 1; isize < 4; isize++) {
		unsigned int ipos;
		for (ipos = 0; ipos + isize < SIZE; ipos++) {
			unsigned int jsize;
			for (jsize = 1; jsize < 4; jsize++) {
				unsigned int jpos;
				for (jpos = 0; jpos + jsize < SIZE; jpos++) {
					unsigned int ksize;
					for (ksize = 1; ksize < 4; ksize++) {
						unsigned int kpos;
						for (kpos = 0;
						     kpos + ksize < SIZE;
						     kpos++) {
							ok1(test(fd,
								 ipos, isize,
								 jpos, jsize,
								 kpos, ksize));
						}
					}
				}
			}
		}
	}

	return exit_status();
}