xref: /dragonfly/test/lockf/lockf.c (revision abf903a5)
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 }
195