aboutsummaryrefslogtreecommitdiff
path: root/src/testcurl
diff options
context:
space:
mode:
authorEvgeny Grin (Karlson2k) <k2k@narod.ru>2019-05-26 16:27:06 +0300
committerEvgeny Grin (Karlson2k) <k2k@narod.ru>2019-05-26 16:27:06 +0300
commit55e624e7d0c25804d242d453cb043779cf67fede (patch)
treee6380882460bbc3d4ccea6bb62c43d7fc1dd7d77 /src/testcurl
parent29e20dfb656e146c8b2797a8d4b12cf6fa87fc92 (diff)
downloadlibmicrohttpd-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.c149
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 */
61static struct MHD_Response *response; 62static struct MHD_Response *response;
62 63
64/**
65 * Continue generating new requests?
66 */
67static volatile int continue_requesting;
68
69/**
70 * Continue waiting in watchdog thread?
71 */
72static volatile int watchdog_continue;
73
74static const char *watchdog_obj;
75
76static void *
77thread_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
97pthread_t watchdog_tid;
98
99static void
100start_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
111static void
112stop_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
64static size_t 122static size_t
65copyBuffer (void *ptr, 123copyBuffer (void *ptr,
@@ -103,61 +161,44 @@ ahc_echo (void *cls,
103 return ret; 161 return ret;
104} 162}
105 163
106static void
107clean_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
117static void * 164static void *
118thread_gets (void *param) 165thread_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, &copyBuffer);
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, &copyBuffer);
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)
200pthread_t start_gets(int port) 240pthread_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))