-
-
Notifications
You must be signed in to change notification settings - Fork 6.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
gopher: check remaining time left during write busy loop #5214
Conversation
b2058a7
to
0611d61
Compare
I'm in the process of redoing schannel_send to be non-blocking, hopefully it will help with #5177. The socket writable check there is likely going be removed. It calls select which will block on a non-blocking socket. AFAICS if the timeout is 0 and that means no timeout and the non-blocking socket is not ready then 0 will be returned. If that is the case then returning CURLE_OPERATION_TIMEDOUT is wrong. In other words, if the user has not given a timeout, and therefore the timeout is 0, then we shouldn't timeout if the socket is not ready. |
Okay, I will wait for your enhancements to |
Maybe Curl_timeleft should not return 0 when there is no timeout set? Return TIMEDIFF_T_MAX? Lines 214 to 221 in b81e0b0
|
Just checked Curl_timeleft("unspecifed")=> TIMEDIFF_T_MAX with schannel problem and it's works fine.
|
I think that sounds like a pretty clever way to enhance the function and remove the need to special-case when it returns zero... |
I don't think this is correct, because:
Source: https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-select#remarks |
I don't know if this is a good idea, because this is basically busy-looping and putting pressure on the socket write buffers. But I am not sure, maybe it is an alternative solution? cc @bagder @jay? |
I don't think I understand the question. Should we avoid select() ? If we would do it entirely correctly, it should loop at all and then it shouldn't do select()... |
But you're right, we should not busy-loop. That's the worst. |
I was referring to @ajax16384 points above and the specific reference to "(like it's done here)" there Lines 174 to 185 in b81e0b0
Is that even possible inside Lines 1625 to 1628 in 6d13ef5
And I am not sure if that would also apply to |
- Add threaded resolver cleanup and GSSAPI for FTP to the TODO list of known blocking operations. - New known bugs entry 'Blocking socket operations in non-blocking API' that directs to the TODO's list of known blocking operations. Ref: curl#5214 (comment) Reported-by: Marc Hoersken Closes #xxxx
...
Yes you're right it's a busy loop if the socket isn't available. Though we shouldn't block, if we must then we should block waiting for the socket rather than call the underlying write repeatedly and eat CPU. That code in security.c needs to be improved, even if it can't be made non-blocking. I've added GSSAPI for FTP (afaict this is what security.c does) as a blocking operation to the TODO list. #5216 |
@mback2k well noticed: "If TIMEVAL is initialized to {0, 0}, select will return immediately; this is used to poll the state of the selected sockets.". |
I'm having second thoughts. I've since I looked through the codebase and it is depended on elsewhere that Curl_timeleft uses 0 to signal there is no timeout, so it may not be as easy as I thought. The crux of the issue is it is not immediately clear to contributors that Curl_timeleft returns 0 to signal there is no timeout set, though there is some comment at the end of the function that implies it. However most of the code seems to have been written with an understanding of that. Example: Lines 428 to 435 in b81e0b0
It would be easier to update the documentation and then address those cases individually where 0 is wrongly treated as time remaining. For example in this PR timeleft = Curl_timeleft(conn->data, NULL, FALSE);
if(timeleft < 0) {
result = CURLE_OPERATION_TIMEDOUT;
break;
}
if(!timeleft || timeleft > TIME_T_MAX)
timeleft = TIME_T_MAX; Otherwise we'd have to trace every Curl_timeleft to find which code depends on 0 to signal no timeout and then walk through that logic, and change Curl_timeleft to return 0 to mean no time left. Possibly renaming the function Curl_calculate_timeout or something would help to make it clear that 0 may have some special value? |
Assisted-by: Jay Satiro Reviewed-by: Daniel Stenberg Closes curl#5214
0611d61
to
3c63de3
Compare
@jay thanks, I updated this PR accordingly. |
- Document in Curl_timeleft's comment block that returning 0 signals no timeout (ie there's infinite time left). - Fix SOCKS' Curl_blockread_all for the case when no timeout was set. Prior to this change if the timeout had a value of 0 and that was passed to SOCKET_READABLE it would return right away instead of blocking. That was likely because it was not well understood that when Curl_timeleft returns 0 it is not a timeout of 0 ms but actually means no timeout. Ref: curl#5214 (comment) Closes #xxxx
I found a similar issue in socks #5220 and I renamed timeleft to timeout_ms, since I think that may be easier to understand. |
Thanks, looks good! I will also rename the variable here, because that makes a lot more sense. |
3c63de3
to
9726dc9
Compare
9726dc9
to
1da941a
Compare
- Document in Curl_timeleft's comment block that returning 0 signals no timeout (ie there's infinite time left). - Fix SOCKS' Curl_blockread_all for the case when no timeout was set. Prior to this change if the timeout had a value of 0 and that was passed to SOCKET_READABLE it would return right away instead of blocking. That was likely because it was not well understood that when Curl_timeleft returns 0 it is not a timeout of 0 ms but actually means no timeout. Ref: #5214 (comment) Closes #5220
Thanks |
- Add threaded resolver cleanup and GSSAPI for FTP to the TODO list of known blocking operations. - New known bugs entry 'Blocking socket operations in non-blocking API' that directs to the TODO's list of known blocking operations. Ref: #5214 (comment) Reported-by: Marc Hoersken Closes #5216
Now that all functions in select.[ch] take timediff_t instead of the limited time_t or int, we can remove type conversions and related preprocessor checks to silence compiler warnings. Based upon curl#5262 Related to curl#5479 Supersedes curl#5214, curl#5220 and curl#5221 Follow up to curl#5343 Closes curl#5490
Remove obsolete type conversions to time_t or int: Now that all functions in select.[ch] take timediff_t instead of the limited time_t or int, we can remove type conversions and related preprocessor checks to silence compiler warnings. Based upon curl#5262 Supersedes curl#5214, curl#5220 and curl#5221 Follow up to curl#5343 and curl#5479 Closes curl#5490
Now that all functions in select.[ch] take timediff_t instead of the limited time_t or int, we can remove type conversions and related preprocessor checks to silence compiler warnings. Based upon curl#5262 Supersedes curl#5214, curl#5220 and curl#5221 Follow up to curl#5343 and curl#5479 Closes curl#5490
Now that all functions in select.[ch] take timediff_t instead of the limited time_t or int, we can remove type conversions and related preprocessor checks to silence compiler warnings. Based upon curl#5262 Supersedes curl#5214, curl#5220 and curl#5221 Follow up to curl#5343 and curl#5479 Closes curl#5490
Now that all functions in select.[ch] take timediff_t instead of the limited int or long, we can remove type conversions and related preprocessor checks to silence compiler warnings. Avoiding conversions from time_t was already done in 842f73d. Based upon curl#5262 Supersedes curl#5214, curl#5220 and curl#5221 Follow up to curl#5343 and curl#5479 Closes curl#5490
Now that all functions in select.[ch] take timediff_t instead of the limited int or long, we can remove type conversions and related preprocessor checks to silence compiler warnings. Avoiding conversions from time_t was already done in 842f73d. Based upon #5262 Supersedes #5214, #5220 and #5221 Follow up to #5343 and #5479 Closes #5490
Comparing SOCKET_WRITABLE in
schannel.c
andgopher.c
, gopher never considered the transfer time out before.