4 Copyright (C) Andrew Tridgell 2006
6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2 of the License, or (at your option) any later version.
11 This library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public
17 License along with this library; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 #include "lib/events/events.h"
23 #include "system/filesys.h"
24 #include "system/wait.h"
29 struct lockwait_handle {
34 void (*callback)(void *);
37 static void lockwait_handler(struct event_context *ev, struct fd_event *fde,
38 uint16_t flags, void *private_data)
40 struct lockwait_handle *h = talloc_get_type(private_data,
41 struct lockwait_handle);
42 void (*callback)(void *) = h->callback;
43 void *p = h->private_data;
44 talloc_set_destructor(h, NULL);
48 waitpid(h->child, NULL, 0);
51 static int lockwait_destructor(struct lockwait_handle *h)
54 kill(h->child, SIGKILL);
55 waitpid(h->child, NULL, 0);
60 static struct lockwait_handle *lockwait(struct event_context *ev,
62 int fd, off_t ofs, size_t len,
63 void (*callback)(void *), void *private_data)
65 struct lockwait_handle *h;
68 h = talloc_zero(mem_ctx, struct lockwait_handle);
80 if (h->child == (pid_t)-1) {
87 h->callback = callback;
88 h->private_data = private_data;
94 lock.l_type = F_WRLCK;
95 lock.l_whence = SEEK_SET;
99 fcntl(fd,F_SETLKW,&lock);
104 talloc_set_destructor(h, lockwait_destructor);
106 h->fde = event_add_fd(ev, h, h->fd[0], EVENT_FD_READ, lockwait_handler, h);
107 if (h->fde == NULL) {
118 static void fcntl_lock_callback(void *p)
120 int *got_lock = (int *)p;
125 get an fcntl lock - waiting if necessary
127 static int fcntl_lock(struct event_context *ev,
128 int fd, int op, off_t offset, off_t count, int type)
132 int use_lockwait = (op == F_SETLKW);
136 lock.l_whence = SEEK_SET;
137 lock.l_start = offset;
142 ret = fcntl(fd,use_lockwait?F_SETLK:op,&lock);
147 (errno == EACCES || errno == EAGAIN || errno == EDEADLK)) {
148 struct lockwait_handle *h;
149 h = lockwait(ev, ev, fd, offset, count,
150 fcntl_lock_callback, &got_lock);
155 /* in real code we would return to the event loop */
166 static void child(struct event_context *ev, int n)
171 fd = open("test.dat", O_CREAT|O_RDWR, 0666);
177 tv = timeval_current();
179 while (timeval_elapsed(&tv) < 10) {
181 ret = fcntl_lock(ev, fd, F_SETLKW, 0, 1, F_WRLCK);
183 printf("Failed to get lock in child %d!\n", n);
186 fcntl_lock(ev, fd, F_SETLK, 0, 1, F_UNLCK);
190 printf("child %2d %.0f ops/sec\n", n, count/timeval_elapsed(&tv));
194 static int timelimit = 10;
199 int main(int argc, const char *argv[])
204 struct event_context *ev;
205 struct poptOption popt_options[] = {
207 { "timelimit", 't', POPT_ARG_INT, &timelimit, 0, "timelimit", "integer" },
208 { "num-progs", 'n', POPT_ARG_INT, &nprogs, 0, "num_progs", "integer" },
214 pc = poptGetContext(argv[0], argc, argv, popt_options, POPT_CONTEXT_KEEP_FIRST);
216 while ((opt = poptGetNextOpt(pc)) != -1) {
219 fprintf(stderr, "Invalid option %s: %s\n",
220 poptBadOption(pc, 0), poptStrerror(opt));
225 ev = event_context_init(NULL);
227 pids = talloc_array(ev, pid_t, nprogs);
229 /* create N processes fighting over the same lock */
230 for (i=0;i<nprogs;i++) {
237 printf("Waiting for %d children ...\n", nprogs);
239 /* wait for our kids to finish playing */
240 for (i=0;i<nprogs;i++) {
241 waitpid(pids[i], NULL, 0);