summaryrefslogtreecommitdiffstats
path: root/test/run-mutex1.c
blob: eb75946fe25fadf5ac74fc82769a263ee2ff0068 (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
#include "../common/tdb_private.h"
#include "../common/io.c"
#include "../common/tdb.c"
#include "../common/lock.c"
#include "../common/freelist.c"
#include "../common/traverse.c"
#include "../common/transaction.c"
#include "../common/error.c"
#include "../common/open.c"
#include "../common/check.c"
#include "../common/hash.c"
#include "../common/mutex.c"
#include "tap-interface.h"
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdarg.h>

static TDB_DATA key, data;

static void log_fn(struct tdb_context *tdb, enum tdb_debug_level level,
		   const char *fmt, ...)
{
	va_list ap;
	va_start(ap, fmt);
	vfprintf(stderr, fmt, ap);
	va_end(ap);
}

static int do_child(int tdb_flags, int to, int from)
{
	struct tdb_context *tdb;
	unsigned int log_count;
	struct tdb_logging_context log_ctx = { log_fn, &log_count };
	int ret;
	char c = 0;

	tdb = tdb_open_ex("mutex1.tdb", 0, tdb_flags,
			  O_RDWR|O_CREAT, 0755, &log_ctx, NULL);
	ok(tdb, "tdb_open_ex should succeed");

	ret = tdb_chainlock(tdb, key);
	ok(ret == 0, "tdb_chainlock should succeed");

	write(to, &c, sizeof(c));
	read(from, &c, sizeof(c));

	ret = tdb_chainunlock(tdb, key);
	ok(ret == 0, "tdb_chainunlock should succeed");

	write(to, &c, sizeof(c));
	read(from, &c, sizeof(c));

	ret = tdb_allrecord_lock(tdb, F_WRLCK, TDB_LOCK_WAIT, false);
	ok(ret == 0, "tdb_allrecord_lock should succeed");

	write(to, &c, sizeof(c));
	read(from, &c, sizeof(c));

	ret = tdb_allrecord_unlock(tdb, F_WRLCK, false);
	ok(ret == 0, "tdb_allrecord_lock should succeed");

	return 0;
}

/* The code should barf on TDBs created with rwlocks. */
int main(int argc, char *argv[])
{
	struct tdb_context *tdb;
	unsigned int log_count;
	struct tdb_logging_context log_ctx = { log_fn, &log_count };
	int ret, status;
	pid_t child, wait_ret;
	int fromchild[2];
	int tochild[2];
	char c;
	int tdb_flags;
	bool runtime_support;

	runtime_support = tdb_runtime_check_for_robust_mutexes();

	if (!runtime_support) {
		skip(1, "No robust mutex support");
		return exit_status();
	}

	key.dsize = strlen("hi");
	key.dptr = discard_const_p(uint8_t, "hi");
	data.dsize = strlen("world");
	data.dptr = discard_const_p(uint8_t, "world");

	pipe(fromchild);
	pipe(tochild);

	tdb_flags = TDB_INCOMPATIBLE_HASH|
		TDB_MUTEX_LOCKING|
		TDB_CLEAR_IF_FIRST;

	child = fork();
	if (child == 0) {
		close(fromchild[0]);
		close(tochild[1]);
		return do_child(tdb_flags, fromchild[1], tochild[0]);
	}
	close(fromchild[1]);
	close(tochild[0]);

	read(fromchild[0], &c, sizeof(c));

	tdb = tdb_open_ex("mutex1.tdb", 0, tdb_flags,
			  O_RDWR|O_CREAT, 0755, &log_ctx, NULL);
	ok(tdb, "tdb_open_ex should succeed");

	write(tochild[1], &c, sizeof(c));
	read(fromchild[0], &c, sizeof(c));

	ret = tdb_allrecord_lock(tdb, F_WRLCK, TDB_LOCK_WAIT, false);
	ok(ret == 0, "tdb_allrecord_lock should succeed");

	ret = tdb_store(tdb, key, data, 0);
	ok(ret == 0, "tdb_store should succeed");

	ret = tdb_allrecord_unlock(tdb, F_WRLCK, false);
	ok(ret == 0, "tdb_allrecord_unlock should succeed");

	write(tochild[1], &c, sizeof(c));
	read(fromchild[0], &c, sizeof(c));
	write(tochild[1], &c, sizeof(c));

	ret = tdb_delete(tdb, key);
	ok(ret == 0, "tdb_delete should succeed");

	wait_ret = wait(&status);
	ok(wait_ret == child, "child should have exited correctly");

	diag("done");
	return exit_status();
}