tdb: new test, cleanup old tests by centralizing lock tracking.
[ccan] / ccan / tdb / test / lock-tracking.c
1 /* We save the locks so we can reaquire them. */
2 #include <unistd.h>
3 #include <fcntl.h>
4 #include <stdarg.h>
5 #include <stdlib.h>
6 #include <ccan/tap/tap.h>
7
8 struct lock {
9         struct lock *next;
10         unsigned int off;
11         unsigned int len;
12         int type;
13 };
14 static struct lock *locks;
15 int locking_errors = 0;
16 void (*unlock_callback)(int fd);
17
18 int fcntl_with_lockcheck(int fd, int cmd, ... /* arg */ )
19 {
20         va_list ap;
21         int ret, arg3;
22         struct flock *fl;
23
24         if (cmd != F_SETLK && cmd != F_SETLKW) {
25                 /* This may be totally bogus, but we don't know in general. */
26                 va_start(ap, cmd);
27                 arg3 = va_arg(ap, int);
28                 va_end(ap);
29
30                 return fcntl(fd, cmd, arg3);
31         }
32
33         va_start(ap, cmd);
34         fl = va_arg(ap, struct flock *);
35         va_end(ap);
36
37         if (fl->l_type == F_UNLCK) {
38                 struct lock **l;
39                 struct lock *old = NULL;
40                         
41                 for (l = &locks; *l; l = &(*l)->next) {
42                         if ((*l)->off == fl->l_start
43                             && (*l)->len == fl->l_len) {
44                                 old = *l;
45                                 *l = (*l)->next;
46                                 free(old);
47                                 break;
48                         }
49                 }
50                 if (!old) {
51                         diag("Unknown unlock %u@%u",
52                              (int)fl->l_len, (int)fl->l_start);
53                         locking_errors++;
54                 }
55         } else {
56                 struct lock *new, *i;
57                 unsigned int fl_end = fl->l_start + fl->l_len;
58                 if (fl->l_len == 0)
59                         fl_end = (unsigned int)-1;
60
61                 /* Check for overlaps: we shouldn't do this. */
62                 for (i = locks; i; i = i->next) {
63                         unsigned int i_end = i->off + i->len;
64                         if (i->len == 0)
65                                 i_end = (unsigned int)-1;
66
67                         if (fl->l_start >= i->off && fl->l_start < i_end)
68                                 break;
69                         if (fl_end >= i->off && fl_end < i_end)
70                                 break;
71                 }
72                 if (i) {
73                         diag("%s lock %u@%u overlaps %u@%u",
74                              fl->l_type == F_WRLCK ? "write" : "read",
75                              (int)fl->l_len, (int)fl->l_start,
76                              i->len, (int)i->off);
77                         locking_errors++;
78                 }
79                 new = malloc(sizeof *new);
80                 new->off = fl->l_start;
81                 new->len = fl->l_len;
82                 new->type = fl->l_type;
83                 new->next = locks;
84                 locks = new;
85         }
86
87         ret = fcntl(fd, cmd, fl);
88         if (ret == 0 && fl->l_type == F_UNLCK && unlock_callback)
89                 unlock_callback(fd);
90         return ret;
91 }
92
93 int forget_locking(void)
94 {
95         unsigned int num = 0;
96         while (locks) {
97                 struct lock *next = locks->next;
98                 free(locks);
99                 locks = next;
100                 num++;
101         }
102         return num;
103 }