Previously, if the system time was adjusted backwards during a progress display, get_update_timediff return negative values prevent the progress bar from updating. Instead, on negative values, the saved time is reset. Additionally, the download callback ignores the amount downloaded to avoid skewing the rate. Fixes FS#36983 Signed-off-by: Andrew Gregory <andrew.gregory.8@gmail.com> --- src/pacman/callback.c | 33 +++++++++++++++++++-------------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/src/pacman/callback.c b/src/pacman/callback.c index a181fa5..0ffb2ef 100644 --- a/src/pacman/callback.c +++ b/src/pacman/callback.c @@ -73,8 +73,8 @@ static long get_update_timediff(int first_call) retval = (diff_sec * 1000) + (diff_usec / 1000); - /* do not update last_time if interval was too short */ - if(retval >= UPDATE_SPEED_MS) { + /* update last_time if it is in the future or interval was long enough */ + if(retval < 0 || retval >= UPDATE_SPEED_MS) { last_time = this_time; } } @@ -554,7 +554,7 @@ void cb_dl_progress(const char *filename, off_t file_xfered, off_t file_total) { static double rate_last; static off_t xfered_last; - static struct timeval initial_time; + static long elapsed_time = 0; int infolen; int filenamelen; char *fname, *p; @@ -616,25 +616,23 @@ void cb_dl_progress(const char *filename, off_t file_xfered, off_t file_total) /* set default starting values, ensure we only call this once * if TotalDownload is enabled */ if(!totaldownload || (totaldownload && list_xfered == 0)) { - gettimeofday(&initial_time, NULL); + elapsed_time = 0; xfered_last = (off_t)0; rate_last = 0.0; get_update_timediff(1); } } else if(file_xfered == file_total) { /* compute final values */ - struct timeval current_time; - time_t diff_sec; - suseconds_t diff_usec; + timediff = get_update_timediff(0); - gettimeofday(¤t_time, NULL); - diff_sec = current_time.tv_sec - initial_time.tv_sec; - diff_usec = current_time.tv_usec - initial_time.tv_usec; - timediff = (diff_sec * 1000) + (diff_usec / 1000); if(timediff > 0) { - rate = (double)xfered / (timediff / 1000.0); + elapsed_time += timediff; + } + + if(elapsed_time > 0) { + rate = (double)xfered / (elapsed_time / 1000.0); /* round elapsed time (in ms) to the nearest second */ - eta_s = (unsigned int)(timediff + 500) / 1000; + eta_s = (unsigned int)(elapsed_time + 500) / 1000; } else { eta_s = 0; } @@ -642,10 +640,17 @@ void cb_dl_progress(const char *filename, off_t file_xfered, off_t file_total) /* compute current average values */ timediff = get_update_timediff(0); - if(timediff < UPDATE_SPEED_MS) { + if(timediff < 0) { + /* we lost a chunk of time due to a clock change, including the amount + * xfered during that period in the next update would skew the rate */ + xfered_last = xfered; + return; + } else if(timediff < UPDATE_SPEED_MS) { /* return if the calling interval was too short */ return; } + + elapsed_time += timediff; rate = (double)(xfered - xfered_last) / (timediff / 1000.0); /* average rate to reduce jumpiness */ rate = (rate + 2 * rate_last) / 3; -- 1.8.4.2