1 /*	$OpenBSD: dup2_race.c,v 1.3 2006/10/06 13:11:58 kurt Exp $	*/
2 /*
3  * Copyright (c) 2006 Kurt Miller <kurt@intricatesoftware.com>
4  *
5  * Permission to use, copy, modify, and distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17 
18 /*
19  * Test dup2() racing with other threads using the same file
20  * descriptor.
21  */
22 
23 #include <pthread.h>
24 #include <unistd.h>
25 #include <fcntl.h>
26 #include <time.h>
27 #include <sys/socket.h>
28 #include "test.h"
29 
30 #define ITERATIONS	100
31 #define BUSY_THREADS	10
32 
33 static void *
34 deadlock_detector(void *arg)
35 {
36 	sleep(60);
37 	PANIC("deadlock detected");
38 }
39 
40 static void *
41 busy_thread(void *arg)
42 {
43 	int fd = *(int *)arg;
44 
45 	/* loop until error */
46 	while(fcntl(fd, F_GETFD, NULL) != -1);
47 
48 	return ((caddr_t)NULL + errno);
49 }
50 
51 int
52 main(int argc, char *argv[])
53 {
54 	pthread_t busy_threads[BUSY_THREADS], deadlock_thread;
55 	int fd, newfd, i, j;
56 	void *value_ptr;
57 	struct timespec rqtp;
58 
59 	rqtp.tv_sec = 0;
60 	rqtp.tv_nsec = 1000000;
61 
62 	CHECKr(pthread_create(&deadlock_thread, NULL,
63 	    deadlock_detector, NULL));
64 
65 	CHECKe(fd = socket(AF_INET, SOCK_DGRAM, 0));
66 
67 	for (i = 0; i < 100; i++) {
68 		CHECKe(newfd = socket(AF_INET, SOCK_DGRAM, 0));
69 		for (j = 0; j < BUSY_THREADS; j++)
70 			CHECKr(pthread_create(&busy_threads[j], NULL,
71 			    busy_thread, (void *)&newfd));
72 		nanosleep(&rqtp, NULL);
73 		CHECKe(dup2(fd, newfd));
74 		for (j = 0; j < BUSY_THREADS; j++) {
75 			CHECKr(pthread_join(busy_threads[j], &value_ptr));
76 			ASSERT(value_ptr == (void *)EBADF);
77 		}
78 		CHECKe(close(newfd));
79 	}
80 	SUCCEED;
81 }
82