diff options
author | Evgeny Grin (Karlson2k) <k2k@narod.ru> | 2019-05-26 16:27:06 +0300 |
---|---|---|
committer | Evgeny Grin (Karlson2k) <k2k@narod.ru> | 2019-05-26 16:27:06 +0300 |
commit | 55e624e7d0c25804d242d453cb043779cf67fede (patch) | |
tree | e6380882460bbc3d4ccea6bb62c43d7fc1dd7d77 /src/testcurl | |
parent | 29e20dfb656e146c8b2797a8d4b12cf6fa87fc92 (diff) | |
download | libmicrohttpd-55e624e7d0c25804d242d453cb043779cf67fede.tar.gz libmicrohttpd-55e624e7d0c25804d242d453cb043779cf67fede.zip |
test_concurrent_stop: heavily rewritten, added watchdog, avoided exhausting of ports,
fixed resource leakage.
Implemented local watchdog, so test will fails instead of hanging in
case of problems,
Reused connections on libcurl, so test really check functioning (before
fix test could just exhausted all local ports and did not have any
any connection for moment when "MHD_stop_daemon()" was called.
CURL resources are not leaked during normal testing.
Diffstat (limited to 'src/testcurl')
-rw-r--r-- | src/testcurl/test_concurrent_stop.c | 149 |
1 files changed, 99 insertions, 50 deletions
diff --git a/src/testcurl/test_concurrent_stop.c b/src/testcurl/test_concurrent_stop.c index 263aaf0a..71202add 100644 --- a/src/testcurl/test_concurrent_stop.c +++ b/src/testcurl/test_concurrent_stop.c | |||
@@ -33,11 +33,12 @@ | |||
33 | #include <pthread.h> | 33 | #include <pthread.h> |
34 | #include "gauger.h" | 34 | #include "gauger.h" |
35 | 35 | ||
36 | #ifdef CPU_COUNT | 36 | #if defined(CPU_COUNT) && (CPU_COUNT+0) < 2 |
37 | #undef CPU_COUNT | 37 | #undef CPU_COUNT |
38 | #endif | 38 | #endif |
39 | #define CPU_COUNT 40 | 39 | #if !defined(CPU_COUNT) |
40 | 40 | #define CPU_COUNT 2 | |
41 | #endif | ||
41 | 42 | ||
42 | /** | 43 | /** |
43 | * How many rounds of operations do we do for each | 44 | * How many rounds of operations do we do for each |
@@ -48,7 +49,7 @@ | |||
48 | /** | 49 | /** |
49 | * How many requests do we do in parallel? | 50 | * How many requests do we do in parallel? |
50 | */ | 51 | */ |
51 | #define PAR CPU_COUNT | 52 | #define PAR (CPU_COUNT * 4) |
52 | 53 | ||
53 | /** | 54 | /** |
54 | * Do we use HTTP 1.1? | 55 | * Do we use HTTP 1.1? |
@@ -60,6 +61,63 @@ static int oneone; | |||
60 | */ | 61 | */ |
61 | static struct MHD_Response *response; | 62 | static struct MHD_Response *response; |
62 | 63 | ||
64 | /** | ||
65 | * Continue generating new requests? | ||
66 | */ | ||
67 | static volatile int continue_requesting; | ||
68 | |||
69 | /** | ||
70 | * Continue waiting in watchdog thread? | ||
71 | */ | ||
72 | static volatile int watchdog_continue; | ||
73 | |||
74 | static const char *watchdog_obj; | ||
75 | |||
76 | static void * | ||
77 | thread_watchdog (void *param) | ||
78 | { | ||
79 | int seconds_passed; | ||
80 | const int timeout_val = (int) (intptr_t) param; | ||
81 | |||
82 | seconds_passed = 0; | ||
83 | while (watchdog_continue) /* Poor threads sync, but works for testing. */ | ||
84 | { | ||
85 | if (0 == sleep (1)) /* Poor accuracy, but enough for testing. */ | ||
86 | seconds_passed++; | ||
87 | if (timeout_val < seconds_passed) | ||
88 | { | ||
89 | fprintf (stderr, "%s timeout expired.\n", watchdog_obj ? watchdog_obj : "Watchdog"); | ||
90 | fflush (stderr); | ||
91 | _exit(16); | ||
92 | } | ||
93 | } | ||
94 | return NULL; | ||
95 | } | ||
96 | |||
97 | pthread_t watchdog_tid; | ||
98 | |||
99 | static void | ||
100 | start_watchdog(int timeout, const char *obj_name) | ||
101 | { | ||
102 | watchdog_continue = 1; | ||
103 | watchdog_obj = obj_name; | ||
104 | if (0 != pthread_create(&watchdog_tid, NULL, &thread_watchdog, (void*)(intptr_t)timeout)) | ||
105 | { | ||
106 | fprintf(stderr, "Failed to start watchdog.\n"); | ||
107 | _exit (99); | ||
108 | } | ||
109 | } | ||
110 | |||
111 | static void | ||
112 | stop_watchdog(void) | ||
113 | { | ||
114 | watchdog_continue = 0; | ||
115 | if (0 != pthread_join (watchdog_tid, NULL)) | ||
116 | { | ||
117 | fprintf(stderr, "Failed to stop watchdog.\n"); | ||
118 | _exit (99); | ||
119 | } | ||
120 | } | ||
63 | 121 | ||
64 | static size_t | 122 | static size_t |
65 | copyBuffer (void *ptr, | 123 | copyBuffer (void *ptr, |
@@ -103,61 +161,44 @@ ahc_echo (void *cls, | |||
103 | return ret; | 161 | return ret; |
104 | } | 162 | } |
105 | 163 | ||
106 | static void | ||
107 | clean_curl(void * param) | ||
108 | { | ||
109 | if (param) | ||
110 | { | ||
111 | CURL * const c = *((CURL **)param); | ||
112 | if (c) | ||
113 | curl_easy_cleanup (c); | ||
114 | } | ||
115 | } | ||
116 | |||
117 | static void * | 164 | static void * |
118 | thread_gets (void *param) | 165 | thread_gets (void *param) |
119 | { | 166 | { |
120 | CURL *c; | 167 | CURL *c; |
121 | CURLcode errornum; | 168 | CURLcode errornum; |
122 | unsigned int i; | ||
123 | char * const url = (char*) param; | 169 | char * const url = (char*) param; |
124 | int pth_olst; | 170 | |
125 | if (pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &pth_olst) || | 171 | c = NULL; |
126 | pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, &pth_olst) ) | 172 | c = curl_easy_init (); |
173 | if (NULL == c) | ||
127 | { | 174 | { |
128 | fprintf(stderr, | 175 | fprintf(stderr, "curl_easy_init failed.\n"); |
129 | "pthread_setcancelstate()/pthread_setcanceltype() failed.\n"); | ||
130 | _exit(99); | 176 | _exit(99); |
131 | } | 177 | } |
132 | 178 | curl_easy_setopt (c, CURLOPT_URL, url); | |
133 | for (i=0;i<ROUNDS;i++) | 179 | curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer); |
180 | curl_easy_setopt (c, CURLOPT_WRITEDATA, NULL); | ||
181 | curl_easy_setopt (c, CURLOPT_FAILONERROR, 1L); | ||
182 | curl_easy_setopt (c, CURLOPT_TIMEOUT, 2L); | ||
183 | if (oneone) | ||
184 | curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); | ||
185 | else | ||
186 | curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0); | ||
187 | curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 2L); | ||
188 | /* NOTE: use of CONNECTTIMEOUT without also | ||
189 | setting NOSIGNAL results in really weird | ||
190 | crashes on my system! */ | ||
191 | curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L); | ||
192 | while (continue_requesting) | ||
134 | { | 193 | { |
135 | pthread_testcancel(); | ||
136 | c = NULL; | ||
137 | pthread_cleanup_push(clean_curl, (void*)&c); | ||
138 | c = curl_easy_init (); | ||
139 | pthread_testcancel(); | ||
140 | curl_easy_setopt (c, CURLOPT_URL, url); | ||
141 | curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer); | ||
142 | curl_easy_setopt (c, CURLOPT_WRITEDATA, NULL); | ||
143 | curl_easy_setopt (c, CURLOPT_FAILONERROR, 1); | ||
144 | curl_easy_setopt (c, CURLOPT_TIMEOUT, 5L); | ||
145 | if (oneone) | ||
146 | curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); | ||
147 | else | ||
148 | curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0); | ||
149 | curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 5L); | ||
150 | /* NOTE: use of CONNECTTIMEOUT without also | ||
151 | setting NOSIGNAL results in really weird | ||
152 | crashes on my system! */ | ||
153 | curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1); | ||
154 | pthread_testcancel(); | ||
155 | errornum = curl_easy_perform (c); | 194 | errornum = curl_easy_perform (c); |
156 | pthread_cleanup_pop (1); | ||
157 | if (CURLE_OK != errornum) | 195 | if (CURLE_OK != errornum) |
158 | return NULL; | 196 | { |
197 | curl_easy_cleanup (c); | ||
198 | return NULL; | ||
199 | } | ||
159 | } | 200 | } |
160 | 201 | curl_easy_cleanup (c); | |
161 | return NULL; | 202 | return NULL; |
162 | } | 203 | } |
163 | 204 | ||
@@ -179,9 +220,9 @@ do_gets (void * param) | |||
179 | if (0 != pthread_create(&par[j], NULL, &thread_gets, (void*)url)) | 220 | if (0 != pthread_create(&par[j], NULL, &thread_gets, (void*)url)) |
180 | { | 221 | { |
181 | fprintf(stderr, "pthread_create failed.\n"); | 222 | fprintf(stderr, "pthread_create failed.\n"); |
223 | continue_requesting = 0; | ||
182 | for (j--; j >= 0; j--) | 224 | for (j--; j >= 0; j--) |
183 | { | 225 | { |
184 | pthread_cancel(par[j]); | ||
185 | pthread_join(par[j], NULL); | 226 | pthread_join(par[j], NULL); |
186 | } | 227 | } |
187 | _exit(99); | 228 | _exit(99); |
@@ -190,7 +231,6 @@ do_gets (void * param) | |||
190 | (void)sleep (1); | 231 | (void)sleep (1); |
191 | for (j=0;j<PAR;j++) | 232 | for (j=0;j<PAR;j++) |
192 | { | 233 | { |
193 | pthread_cancel(par[j]); | ||
194 | pthread_join(par[j], NULL); | 234 | pthread_join(par[j], NULL); |
195 | } | 235 | } |
196 | return NULL; | 236 | return NULL; |
@@ -200,6 +240,7 @@ do_gets (void * param) | |||
200 | pthread_t start_gets(int port) | 240 | pthread_t start_gets(int port) |
201 | { | 241 | { |
202 | pthread_t tid; | 242 | pthread_t tid; |
243 | continue_requesting = 1; | ||
203 | if (0 != pthread_create(&tid, NULL, &do_gets, (void*)(intptr_t)port)) | 244 | if (0 != pthread_create(&tid, NULL, &do_gets, (void*)(intptr_t)port)) |
204 | { | 245 | { |
205 | fprintf(stderr, "pthread_create failed.\n"); | 246 | fprintf(stderr, "pthread_create failed.\n"); |
@@ -233,7 +274,10 @@ testMultithreadedGet (int port, | |||
233 | } | 274 | } |
234 | p = start_gets (port); | 275 | p = start_gets (port); |
235 | (void)sleep (1); | 276 | (void)sleep (1); |
277 | start_watchdog(10, "daemon_stop() in testMultithreadedGet"); | ||
236 | MHD_stop_daemon (d); | 278 | MHD_stop_daemon (d); |
279 | stop_watchdog(); | ||
280 | continue_requesting = 0; | ||
237 | pthread_join (p, NULL); | 281 | pthread_join (p, NULL); |
238 | return 0; | 282 | return 0; |
239 | } | 283 | } |
@@ -264,7 +308,10 @@ testMultithreadedPoolGet (int port, | |||
264 | } | 308 | } |
265 | p = start_gets (port); | 309 | p = start_gets (port); |
266 | (void)sleep (1); | 310 | (void)sleep (1); |
311 | start_watchdog(10, "daemon_stop() in testMultithreadedPoolGet"); | ||
267 | MHD_stop_daemon (d); | 312 | MHD_stop_daemon (d); |
313 | stop_watchdog(); | ||
314 | continue_requesting = 0; | ||
268 | pthread_join (p, NULL); | 315 | pthread_join (p, NULL); |
269 | return 0; | 316 | return 0; |
270 | } | 317 | } |
@@ -276,14 +323,16 @@ main (int argc, char *const *argv) | |||
276 | unsigned int errorCount = 0; | 323 | unsigned int errorCount = 0; |
277 | int port; | 324 | int port; |
278 | (void)argc; /* Unused. Silent compiler warning. */ | 325 | (void)argc; /* Unused. Silent compiler warning. */ |
326 | (void)argv; /* Unused. Silent compiler warning. */ | ||
279 | 327 | ||
280 | if (MHD_NO != MHD_is_feature_supported (MHD_FEATURE_AUTODETECT_BIND_PORT)) | 328 | if (MHD_NO != MHD_is_feature_supported (MHD_FEATURE_AUTODETECT_BIND_PORT)) |
281 | port = 0; | 329 | port = 0; |
282 | else | 330 | else |
283 | port = 1142; | 331 | port = 1142; |
284 | 332 | ||
285 | oneone = (NULL != strrchr (argv[0], (int) '/')) ? | 333 | /* Do reuse connection, otherwise all available local ports may exhausted. */ |
286 | (NULL != strstr (strrchr (argv[0], (int) '/'), "11")) : 0; | 334 | oneone = 1; |
335 | |||
287 | if (0 != port && oneone) | 336 | if (0 != port && oneone) |
288 | port += 5; | 337 | port += 5; |
289 | if (0 != curl_global_init (CURL_GLOBAL_WIN32)) | 338 | if (0 != curl_global_init (CURL_GLOBAL_WIN32)) |