nrelease: Clean up a bit the 'clean' target
[dragonfly.git] / test / testcases / posixipc / common / common.c
blobd806b2b2967fc692f00349df7ca0c267cbd6cacd
1 /*-
2 * Copyright (c) 2008 Yahoo!, Inc.
3 * All rights reserved.
4 * Written by: John Baldwin <jhb@FreeBSD.org>
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. Neither the name of the author nor the names of any co-contributors
15 * may be used to endorse or promote products derived from this software
16 * without specific prior written permission.
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
31 #include <sys/cdefs.h>
32 #include <sys/mman.h>
33 #include <sys/queue.h>
34 #include <sys/sysctl.h>
35 #include <sys/time.h>
36 #include <sys/types.h>
37 #include <sys/user.h>
38 #include <sys/wait.h>
40 #include <errno.h>
41 #include <kvm.h>
42 #include <limits.h>
43 #include <signal.h>
44 #include <stdio.h>
45 #include <time.h>
47 #include <common.h>
50 * Use a timer to post a specific semaphore after a timeout. A timer
51 * is scheduled via schedule_post(). check_alarm() must be called
52 * afterwards to clean up and check for errors.
54 sem_t *alarm_id = SEM_FAILED;
55 int alarm_errno;
56 int alarm_handler_installed;
58 int
59 checkvalue(sem_t *id, int expected)
61 int val;
63 if (sem_getvalue(id, &val) < 0) {
64 perror("sem_getvalue");
65 return (-1);
67 if (val != expected) {
68 fprintf(stderr, "sem value should be %d instead of %d",
69 expected, val);
70 return (-1);
72 return (0);
75 sem_t *
76 construct_shared_unnamed_sem(unsigned int count)
78 sem_t *id = mmap(NULL, sizeof(sem_t), PROT_READ|PROT_WRITE,
79 MAP_SHARED|MAP_ANON, -1, 0);
80 if (id == MAP_FAILED) {
81 perror("mmap");
82 return SEM_FAILED;
85 if (sem_init(id, 1, count) < 0) {
86 perror("sem_init");
87 munmap(id, sizeof(sem_t));
88 return SEM_FAILED;
91 return id;
94 void
95 destruct_shared_unnamed_sem(sem_t *id)
97 if (sem_destroy(id) < 0)
98 perror("sem_destroy");
100 if (munmap(id, sizeof(sem_t)) < 0)
101 perror("munmap");
105 testwait(sem_t *id, u_int *delta)
107 struct timespec start, end;
109 if (clock_gettime(CLOCK_REALTIME, &start) < 0) {
110 perror("clock_gettime(CLOCK_REALTIME)");
111 return (-1);
113 if (sem_wait(id) < 0) {
114 perror("sem_wait");
115 return (-1);
117 if (clock_gettime(CLOCK_REALTIME, &end) < 0) {
118 perror("clock_gettime(CLOCK_REALTIME)");
119 return (-1);
121 timespecsub(&end, &start, &end);
122 *delta = end.tv_nsec / 1000000;
123 *delta += end.tv_sec * 1000;
124 return (0);
127 static void
128 alarm_handler(int signo)
131 if (sem_post(alarm_id) < 0)
132 alarm_errno = errno;
136 schedule_post(sem_t *id, u_int msec)
138 struct itimerval it;
140 if (!alarm_handler_installed) {
141 if (signal(SIGALRM, alarm_handler) == SIG_ERR) {
142 perror("signal(SIGALRM)");
143 return (-1);
145 alarm_handler_installed = 1;
147 if (alarm_id != SEM_FAILED) {
148 fprintf(stderr, "sem_post() already scheduled");
149 return (-1);
151 alarm_id = id;
152 bzero(&it, sizeof(it));
153 it.it_value.tv_sec = msec / 1000;
154 it.it_value.tv_usec = (msec % 1000) * 1000;
155 if (setitimer(ITIMER_REAL, &it, NULL) < 0) {
156 perror("setitimer");
157 return (-1);
159 return (0);
163 check_alarm(int just_clear)
165 struct itimerval it;
167 bzero(&it, sizeof(it));
168 if (just_clear) {
169 setitimer(ITIMER_REAL, &it, NULL);
170 alarm_errno = 0;
171 alarm_id = SEM_FAILED;
172 return (0);
174 if (setitimer(ITIMER_REAL, &it, NULL) < 0) {
175 perror("setitimer");
176 return (-1);
178 if (alarm_errno != 0 && !just_clear) {
179 errno = alarm_errno;
180 perror("sem_post() (via timeout)");
181 alarm_errno = 0;
182 return (-1);
184 alarm_id = SEM_FAILED;
186 return (0);
190 * Helper routine for tests that use a child process. This routine
191 * creates a pipe and forks a child process. The child process runs
192 * the 'func' routine which returns a status integer. The status
193 * integer gets written over the pipe to the parent and returned in
194 * '*stat'. If there is an error in pipe(), fork(), or wait() this
195 * returns -1 and fails the test.
198 child_worker(int (*func)(void *arg), void *arg, int *stat)
200 pid_t pid;
201 int pfd[2], cstat;
203 if (pipe(pfd) < 0) {
204 perror("pipe");
205 return (-1);
208 pid = fork();
209 switch (pid) {
210 case -1:
211 /* Error. */
212 perror("fork");
213 close(pfd[0]);
214 close(pfd[1]);
215 return (-1);
216 case 0:
217 /* Child. */
218 cstat = func(arg);
219 write(pfd[1], &cstat, sizeof(cstat));
220 exit(0);
223 if (read(pfd[0], stat, sizeof(*stat)) < 0) {
224 perror("read(pipe)");
225 close(pfd[0]);
226 close(pfd[1]);
227 return (-1);
229 if (waitpid(pid, NULL, 0) < 0) {
230 perror("wait");
231 close(pfd[0]);
232 close(pfd[1]);
233 return (-1);
235 close(pfd[0]);
236 close(pfd[1]);
237 return (0);
241 * Fork off a child process. The child will open the semaphore via
242 * the same name. The child will then block on the semaphore waiting
243 * for the parent to post it.
246 wait_twoproc_child(void *arg)
248 sem_t *id;
250 id = sem_open(TEST_PATH, 0, 0, 0);
251 if (id == SEM_FAILED)
252 return (CSTAT(1, errno));
253 if (sem_wait(id) < 0)
254 return (CSTAT(2, errno));
255 if (sem_close(id) < 0)
256 return (CSTAT(3, errno));
257 return (CSTAT(0, 0));
261 timedwait(sem_t *id, u_int msec, u_int *delta, int error)
263 struct timespec start, end;
265 if (clock_gettime(CLOCK_REALTIME, &start) < 0) {
266 perror("clock_gettime(CLOCK_REALTIME)");
267 return (-1);
269 end.tv_sec = msec / 1000;
270 end.tv_nsec = msec % 1000 * 1000000;
271 timespecadd(&end, &start, &end);
272 if (sem_timedwait(id, &end) < 0) {
273 if (errno != error) {
274 perror("sem_timedwait");
275 return (-1);
277 } else if (error != 0) {
278 return (-1);
280 if (clock_gettime(CLOCK_REALTIME, &end) < 0) {
281 perror("clock_gettime(CLOCK_REALTIME)");
282 return (-1);
284 timespecsub(&end, &start, &end);
285 *delta = end.tv_nsec / 1000000;
286 *delta += end.tv_sec * 1000;
287 return (0);
291 * Attempt a sem_open() that should fail with an expected error of
292 * 'error'.
295 sem_open_should_fail(const char *path, int flags, mode_t mode,
296 unsigned int value, int error)
298 int retval = 0;
299 sem_t *id;
301 id = sem_open(path, flags, mode, value);
302 if (id != SEM_FAILED) {
303 sem_close(id);
304 retval = 1;
306 if (errno != error) {
307 fprintf(stderr, "sem_open: %s\n", strerror(errno));
308 retval = 1;
310 return retval;
314 * Attempt a sem_init() that should fail with an expected error of
315 * 'error'.
318 sem_init_should_fail(unsigned int value, int error)
320 sem_t id;
322 if (sem_init(&id, 0, value) >= 0) {
323 sem_destroy(&id);
324 return 1;
326 if (errno != error) {
327 perror("sem_init");
328 return 1;
331 return 0;
335 * Attempt a sem_unlink() that should fail with an expected error of
336 * 'error'.
339 sem_unlink_should_fail(const char *path, int error)
342 if (sem_unlink(path) >= 0) {
343 return 1;
345 if (errno != error) {
346 perror("sem_unlink");
347 return 1;
349 return 0;
353 * Attempt a sem_destroy() that should fail with an expected error of
354 * 'error'.
357 sem_destroy_should_fail(sem_t *id, int error)
359 if (sem_destroy(id) >= 0) {
360 return 1;
362 if (errno != error) {
363 perror("sem_destroy");
364 return 1;
366 return 0;
370 * Attempt a sem_close() that should fail with an expected error of
371 * 'error'.
374 sem_close_should_fail(sem_t *id, int error)
377 if (sem_close(id) >= 0) {
378 return 1;
380 if (errno != error) {
381 perror("sem_close");
382 return 1;
384 return 0;