1 /* $NetBSD: t_lockf.c,v 1.9 2013/10/19 17:45:00 christos Exp $ */
4 * Copyright (c) 2000 The NetBSD Foundation, Inc.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
17 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
39 #include <sys/types.h>
41 #include <sys/ptrace.h>
44 * lockf1 regression test:
47 * Fork N child processes, each of which gets M random byte range locks
48 * on a common file. We ignore all lock errors (practically speaking,
49 * this means EDEADLK or ENOLOCK), but we make numerous passes over all
50 * the children to make sure that they are still awake. (We do this by
51 * verifying that we can ptrace(ATTACH/DETACH) to the children and get
52 * their status via waitpid().)
53 * When finished, reap all the children.
56 #define nlocks 500 /* number of locks per thread */
57 #define nprocs 10 /* number of processes to spawn */
58 #define npasses 50 /* number of passes to make over the children */
59 #define sleeptime 150000 /* sleep time between locks, usec */
60 #define filesize 8192 /* size of file to lock */
62 const char *lockfile
= "lockf_test";
77 fd
= open (lockfile
, O_RDWR
, 0);
80 err(1, "%s", lockfile
);
82 printf("%d: start\n", id
);
84 for (i
= 0; i
< nlocks
; i
++) {
87 fl
.l_start
= random_uint32() % filesize
;
88 fl
.l_len
= random_uint32() % filesize
;
89 switch (random_uint32() % 3) {
100 fl
.l_whence
= SEEK_SET
;
102 (void)fcntl(fd
, F_SETLKW
, &fl
);
104 if (usleep(sleeptime
) < 0)
107 printf("%d: done\n", id
);
112 ATF_TC_HEAD(randlock
, tc
)
115 atf_tc_set_md_var(tc
, "timeout", "300");
116 atf_tc_set_md_var(tc
, "descr", "Checks fcntl(2) locking");
119 ATF_TC_BODY(randlock
, tc
)
125 char pipe_in
, pipe_out
;
126 const char pipe_errmsg
[] = "child: pipe write failed\n";
128 (void)unlink(lockfile
);
130 fd
= open (lockfile
, O_RDWR
|O_CREAT
|O_EXCL
|O_TRUNC
, 0666);
131 ATF_REQUIRE_MSG(fd
>= 0, "open(%s): %s", lockfile
, strerror(errno
));
133 ATF_REQUIRE_MSG(ftruncate(fd
, filesize
) >= 0,
134 "ftruncate(%s): %s", lockfile
, strerror(errno
));
136 ATF_REQUIRE_MSG(pipe(pipe_fd
) == 0, "pipe: %s", strerror(errno
));
141 pid
= malloc(nprocs
* sizeof(pid_t
));
143 for (i
= 0; i
< nprocs
; i
++) {
144 pipe_out
= (char)('A' + i
);
148 if (write(pipe_fd
[1], &pipe_out
, 1) != 1)
149 write(STDERR_FILENO
, pipe_errmsg
,
150 __arraycount(pipe_errmsg
) - 1);
156 atf_tc_fail("fork %d failed", i
);
159 ATF_REQUIRE_MSG(read(pipe_fd
[0], &pipe_in
, 1) == 1,
160 "parent: read_pipe(%i): %s", i
, strerror(errno
));
161 ATF_REQUIRE_MSG(pipe_in
== pipe_out
,
162 "parent: pipe does not match");
166 for (j
= 0; j
< npasses
; j
++) {
167 printf("parent: run %i\n", j
+1);
168 for (i
= 0; i
< nprocs
; i
++) {
169 ATF_REQUIRE_MSG(ptrace(PT_ATTACH
, pid
[i
], 0, 0) >= 0,
170 "ptrace attach %d", pid
[i
]);
171 ATF_REQUIRE_MSG(waitpid(pid
[i
], &status
, WUNTRACED
) >= 0,
173 usleep(sleeptime
/ 3);
174 ATF_REQUIRE_MSG(ptrace(PT_DETACH
, pid
[i
], (caddr_t
)1,
176 "ptrace detach %d", pid
[i
]);
177 usleep(sleeptime
/ 3);
180 for (i
= 0; i
< nprocs
; i
++) {
181 printf("reap %d: ", i
);
183 kill(pid
[i
], SIGINT
);
184 waitpid(pid
[i
], &status
, 0);
185 printf(" status %d\n", status
);
191 dolock(int fd
, int op
, off_t lk_off
, off_t lk_size
)
196 result
= lseek(fd
, lk_off
, SEEK_SET
);
200 ATF_REQUIRE_MSG(result
== lk_off
, "lseek to wrong offset");
201 ret
= lockf(fd
, op
, lk_size
);
209 ATF_TC_HEAD(deadlock
, tc
)
212 atf_tc_set_md_var(tc
, "timeout", "30");
213 atf_tc_set_md_var(tc
, "descr", "Checks fcntl(2) deadlock detection");
216 ATF_TC_BODY(deadlock
, tc
)
223 (void)unlink(lockfile
);
225 fd
= open (lockfile
, O_RDWR
|O_CREAT
|O_EXCL
|O_TRUNC
, 0666);
226 ATF_REQUIRE_MSG(fd
>= 0, "open(%s): %s", lockfile
, strerror(errno
));
228 ATF_REQUIRE_MSG(ftruncate(fd
, filesize
) >= 0,
229 "ftruncate(%s): %s", lockfile
, strerror(errno
));
233 error
= dolock(fd
, F_LOCK
, 0, 1);
234 ATF_REQUIRE_MSG(error
== 0, "initial dolock: %s", strerror(errno
));
237 ATF_REQUIRE_MSG(pid
!= -1, "fork failed: %s", strerror(errno
));
239 error
= dolock(fd
, F_LOCK
, 1, 1);
240 ATF_REQUIRE_MSG(error
== 0, "child dolock: %s",
242 dolock(fd
, F_LOCK
, 0, 1); /* will block */
243 atf_tc_fail("child did not block");
245 sleep(1); /* give child time to grab its lock then block */
247 error
= dolock(fd
, F_LOCK
, 1, 1);
248 ATF_REQUIRE_MSG(error
== EDEADLK
, "parent did not detect deadlock: %s",
250 ret
= kill(pid
, SIGKILL
);
251 ATF_REQUIRE_MSG(ret
!= -1, "failed to kill child: %s", strerror(errno
));
258 ATF_TP_ADD_TC(tp
, randlock
);
259 ATF_TP_ADD_TC(tp
, deadlock
);
261 return atf_no_error();