1 /* Demonstrate starvation of tdb_lockall */
2 #include <ccan/tdb/tdb.h>
14 static void usage(const char *extra)
17 "Usage: starvation [lockall|gradual] <num> <worktime-in-ms>\n"
18 " Each locker holds lock for between 1/2 and 1 1/2 times\n"
19 " worktime, then sleeps for one second.\n\n"
20 " Main process tries tdb_lockall or tdb_lockall_gradual.",
21 extra ? extra : "", extra ? "\n" : "");
24 static void run_and_sleep(struct tdb_context *tdb, int parentfd, unsigned time)
28 unsigned rand, randtime;
31 key.dptr = (void *)&rand;
32 key.dsize = sizeof(rand);
34 while (read(parentfd, &c, 1) != 0) {
35 /* Lock a random key. */
37 if (tdb_chainlock(tdb, key) != 0)
38 errx(1, "chainlock failed: %s", tdb_errorstr(tdb));
40 /* Hold it for some variable time. */
41 randtime = time / 2 + (random() % time);
42 hold.tv_sec = randtime / 1000;
43 hold.tv_nsec = (randtime % 1000) * 1000000;
44 nanosleep(&hold, NULL);
46 if (tdb_chainunlock(tdb, key) != 0)
47 errx(1, "chainunlock failed: %s", tdb_errorstr(tdb));
49 /* Wait for a second without the lock. */
55 static void logfn(struct tdb_context *tdb,
56 enum tdb_debug_level level,
62 vfprintf(stderr, fmt, ap);
66 int main(int argc, char *argv[])
68 int (*lockall)(struct tdb_context *);
69 unsigned int num, worktime, i;
71 struct tdb_context *tdb;
72 struct tdb_logging_context log = { logfn, NULL };
73 struct timeval start, end, duration;
78 if (strcmp(argv[1], "lockall") == 0)
79 lockall = tdb_lockall;
80 else if (strcmp(argv[1], "gradual") == 0) {
82 lockall = tdb_lockall_gradual;
84 errx(1, "gradual is now the default implementation");
87 usage("Arg1 should be 'lockall' or 'gradual'");
90 worktime = atoi(argv[3]);
92 if (!num || !worktime)
93 usage("Number of threads and worktime must be non-zero");
96 err(1, "Creating pipe");
98 tdb = tdb_open_ex("/tmp/starvation.tdb", 10000, TDB_DEFAULT,
99 O_RDWR|O_CREAT|O_TRUNC, 0600, &log, NULL);
101 err(1, "Opening tdb /tmp/starvation.tdb");
103 for (i = 0; i < num; i++) {
107 fcntl(pfd[0], F_SETFL,
108 fcntl(pfd[0], F_GETFL)|O_NONBLOCK);
109 srandom(getpid() + i);
110 if (tdb_reopen(tdb) != 0)
111 err(1, "Reopening tdb %s", tdb_name(tdb));
113 run_and_sleep(tdb, pfd[0], worktime);
117 /* Stagger the children. */
118 usleep(random() % (1000000 / num));
123 gettimeofday(&start, NULL);
124 if (lockall(tdb) != 0)
125 errx(1, "lockall failed: %s", tdb_errorstr(tdb));
126 gettimeofday(&end, NULL);
128 duration.tv_sec = end.tv_sec - start.tv_sec;
129 duration.tv_usec = end.tv_usec - start.tv_usec;
130 if (duration.tv_usec < 0) {
132 duration.tv_usec += 1000000;
135 if (tdb_unlockall(tdb) != 0)
136 errx(1, "unlockall failed: %s", tdb_errorstr(tdb));
138 unlink("/tmp/starvation.tdb");
140 printf("Took %lu.%06lu seconds\n", duration.tv_sec, duration.tv_usec);