]> git.proxmox.com Git - mirror_ovs.git/blame - tests/test-lockfile.c
classifier: Fix segfault iterating with rules that differ only in priority.
[mirror_ovs.git] / tests / test-lockfile.c
CommitLineData
ac718c9d 1/*
93ff0290 2 * Copyright (c) 2009, 2010 Nicira Networks.
ac718c9d
BP
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at:
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <config.h>
18
19#include "lockfile.h"
20
21#include <errno.h>
22#include <stdlib.h>
23#include <sys/wait.h>
24#include <unistd.h>
25
26#include "process.h"
27#include "timeval.h"
28#include "util.h"
1e8cf0f7 29#include "vlog.h"
ac718c9d
BP
30
31#undef NDEBUG
32#include <assert.h>
33
34struct test {
35 const char *name;
36 void (*function)(void);
37};
38
39static const struct test tests[];
40
41static void
42run_lock_and_unlock(void)
43{
44 struct lockfile *lockfile;
45
46 assert(lockfile_lock("file", 0, &lockfile) == 0);
47 lockfile_unlock(lockfile);
48}
49
50static void
51run_lock_and_unlock_twice(void)
52{
53 struct lockfile *lockfile;
54
55 assert(lockfile_lock("file", 0, &lockfile) == 0);
56 lockfile_unlock(lockfile);
57
58 assert(lockfile_lock("file", 0, &lockfile) == 0);
59 lockfile_unlock(lockfile);
60}
61
62static void
63run_lock_blocks_same_process(void)
64{
65 struct lockfile *lockfile;
66
67 assert(lockfile_lock("file", 0, &lockfile) == 0);
68 assert(lockfile_lock("file", 0, &lockfile) == EDEADLK);
69 lockfile_unlock(lockfile);
70}
71
72static void
73run_lock_blocks_same_process_twice(void)
74{
75 struct lockfile *lockfile;
76
77 assert(lockfile_lock("file", 0, &lockfile) == 0);
78 assert(lockfile_lock("file", 0, &lockfile) == EDEADLK);
79 assert(lockfile_lock("file", 0, &lockfile) == EDEADLK);
80 lockfile_unlock(lockfile);
81}
82
83static enum { PARENT, CHILD }
84do_fork(void)
85{
86 switch (fork()) {
87 case 0:
88 time_postfork();
89 lockfile_postfork();
90 return CHILD;
91
92 default:
93 return PARENT;
94
95 case -1:
96 /* Error. */
97 ovs_fatal(errno, "fork failed");
98 }
99}
100
101static void
102run_lock_blocks_other_process(void)
103{
93ff0290
BP
104 /* Making this static prevents a memory leak warning from valgrind for the
105 * parent process, which cannot easily unlock (and free) 'lockfile' because
106 * it can only do so after the child has exited, and it's the caller of
107 * this function that does the wait() call. */
108 static struct lockfile *lockfile;
ac718c9d
BP
109
110 assert(lockfile_lock("file", 0, &lockfile) == 0);
111 if (do_fork() == CHILD) {
93ff0290 112 lockfile_unlock(lockfile);
ac718c9d
BP
113 assert(lockfile_lock("file", 0, &lockfile) == EAGAIN);
114 exit(11);
115 }
116}
117
118static void
119run_lock_twice_blocks_other_process(void)
120{
121 struct lockfile *lockfile, *dummy;
122
123 assert(lockfile_lock("file", 0, &lockfile) == 0);
124 assert(lockfile_lock("file", 0, &dummy) == EDEADLK);
125 if (do_fork() == CHILD) {
126 assert(lockfile_lock("file", 0, &dummy) == EAGAIN);
127 exit(11);
128 }
129}
130
131static void
132run_lock_and_unlock_allows_other_process(void)
133{
134 struct lockfile *lockfile;
135
136 assert(lockfile_lock("file", 0, &lockfile) == 0);
137 lockfile_unlock(lockfile);
138
139 if (do_fork() == CHILD) {
140 assert(lockfile_lock("file", 0, &lockfile) == 0);
141 exit(11);
142 }
143}
144
145static void
146run_lock_timeout_gets_the_lock(void)
147{
148 struct lockfile *lockfile;
149
150 assert(lockfile_lock("file", 0, &lockfile) == 0);
151
152 if (do_fork() == CHILD) {
93ff0290 153 lockfile_unlock(lockfile);
ac718c9d
BP
154 assert(lockfile_lock("file", TIME_UPDATE_INTERVAL * 3,
155 &lockfile) == 0);
156 exit(11);
157 } else {
158 long long int now = time_msec();
159 while (time_msec() < now + TIME_UPDATE_INTERVAL) {
160 pause();
161 }
162 lockfile_unlock(lockfile);
163 }
164}
165
166static void
167run_lock_timeout_runs_out(void)
168{
169 struct lockfile *lockfile;
170
171 assert(lockfile_lock("file", 0, &lockfile) == 0);
172
173 if (do_fork() == CHILD) {
93ff0290 174 lockfile_unlock(lockfile);
ac718c9d
BP
175 assert(lockfile_lock("file", TIME_UPDATE_INTERVAL,
176 &lockfile) == ETIMEDOUT);
177 exit(11);
178 } else {
179 long long int now = time_msec();
180 while (time_msec() < now + TIME_UPDATE_INTERVAL * 3) {
181 pause();
182 }
183 lockfile_unlock(lockfile);
184 }
185}
186
187static void
188run_lock_multiple(void)
189{
190 struct lockfile *a, *b, *c, *dummy;
191
192 assert(lockfile_lock("a", 0, &a) == 0);
193 assert(lockfile_lock("b", 0, &b) == 0);
194 assert(lockfile_lock("c", 0, &c) == 0);
195
196 lockfile_unlock(a);
197 assert(lockfile_lock("a", 0, &a) == 0);
198 assert(lockfile_lock("a", 0, &dummy) == EDEADLK);
199 lockfile_unlock(a);
200
201 lockfile_unlock(b);
202 assert(lockfile_lock("a", 0, &a) == 0);
203
204 lockfile_unlock(c);
205 lockfile_unlock(a);
206}
207
208static void
209run_help(void)
210{
211 size_t i;
212
213 printf("usage: %s TESTNAME\n"
214 "where TESTNAME is one of the following:\n",
215 program_name);
216 for (i = 0; tests[i].name; i++) {
217 fprintf(stderr, "\t%s\n", tests[i].name);
218 }
219}
220
221static const struct test tests[] = {
222#define TEST(NAME) { #NAME, run_##NAME }
223 TEST(lock_and_unlock),
224 TEST(lock_and_unlock_twice),
225 TEST(lock_blocks_same_process),
226 TEST(lock_blocks_same_process_twice),
227 TEST(lock_blocks_other_process),
228 TEST(lock_twice_blocks_other_process),
229 TEST(lock_and_unlock_allows_other_process),
230 TEST(lock_timeout_gets_the_lock),
231 TEST(lock_timeout_runs_out),
232 TEST(lock_multiple),
233 TEST(help),
234 { 0, 0 }
235#undef TEST
236};
237
238int
239main(int argc, char *argv[])
240{
480ce8ab 241 extern struct vlog_module VLM_lockfile;
ac718c9d
BP
242 size_t i;
243
244 set_program_name(argv[0]);
480ce8ab 245 vlog_set_levels(&VLM_lockfile, VLF_ANY_FACILITY, VLL_ERR);
ac718c9d
BP
246
247 if (argc != 2) {
248 ovs_fatal(0, "exactly one argument required; use \"%s help\" for help",
249 program_name);
250 return 1;
251 }
252
253 for (i = 0; tests[i].name; i++) {
254 if (!strcmp(argv[1], tests[i].name)) {
255 int n_children;
256 int status;
257
258 (tests[i].function)();
259
260 n_children = 0;
261 while (wait(&status) > 0) {
262 if (WIFEXITED(status) && WEXITSTATUS(status) == 11) {
263 n_children++;
264 } else {
265 ovs_fatal(0, "child exited in unexpected way: %s",
266 process_status_msg(status));
267 }
268 }
269 if (errno != ECHILD) {
270 ovs_fatal(errno, "wait");
271 }
272
273 printf("%s: success (%d child%s)\n",
274 tests[i].name, n_children, n_children != 1 ? "ren" : "");
275 exit(0);
276 }
277 }
278 ovs_fatal(0, "unknown test \"%s\"; use \"%s help\" for help",
279 argv[1], program_name);
280}
281