From 5f4aaf8b66ef04208c1c2121d4b780c792303f32 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Tue, 30 Apr 2024 11:07:28 +0200 Subject: [PATCH] tool_cb_rea: limit rate unpause for -T . uploads To avoid getting stuck in a busy-loop when nothing is read from stdin, this function now checks the call rate and might enforce a short sleep when called repeatedly without uploading anything. It is a crude work-around to avoid a 100% busy CPU. Reported-by: magisterquis on hackerone Fixes #13174 Closes #13506 Conflict:Context adapt add #include "tool_util.h" for tvdiff Reference:https://github.com/curl/curl/commit/5f4aaf8b66ef04208c1c2121d4b780c792303f32 --- src/tool_cb_rea.c | 31 ++++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/src/tool_cb_rea.c b/src/tool_cb_rea.c index 8cb5bbe8ac1d11..961dd113bc519d 100644 --- a/src/tool_cb_rea.c +++ b/src/tool_cb_rea.c @@ -36,6 +36,8 @@ #include "tool_cfgable.h" #include "tool_cb_rea.h" #include "tool_operate.h" +#include "tool_util.h" +#include "tool_sleep.h" #include "memdebug.h" /* keep this as LAST include */ @@ -124,8 +125,33 @@ int tool_readbusy_cb(void *clientp, (void)ulnow; /* unused */ if(config->readbusy) { - config->readbusy = FALSE; - curl_easy_pause(per->curl, CURLPAUSE_CONT); + /* lame code to keep the rate down because the input might not deliver + anything, get paused again and come back here immediately */ + static long rate = 500; + static struct timeval prev; + static curl_off_t ulprev; + + if(ulprev == ulnow) { + /* it did not upload anything since last call */ + struct timeval now = tvnow(); + if(prev.tv_sec) + /* get a rolling average rate */ + /* rate = rate - rate/4 + tvdiff(now, prev)/4; */ + rate -= rate/4 - tvdiff(now, prev)/4; + prev = now; + } + else { + rate = 50; + ulprev = ulnow; + } + if(rate >= 50) { + /* keeps the looping down to 20 times per second in the crazy case */ + config->readbusy = FALSE; + curl_easy_pause(per->curl, CURLPAUSE_CONT); + } + else + /* sleep half a period */ + tool_go_sleep(25); } return per->noprogress? 0 : CURL_PROGRESSFUNC_CONTINUE;