Merge branch 'vendor/LIBEDIT'
[dragonfly.git] / test / lockf / lockf.c
1 /*      $NetBSD: lockf.c,v 1.4 2000/07/30 09:16:06 jdolecek Exp $       */
2 /* $DragonFly: src/test/lockf/lockf.c,v 1.1 2004/05/11 08:03:57 joerg Exp $ */
3
4 /*-
5  * Copyright (c) 2000 The NetBSD Foundation, Inc.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. All advertising materials mentioning features or use of this software
17  *    must display the following acknowledgement:
18  *      This product includes software developed by the NetBSD
19  *      Foundation, Inc. and its contributors.
20  * 4. Neither the name of The NetBSD Foundation nor the names of its
21  *    contributors may be used to endorse or promote products derived
22  *    from this software without specific prior written permission.
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
25  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
26  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
27  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
28  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
29  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
30  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
31  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
32  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
33  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34  * POSSIBILITY OF SUCH DAMAGE.
35  */
36
37 /*
38  * lockf regression test:
39  *
40  * Tests:
41  * 1) fork N child processes, do a bunch of random byte range lock/unlock.
42  */
43
44 #include <sys/types.h>
45 #include <sys/wait.h>
46 #include <sys/ptrace.h> 
47
48 #include <unistd.h>
49 #include <fcntl.h>
50 #include <stdio.h>
51 #include <stdlib.h>
52 #include <err.h>
53 #include <signal.h>
54 #include <errno.h>
55
56 int nlocks = 10000;                     /* number of locks per thread */
57 int nprocs = 100;               /* number of processes to spawn */
58 int sleeptime = 50000;          /* sleep time between locks, usec */
59 off_t size = 65536;             /* size of file to lock */
60 const char *lockfile = "/tmp/lockf_test";
61
62 static uint32_t
63 random_uint32(void)
64 {
65         return lrand48();
66 }
67
68
69 static void
70 trylocks(int id)
71 {
72         int i, ret, fd;
73         int uids[3];
74         const char *which;
75
76         uids[0] = -1;
77         uids[1] = getuid();
78         uids[2] = geteuid();
79         srand48(getpid());
80
81         fd = open (lockfile, O_RDWR, 0);
82         
83         if (fd < 0)
84                 err(1, lockfile);
85         
86         printf("%d: start\n", id);
87         
88         for (i=0; i<nlocks; i++) {
89                 struct flock fl;
90                 ret = random_uint32() % 3;
91                 if (uids[ret] != -1) {
92                         printf("switching to uid %d\n", uids[ret]);
93                         setuid(uids[ret]);
94                 }
95
96                 fl.l_start = random_uint32() % size;
97                 fl.l_len = random_uint32() % size;
98                 switch (random_uint32() % 3) {
99                 case 0:
100                         which = "read";
101                         fl.l_type = F_RDLCK;
102                         break;
103                 case 1:
104                         which = "write";
105                         fl.l_type = F_WRLCK;
106                         break;
107                 case 2:
108                         which = "un";
109                         fl.l_type = F_UNLCK;
110                         break;
111                 }
112                 fl.l_whence = SEEK_SET;
113
114                 printf("%d: try %slock %d to %d\n", id, which, (int)fl.l_start,
115                     (int)(fl.l_start + fl.l_len));
116                 
117                 ret = fcntl(fd, F_SETLKW, &fl);
118
119                 if (ret < 0)
120                         perror("fcntl");
121                 printf("%d: got %slock %d to %d\n", id, which, (int)fl.l_start,
122                     ((int)(fl.l_start + fl.l_len)));
123                 
124                 if (usleep(sleeptime) < 0) 
125                   err(1, "usleep");
126         }
127         printf("%d: done\n", id);
128         close (fd);
129 }
130
131 /* ARGSUSED */
132 int
133 main(int argc, char **argv)
134 {
135         int i, j;
136         pid_t *pid;
137         int status;
138         int fd;
139         
140         unlink(lockfile);
141
142         fd = open (lockfile, O_RDWR|O_CREAT|O_EXCL|O_TRUNC, 0666);
143         if (fd < 0)
144                 err(1, "%s", lockfile);
145
146         if (ftruncate(fd, size) < 0)
147                 err(1, "ftruncate of %s failed", lockfile);
148
149         fsync(fd);
150         close(fd);
151         
152         pid = malloc(nprocs * sizeof(pid_t));
153         
154         for (i=0; i<nprocs; i++) {
155                 pid[i] = fork();
156                 switch (pid[i]) {
157                 case 0:
158                         trylocks(i);
159                         _exit(0);
160                         break;
161                 case -1:
162                         err(1, "fork failed");
163                         break;
164                 default:
165                         break;
166                 }
167         }
168         for (j=0; j<100; j++) {
169                 printf("parent: run %i\n", j+1);
170                 for (i=0; i<nprocs; i++) {
171                         printf("stop %d\n", i);
172                         if (ptrace(PT_ATTACH, pid[i], 0, 0) < 0)
173                                 err(1, "ptrace attach %d", pid[i]);
174                         printf("wait %d\n", i);
175                         if (waitpid(pid[i], &status, WUNTRACED) < 0)
176                                 err(1, "waitpid(ptrace)");
177                         printf("awake %d\n", i);
178                         usleep(sleeptime/3);
179                         if (ptrace(PT_DETACH, pid[i], (caddr_t)1, 0) < 0)
180                                 err(1, "ptrace detach %d", pid[i]);
181                         printf("done %d\n", i);
182                         usleep(sleeptime/3);
183                 }
184         }
185         for (i=0; i<nprocs; i++) {
186                 printf("reap %d: ", i);
187                 fflush(stdout);
188                 kill(pid[i], SIGINT);
189                 waitpid(pid[i], &status, 0);
190                 printf(" status %d\n", status);
191         }
192         exit(0);
193         /* NOTREACHED */
194 }