Conversation
- Split WINSOCK and POSIX code in `multi_wait()` as the ifdef'ery was becoming unreadable - define `ENABLE_WAKEUP` to mean the wakeup socketpair is enabled, no additional USE_WINSOCK check needed. Under WINSOCK `ENABLE_WAKEUP` is not defined, so it's availability is as before under the double defined() checks - When the multi handle has "alive" transfers, the admin handle's pollset include the wakeup receive socket. This results in the admin handle running when someone uses `curl_multi_wakeup()`. - Without any "alive" transfers, the wakeup socket is removed from the pollset. Otherwise, event based processing would never finish, eg. leave the event loop. - The wakeup socket was never registered for event processing before, e.g. `curl_multi_wakeup()` never worked in that mode. - Adjust test exepectations on socket callback invocations and number of sockets appearing in waitfds sets.
having added transfers to a multi handle.
|
@jay please have a look if my split of the WINSOCK code looks sane. |
|
@icing sorry I did not see this until it was bumped in my inbox. @mback2k wrote the Winsock select code. I don't grok this area but I took a look. I notice that your split logic change removes multi_wait's Also, the extra wait handling has been moved into the split-off functions and is handled differently depending on winsock or posix (ie non-winsock). For the winsock version it doesn't call multi_timeout to calculate the extra wait time any longer if there are no sockets. What I'm saying is before it was this: multi_wait does a unix poll or winsock poll now it's either multi_wait calls multi_winsock_select (Windows) It is not entirely clear to me whether the winsock function that was split off is correct, but again I don't grok this area, maybe Marc can take a look. |
|
This area was always very complicated and I remember spending a lot of time even getting into this initially. The difference described by @jay may actually be quite important, because I remember that I spent a lot of time to make the wake-able timeout code work correctly on Windows using |
|
Thanks for reviewing and your comments. I agree that the code has been very complicated and we seem to have no adequate test cases (@mback2k how did you verify your changes in the past?). My reason for splitting the windows and posix cases are twofold:
The former code in #ifdef ENABLE_WAKEUP
#ifndef USE_WINSOCK
if(use_wakeup && multi->wakeup_pair[0] != CURL_SOCKET_BAD) {
if(Curl_pollfds_add_sock(&cpfds, multi->wakeup_pair[0], POLLIN)) {
mresult = CURLM_OUT_OF_MEMORY;
goto out;
}
}
#endif
#endifSo the wakeup socket was never part of the pollset under Windows. Something needed to be done here. As to @jay's observations:
I'll make a follow-up PR with these changes. |
The refactoring in curl#20832 introduced some inconsistencies between windows and posix handling, pointed out by reviews. Fix them: - rename `wait_on_nop` back to `extrawait` as it was called before - use multi_timeout() to shorten the user supplied timeout for both windows/posix in the same way - remove the extra multi_timeout() check in the posix function - Add the multi's wakeup socket for monitoring only when there are other sockets to poll on or when the caller wants the extra waiting time.
|
I made #21072 to fix the things discovered in review. Thanks! |
|
I hate to say it but if we can't be sure the Winsock event code is going to do what is expected, or we are not sure it is correct for this forthcoming remodel, then we should consider dropping it in favor of the posix code which also works on Windows. IIRC the Winsock specific event style of poll has an advantage in that it allows more than tested ok with it disabled, shows similar numbers of CPU cycles in repeated runs of 200MB download diff --git a/lib/multi.c b/lib/multi.c
index 7646e12..3911ed6 100644
--- a/lib/multi.c
+++ b/lib/multi.c
@@ -1330,7 +1330,7 @@ CURLMcode curl_multi_waitfds(CURLM *m,
return mresult;
}
-#ifdef USE_WINSOCK
+#if 0
/* Reset FD_WRITE for TCP sockets. Nothing is actually sent. UDP sockets cannot
* be reset this way because an empty datagram would be sent. #9203
*
@@ -1610,7 +1610,7 @@ static CURLMcode multi_wait(struct Curl_multi *multi,
CURL_TRC_M(data, "multi_wait(fds=%d, timeout=%d) tinternal=%ld",
cpfds.n, timeout_ms, timeout_internal);
-#ifdef USE_WINSOCK
+#if 0
mresult = multi_winsock_select(multi, &cpfds, curl_nfds,
extra_fds, extra_nfds,
timeout_ms, extrawait, &nevents);That said I don't have any objections to #21072 |
|
I am all for simplifying this, but I cannot judge the impacts this change would have. |
|
The POSIX code does not work with stdin/stdout on Windows as far as I remember, so piping with curl.exe was problematic with Windows Event style handling. I would have to trace the origins of why I introduced this at the time which is not so easy to many refactors and me currently traveling on vacation. |
Understood. My disabled test was quick and dirty so yes there may be some disadvantages. It doesn't address FD_SETSIZE issue (too large FD_SETSIZE with fd_set declarations on the stack could be a problem) or the wakeup code. Coming back to what Stefan said earlier, if Winsock is used then ENABLE_WAKEUP is not defined (both before and after this pr). This is because instead of a socketpair to wake up the multi, the winsock builds use a wakeup from an event handle in the multi wsa_event. So if we drop Currently it's one or the other: from 8.19.0: Lines 161 to 169 in 8c908d2 from master (has the changes from this pr): Lines 74 to 76 in 797bc31 Lines 161 to 168 in 797bc31 I think though this would explain what Stefan said about observing that with winsock a wakeup socket is never part of the pollset because it wouldn't be since an event is used to wake up instead. As seen in curl_multi_wakeup. |
|
Understood. I was able to find the original PR which also links a bug as reason for the event-based implementation: #6245 There were also some follow-up PRs with further fixes, enhancements and finally additional enabled tests which didn't work before. I think MinGW and other implementations of POSIX derived from msys/cygwin had some problems without this as well. It was a tedious process to get this correct initially on all platforms. I am worried the refactor won't be tested as thoroughly since the Azure and AppVeyor tests regarding MinGW have been dropped as far as I understand. |
The refactoring in #20832 introduced some inconsistencies between windows and posix handling, pointed out by reviews. Fix them: - rename `wait_on_nop` back to `extrawait` as it was called before - use multi_timeout() to shorten the user supplied timeout for both windows/posix in the same way - remove the extra multi_timeout() check in the posix function - Add the multi's wakeup socket for monitoring only when there are other sockets to poll on or when the caller wants the extra waiting time. Closes #21072
multi_wait()as the ifdef'ery was becoming unreadableENABLE_WAKEUPto mean the wakeup socketpair is enabled, no additional USE_WINSOCK check needed. Under WINSOCKENABLE_WAKEUPis not defined, so it's availability is as before under the double defined() checkscurl_multi_wakeup().curl_multi_wakeup()never worked in that mode.