1 | /* BZ #17977 _res_hconf_reorder_addrs test. |
2 | |
3 | Copyright (C) 2015-2022 Free Software Foundation, Inc. |
4 | This file is part of the GNU C Library. |
5 | |
6 | The GNU C Library is free software; you can redistribute it and/or |
7 | modify it under the terms of the GNU Lesser General Public |
8 | License as published by the Free Software Foundation; either |
9 | version 2.1 of the License, or (at your option) any later version. |
10 | |
11 | The GNU C Library is distributed in the hope that it will be useful, |
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
14 | Lesser General Public License for more details. |
15 | |
16 | You should have received a copy of the GNU Lesser General Public |
17 | License along with the GNU C Library; if not, see |
18 | <https://www.gnu.org/licenses/>. */ |
19 | |
20 | #include <errno.h> |
21 | #include <stdio.h> |
22 | #include <stdlib.h> |
23 | #include <string.h> |
24 | #include <time.h> |
25 | #include <dlfcn.h> |
26 | #include <pthread.h> |
27 | #include <netdb.h> |
28 | #include <netinet/in.h> |
29 | #include <sys/socket.h> |
30 | |
31 | static struct timespec ts; |
32 | |
33 | /* The first thread that gets a lock in _res_hconf_reorder_addrs() |
34 | should hold the lock long enough to make two other threads blocked. |
35 | This is achieved by slowing down realloc(3) that is called several times |
36 | by _res_hconf_reorder_addrs(). */ |
37 | |
38 | void * |
39 | realloc (void *ptr, size_t len) |
40 | { |
41 | static void *(*fun) (void *, size_t); |
42 | |
43 | if (!fun) |
44 | fun = dlsym (RTLD_NEXT, name: "realloc" ); |
45 | |
46 | if (ts.tv_nsec) |
47 | nanosleep (requested_time: &ts, NULL); |
48 | |
49 | return (*fun) (ptr, len); |
50 | } |
51 | |
52 | static void * |
53 | resolve (void *arg) |
54 | { |
55 | struct in_addr addr; |
56 | struct hostent ent; |
57 | struct hostent *result; |
58 | int err; |
59 | char buf[1024]; |
60 | |
61 | addr.s_addr = htonl (INADDR_LOOPBACK); |
62 | (void) gethostbyaddr_r (addr: (void *) &addr, len: sizeof (addr), AF_INET, |
63 | result_buf: &ent, buf: buf, buflen: sizeof (buf), result: &result, h_errnop: &err); |
64 | return arg; |
65 | } |
66 | |
67 | static int |
68 | do_test (void) |
69 | { |
70 | #define N 3 |
71 | pthread_t thr[N]; |
72 | unsigned int i; |
73 | int result = 0; |
74 | |
75 | /* turn on realloc slowdown */ |
76 | ts.tv_nsec = 100000000; |
77 | |
78 | for (i = 0; i < N; ++i) |
79 | { |
80 | int rc = pthread_create (newthread: &thr[i], NULL, start_routine: resolve, NULL); |
81 | |
82 | if (rc) |
83 | { |
84 | printf (format: "pthread_create: %s\n" , strerror(errnum: rc)); |
85 | exit (status: 1); |
86 | } |
87 | } |
88 | |
89 | for (i = 0; i < N; ++i) |
90 | { |
91 | void *retval; |
92 | int rc = pthread_join (th: thr[i], thread_return: &retval); |
93 | |
94 | if (rc) |
95 | { |
96 | printf (format: "pthread_join: %s\n" , strerror(errnum: rc)); |
97 | exit (status: 1); |
98 | } |
99 | if (retval) |
100 | { |
101 | printf (format: "thread %u exit status %p\n" , i, retval); |
102 | result = 1; |
103 | } |
104 | } |
105 | |
106 | /* turn off realloc slowdown, no longer needed */ |
107 | ts.tv_nsec = 0; |
108 | |
109 | return result; |
110 | } |
111 | |
112 | #define TEST_FUNCTION do_test () |
113 | #include "../test-skeleton.c" |
114 | |