diff options
author | Denys Vlasenko <vda.linux@googlemail.com> | 2012-09-03 12:49:30 +0200 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2012-09-03 12:49:30 +0200 |
commit | b7812ce0f7ee230330e18de3ac447b700311ab84 (patch) | |
tree | 12919e12982f3ef7a5562ca504417742c170ea7a /networking/wget.c | |
parent | 168f87c531d04be06e16f04144c61ba289e0c0ec (diff) | |
download | busybox-w32-b7812ce0f7ee230330e18de3ac447b700311ab84.tar.gz busybox-w32-b7812ce0f7ee230330e18de3ac447b700311ab84.tar.bz2 busybox-w32-b7812ce0f7ee230330e18de3ac447b700311ab84.zip |
wget: reorder fread and poll: poll only if fread returns EAGAIN. Closes 5426
function old new delta
retrieve_file_data 451 427 -24
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
Diffstat (limited to 'networking/wget.c')
-rw-r--r-- | networking/wget.c | 114 |
1 files changed, 62 insertions, 52 deletions
diff --git a/networking/wget.c b/networking/wget.c index 3416636ae..4eafebe40 100644 --- a/networking/wget.c +++ b/networking/wget.c | |||
@@ -444,13 +444,10 @@ static void NOINLINE retrieve_file_data(FILE *dfp) | |||
444 | { | 444 | { |
445 | #if ENABLE_FEATURE_WGET_STATUSBAR || ENABLE_FEATURE_WGET_TIMEOUT | 445 | #if ENABLE_FEATURE_WGET_STATUSBAR || ENABLE_FEATURE_WGET_TIMEOUT |
446 | # if ENABLE_FEATURE_WGET_TIMEOUT | 446 | # if ENABLE_FEATURE_WGET_TIMEOUT |
447 | unsigned second_cnt; | 447 | unsigned second_cnt = G.timeout_seconds; |
448 | # endif | 448 | # endif |
449 | struct pollfd polldata; | 449 | struct pollfd polldata; |
450 | 450 | ||
451 | # if ENABLE_FEATURE_WGET_TIMEOUT | ||
452 | second_cnt = G.timeout_seconds; | ||
453 | # endif | ||
454 | polldata.fd = fileno(dfp); | 451 | polldata.fd = fileno(dfp); |
455 | polldata.events = POLLIN | POLLPRI; | 452 | polldata.events = POLLIN | POLLPRI; |
456 | #endif | 453 | #endif |
@@ -468,7 +465,7 @@ static void NOINLINE retrieve_file_data(FILE *dfp) | |||
468 | * which messes up progress bar and/or timeout logic. | 465 | * which messes up progress bar and/or timeout logic. |
469 | * Because of nonblocking I/O, we need to dance | 466 | * Because of nonblocking I/O, we need to dance |
470 | * very carefully around EAGAIN. See explanation at | 467 | * very carefully around EAGAIN. See explanation at |
471 | * clearerr() call. | 468 | * clearerr() calls. |
472 | */ | 469 | */ |
473 | ndelay_on(polldata.fd); | 470 | ndelay_on(polldata.fd); |
474 | #endif | 471 | #endif |
@@ -476,34 +473,7 @@ static void NOINLINE retrieve_file_data(FILE *dfp) | |||
476 | int n; | 473 | int n; |
477 | unsigned rdsz; | 474 | unsigned rdsz; |
478 | 475 | ||
479 | rdsz = sizeof(G.wget_buf); | ||
480 | if (G.got_clen) { | ||
481 | if (G.content_len < (off_t)sizeof(G.wget_buf)) { | ||
482 | if ((int)G.content_len <= 0) | ||
483 | break; | ||
484 | rdsz = (unsigned)G.content_len; | ||
485 | } | ||
486 | } | ||
487 | |||
488 | #if ENABLE_FEATURE_WGET_STATUSBAR || ENABLE_FEATURE_WGET_TIMEOUT | 476 | #if ENABLE_FEATURE_WGET_STATUSBAR || ENABLE_FEATURE_WGET_TIMEOUT |
489 | if (safe_poll(&polldata, 1, 1000) == 0) { | ||
490 | # if ENABLE_FEATURE_WGET_TIMEOUT | ||
491 | if (second_cnt != 0 && --second_cnt == 0) { | ||
492 | progress_meter(PROGRESS_END); | ||
493 | bb_error_msg_and_die("download timed out"); | ||
494 | } | ||
495 | # endif | ||
496 | /* Needed for "stalled" indicator */ | ||
497 | progress_meter(PROGRESS_BUMP); | ||
498 | /* | ||
499 | * We used to loop back to poll here, | ||
500 | * but in chunked case, we can be here after | ||
501 | * fgets and it could buffer some data in dfp... | ||
502 | * which poll knows nothing about! | ||
503 | * Therefore let's try fread'ing anyway. | ||
504 | */ | ||
505 | } | ||
506 | |||
507 | /* fread internally uses read loop, which in our case | 477 | /* fread internally uses read loop, which in our case |
508 | * is usually exited when we get EAGAIN. | 478 | * is usually exited when we get EAGAIN. |
509 | * In this case, libc sets error marker on the stream. | 479 | * In this case, libc sets error marker on the stream. |
@@ -513,38 +483,71 @@ static void NOINLINE retrieve_file_data(FILE *dfp) | |||
513 | * into if (n <= 0) ... | 483 | * into if (n <= 0) ... |
514 | */ | 484 | */ |
515 | clearerr(dfp); | 485 | clearerr(dfp); |
516 | errno = 0; | ||
517 | #endif | 486 | #endif |
487 | errno = 0; | ||
488 | rdsz = sizeof(G.wget_buf); | ||
489 | if (G.got_clen) { | ||
490 | if (G.content_len < (off_t)sizeof(G.wget_buf)) { | ||
491 | if ((int)G.content_len <= 0) | ||
492 | break; | ||
493 | rdsz = (unsigned)G.content_len; | ||
494 | } | ||
495 | } | ||
518 | n = fread(G.wget_buf, 1, rdsz, dfp); | 496 | n = fread(G.wget_buf, 1, rdsz, dfp); |
519 | /* man fread: | 497 | |
498 | if (n > 0) { | ||
499 | xwrite(G.output_fd, G.wget_buf, n); | ||
500 | #if ENABLE_FEATURE_WGET_STATUSBAR | ||
501 | G.transferred += n; | ||
502 | #endif | ||
503 | if (G.got_clen) { | ||
504 | G.content_len -= n; | ||
505 | if (G.content_len == 0) | ||
506 | break; | ||
507 | } | ||
508 | #if ENABLE_FEATURE_WGET_TIMEOUT | ||
509 | second_cnt = G.timeout_seconds; | ||
510 | #endif | ||
511 | continue; | ||
512 | } | ||
513 | |||
514 | /* n <= 0. | ||
515 | * man fread: | ||
520 | * If error occurs, or EOF is reached, the return value | 516 | * If error occurs, or EOF is reached, the return value |
521 | * is a short item count (or zero). | 517 | * is a short item count (or zero). |
522 | * fread does not distinguish between EOF and error. | 518 | * fread does not distinguish between EOF and error. |
523 | */ | 519 | */ |
524 | if (n <= 0) { | 520 | if (errno != EAGAIN) { |
525 | #if ENABLE_FEATURE_WGET_STATUSBAR || ENABLE_FEATURE_WGET_TIMEOUT | 521 | if (ferror(dfp)) { |
526 | if (errno == EAGAIN) /* poll lied, there is no data? */ | 522 | progress_meter(PROGRESS_END); |
527 | continue; /* yes */ | ||
528 | #endif | ||
529 | if (ferror(dfp)) | ||
530 | bb_perror_msg_and_die(bb_msg_read_error); | 523 | bb_perror_msg_and_die(bb_msg_read_error); |
524 | } | ||
531 | break; /* EOF, not error */ | 525 | break; /* EOF, not error */ |
532 | } | 526 | } |
533 | 527 | ||
534 | xwrite(G.output_fd, G.wget_buf, n); | 528 | #if ENABLE_FEATURE_WGET_STATUSBAR || ENABLE_FEATURE_WGET_TIMEOUT |
535 | #if ENABLE_FEATURE_WGET_TIMEOUT | 529 | /* It was EAGAIN. There is no data. Wait up to one second |
536 | second_cnt = G.timeout_seconds; | 530 | * then abort if timed out, or update the bar and try reading again. |
537 | #endif | 531 | */ |
538 | #if ENABLE_FEATURE_WGET_STATUSBAR | 532 | if (safe_poll(&polldata, 1, 1000) == 0) { |
539 | G.transferred += n; | 533 | # if ENABLE_FEATURE_WGET_TIMEOUT |
534 | if (second_cnt != 0 && --second_cnt == 0) { | ||
535 | progress_meter(PROGRESS_END); | ||
536 | bb_error_msg_and_die("download timed out"); | ||
537 | } | ||
538 | # endif | ||
539 | /* We used to loop back to poll here, | ||
540 | * but there is no great harm in letting fread | ||
541 | * to try reading anyway. | ||
542 | */ | ||
543 | } | ||
544 | /* Need to do it _every_ second for "stalled" indicator | ||
545 | * to be shown properly. | ||
546 | */ | ||
540 | progress_meter(PROGRESS_BUMP); | 547 | progress_meter(PROGRESS_BUMP); |
541 | #endif | 548 | #endif |
542 | if (G.got_clen) { | 549 | } /* while (reading data) */ |
543 | G.content_len -= n; | 550 | |
544 | if (G.content_len == 0) | ||
545 | break; | ||
546 | } | ||
547 | } | ||
548 | #if ENABLE_FEATURE_WGET_STATUSBAR || ENABLE_FEATURE_WGET_TIMEOUT | 551 | #if ENABLE_FEATURE_WGET_STATUSBAR || ENABLE_FEATURE_WGET_TIMEOUT |
549 | clearerr(dfp); | 552 | clearerr(dfp); |
550 | ndelay_off(polldata.fd); /* else fgets can get very unhappy */ | 553 | ndelay_off(polldata.fd); /* else fgets can get very unhappy */ |
@@ -560,6 +563,13 @@ static void NOINLINE retrieve_file_data(FILE *dfp) | |||
560 | if (G.content_len == 0) | 563 | if (G.content_len == 0) |
561 | break; /* all done! */ | 564 | break; /* all done! */ |
562 | G.got_clen = 1; | 565 | G.got_clen = 1; |
566 | /* | ||
567 | * Note that fgets may result in some data being buffered in dfp. | ||
568 | * We loop back to fread, which will retrieve this data. | ||
569 | * Also note that code has to be arranged so that fread | ||
570 | * is done _before_ one-second poll wait - poll doesn't know | ||
571 | * about stdio buffering and can result in spurious one second waits! | ||
572 | */ | ||
563 | } | 573 | } |
564 | 574 | ||
565 | /* If -c failed, we restart from the beginning, | 575 | /* If -c failed, we restart from the beginning, |