diff --git a/google/cloud/internal/curl_impl.cc b/google/cloud/internal/curl_impl.cc index 26998dbd6988c..d40c7498332e6 100644 --- a/google/cloud/internal/curl_impl.cc +++ b/google/cloud/internal/curl_impl.cc @@ -705,18 +705,32 @@ Status CurlImpl::PerformWorkUntil(absl::FunctionRef predicate) { Status CurlImpl::WaitForHandles(int& repeats) { int const timeout_ms = 1000; int numfds = 0; -#if CURL_AT_LEAST_VERSION(7, 66, 0) - CURLMcode result = - curl_multi_poll(multi_.get(), nullptr, 0, timeout_ms, &numfds); - TRACE_STATE() << ", numfds=" << numfds << ", result=" << result - << ", repeats=" << repeats; - if (result != CURLM_OK) return AsStatus(result, __func__); + CURLMcode result; + // Work around https://github.com/curl/curl/issues/11135 by retrying + // when EINTR fails poll(). Besides, before 7.84.0, poll() errors + // return CURLM_OK. + // Simply `numfds == 0 && errno == EINTR` might be a sufficient condition, + // but not 100% sure. +#if _WIN32 + result = + curl_multi_poll(multi_.get(), nullptr, 0, timeout_ms, &numfds); +#elif CURL_AT_LEAST_VERSION(7, 84, 0) + do { + errno = 0; + result = + curl_multi_poll(multi_.get(), nullptr, 0, timeout_ms, &numfds); + } while (result == CURLM_UNRECOVERABLE_POLL && errno == EINTR); #else - CURLMcode result = - curl_multi_wait(multi_.get(), nullptr, 0, timeout_ms, &numfds); + do { + errno = 0; + result = + curl_multi_poll(multi_.get(), nullptr, 0, timeout_ms, &numfds); + } while (result == CURLM_OK && numfds == 0 && errno == EINTR); +#endif TRACE_STATE() << ", numfds=" << numfds << ", result=" << result << ", repeats=" << repeats; if (result != CURLM_OK) return AsStatus(result, __func__); +#if !CURL_AT_LEAST_VERSION(7, 66, 0) // The documentation for curl_multi_wait() recommends sleeping if it returns // numfds == 0 more than once in a row :shrug: // https://curl.haxx.se/libcurl/c/curl_multi_wait.html