2 * Copyright Rusty Russell, 2013, IBM Corporation
3 * Copyright Jeff Layton, 2013
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 3 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, see
17 * <http://www.gnu.org/licenses/>.
22 #endif /* HAVE_CONFIG_H */
28 #include <sys/types.h>
36 #include <sys/resource.h>
42 #define DEFAULT_PROCESSES 5000
43 #define DEFAULT_ITERATIONS 100
45 /* Taken from TDB: LGPLv3 */
46 static int fcntl_lock(int fd, int rw, off_t off, off_t len, bool waitflag)
51 fl.l_whence = SEEK_SET;
57 return fcntl(fd, F_SETLKW, &fl);
59 return fcntl(fd, F_SETLK, &fl);
62 static int fcntl_unlock(int fd, off_t off, off_t len)
66 fl.l_whence = SEEK_SET;
71 return fcntl(fd, F_SETLKW, &fl);
79 signal(SIGINT, SIG_IGN);
81 while (waitid(P_ALL, 0, &infop, WEXITED) != -1);
85 sighandler(int sig __attribute__((unused)))
91 static int do_child(int lockfd, int i, int to_lockers, int from_lockers)
95 while (read(to_lockers, &c, 1) == 1) {
98 if (fcntl_lock(lockfd, F_WRLCK, i, 1, true) != 0)
100 /* Tell parent we got it! */
101 if (write(from_lockers, &c, 1) != 1)
102 err(1, "Writing to parent");
104 fcntl_unlock(lockfd, i, 1);
112 errx(1, "Usage: %s [-i iterations] [-n nr_children] <filename>", argv0);
115 int main(int argc, char *argv[])
117 int num = DEFAULT_PROCESSES, i, opt;
118 int iter = DEFAULT_ITERATIONS;
119 const char *lockfile;
121 int lockfd, to_lockers[2], from_lockers[2];
122 struct timespec start, end;
123 struct timespec total;
129 while ((opt = getopt(argc, argv, "i:n:")) != -1) {
142 lockfile = argv[optind];
147 if (getrlimit(RLIMIT_NPROC, &rlim))
149 rlim.rlim_cur = rlim.rlim_max;
150 if (setrlimit(RLIMIT_NPROC, &rlim))
153 if (pipe(to_lockers))
154 err(1, "pipe (to_lockers)");
155 if (pipe(from_lockers))
156 err(1, "pipe (from_lockers)");
158 lockfd = open(lockfile, O_CREAT|O_RDWR, 0644);
160 err(1, "Opening %s", lockfile);
162 signal(SIGINT, sighandler);
164 for (i = 0; i < num; i++) {
167 signal(SIGINT, SIG_DFL);
168 return do_child(lockfd, i, to_lockers[0], from_lockers[1]);
170 err(1, "fork failed");
174 close(to_lockers[0]);
175 close(from_lockers[1]);
177 fill = calloc(num, 1);
180 if (fcntl_lock(lockfd, F_WRLCK, 0, num, true) != 0)
181 err(1, "Locking %u bytes in %s", num, lockfile);
183 /* OK, now wake all the kids: they block on lock. */
186 int ret = write(to_lockers[1], fill + i, num - i);
189 err(1, "writing to wake up locker children");
195 if (clock_gettime(CLOCK_MONOTONIC_RAW, &start))
196 err(1, "Getting start time");
198 fcntl_unlock(lockfd, 0, num);
199 for (i = 0; i < num; i++)
200 if (read(from_lockers[0], fill, 1) != 1)
201 err(1, "Reading from locker children");
203 if (clock_gettime(CLOCK_MONOTONIC_RAW, &end))
204 err(1, "Getting start time");
206 total = timespec_add(total, timespec_sub(end, start));
209 printf("%ld.%09ld\n", total.tv_sec, total.tv_nsec);