From f3c35e371cc70f1b6bc33f7faa904d37d1567eb3 Mon Sep 17 00:00:00 2001 From: Gergely Nagy Date: Sun, 17 Nov 2019 15:12:15 +0100 Subject: multi: add curl_multi_wakeup() This commit adds curl_multi_wakeup() which was previously in the TODO list under the curl_multi_unblock name. On some platforms and with some configurations this feature might not be available or can fail, in these cases a new error code (CURLM_WAKEUP_FAILURE) is returned from curl_multi_wakeup(). Fixes #4418 Closes #4608 --- tests/libtest/lib1565.c | 204 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 204 insertions(+) create mode 100644 tests/libtest/lib1565.c (limited to 'tests/libtest/lib1565.c') diff --git a/tests/libtest/lib1565.c b/tests/libtest/lib1565.c new file mode 100644 index 000000000..b2fa40aaa --- /dev/null +++ b/tests/libtest/lib1565.c @@ -0,0 +1,204 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ +#include "test.h" + +#include "testutil.h" +#include "warnless.h" +#include "memdebug.h" + +#ifdef HAVE_PTHREAD_H +#include +#include + +#define TEST_HANG_TIMEOUT 60 * 1000 +#define CONN_NUM 3 +#define TIME_BETWEEN_START_SECS 2 + +static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; +static CURL *pending_handles[CONN_NUM]; +static int pending_num = 0; +static int test_failure = 0; + +static CURLM *multi = NULL; +static const char *url; + +static void *run_thread(void *ptr) +{ + CURL *easy = NULL; + int res = 0; + int i; + + (void)ptr; + + for(i = 0; i < CONN_NUM; i++) { + sleep(TIME_BETWEEN_START_SECS); + + easy_init(easy); + + easy_setopt(easy, CURLOPT_URL, url); + easy_setopt(easy, CURLOPT_VERBOSE, 0L); + + pthread_mutex_lock(&lock); + + if(test_failure) { + pthread_mutex_unlock(&lock); + goto test_cleanup; + } + + pending_handles[pending_num] = easy; + pending_num++; + easy = NULL; + + pthread_mutex_unlock(&lock); + + multi_wakeup(multi); + } + +test_cleanup: + + curl_easy_cleanup(easy); + + pthread_mutex_lock(&lock); + + if(!test_failure) + test_failure = res; + + pthread_mutex_unlock(&lock); + + return NULL; +} + +int test(char *URL) +{ + int still_running; + int num; + int i; + int res = 0; + CURL *started_handles[CONN_NUM]; + int started_num = 0; + int finished_num = 0; + pthread_t tid = 0; + struct CURLMsg *message; + + start_test_timing(); + + global_init(CURL_GLOBAL_ALL); + + multi_init(multi); + + url = URL; + + res = pthread_create(&tid, NULL, run_thread, NULL); + if(0 != res) { + fprintf(stderr, "%s:%d Couldn't create thread, errno %d\n", + __FILE__, __LINE__, res); + goto test_cleanup; + } + + while(1) { + multi_perform(multi, &still_running); + + abort_on_test_timeout(); + + while((message = curl_multi_info_read(multi, &num)) != NULL) { + if(message->msg == CURLMSG_DONE) { + res = message->data.result; + if(res) + goto test_cleanup; + multi_remove_handle(multi, message->easy_handle); + finished_num++; + } + else { + fprintf(stderr, "%s:%d Got an unexpected message from curl: %i\n", + __FILE__, __LINE__, (int)message->msg); + res = TEST_ERR_MAJOR_BAD; + goto test_cleanup; + } + + abort_on_test_timeout(); + } + + if(CONN_NUM == finished_num) + break; + + multi_poll(multi, NULL, 0, TEST_HANG_TIMEOUT, &num); + + abort_on_test_timeout(); + + pthread_mutex_lock(&lock); + + while(pending_num > 0) { + res_multi_add_handle(multi, pending_handles[pending_num - 1]); + if(res) { + pthread_mutex_unlock(&lock); + goto test_cleanup; + } + + started_handles[started_num] = pending_handles[pending_num - 1]; + started_num++; + pending_num--; + } + + pthread_mutex_unlock(&lock); + + abort_on_test_timeout(); + } + + if(CONN_NUM != started_num) { + fprintf(stderr, "%s:%d Not all connections started: %d of %d\n", + __FILE__, __LINE__, started_num, CONN_NUM); + goto test_cleanup; + } + + if(CONN_NUM != finished_num) { + fprintf(stderr, "%s:%d Not all connections finished: %d of %d\n", + __FILE__, __LINE__, started_num, CONN_NUM); + goto test_cleanup; + } + +test_cleanup: + + pthread_mutex_lock(&lock); + if(!test_failure) + test_failure = res; + pthread_mutex_unlock(&lock); + + if(0 != tid) + pthread_join(tid, NULL); + + curl_multi_cleanup(multi); + for(i = 0; i < pending_num; i++) + curl_easy_cleanup(pending_handles[i]); + for(i = 0; i < started_num; i++) + curl_easy_cleanup(started_handles[i]); + curl_global_cleanup(); + + return test_failure; +} + +#else /* without pthread, this test doesn't work */ +int test(char *URL) +{ + (void)URL; + return 0; +} +#endif -- cgit v1.2.3