|
8 | 8 | #include <unistd.h>
|
9 | 9 | #include <fcntl.h>
|
10 | 10 | #include <assert.h>
|
| 11 | +#ifndef WIN32 |
| 12 | +#include <poll.h> |
| 13 | +#include <limits.h> |
| 14 | +#endif |
11 | 15 | #include "memcached.h"
|
12 | 16 | #include "cproxy.h"
|
13 | 17 | #include "mcs.h"
|
|
16 | 20 | /* TODO: This timeout is inherited from zstored, but use it where? */
|
17 | 21 |
|
18 | 22 | #define DOWNSTREAM_DEFAULT_LINGER 1000
|
| 23 | +#ifndef INFTIM |
| 24 | +#define INFTIM -1 |
| 25 | +#endif |
19 | 26 |
|
20 | 27 | /* The lvb stands for libvbucket. */
|
21 | 28 |
|
@@ -584,6 +591,7 @@ ssize_t mcs_io_write(int fd, const void *buffer, size_t length) {
|
584 | 591 | return write(fd, buffer, length);
|
585 | 592 | }
|
586 | 593 |
|
| 594 | +#ifdef WIN32 |
587 | 595 | mcs_return mcs_io_read(int fd, void *dta, size_t size, struct timeval *timeout_in) {
|
588 | 596 | struct timeval my_timeout; /* Linux select() modifies its timeout param. */
|
589 | 597 | struct timeval *timeout = NULL;
|
@@ -626,6 +634,77 @@ mcs_return mcs_io_read(int fd, void *dta, size_t size, struct timeval *timeout_i
|
626 | 634 |
|
627 | 635 | return MCS_SUCCESS;
|
628 | 636 | }
|
| 637 | +#else |
| 638 | + |
| 639 | +static unsigned long long __get_time_ms(const struct timeval *tv) { |
| 640 | + struct timeval now; |
| 641 | + |
| 642 | + if (tv == NULL) { |
| 643 | + if (gettimeofday(&now, NULL) != 0) { |
| 644 | + return 0; |
| 645 | + } |
| 646 | + tv = &now; |
| 647 | + } |
| 648 | + return (unsigned long long)tv->tv_sec * 1000 + (unsigned long long)tv->tv_usec / 1000; |
| 649 | +} |
| 650 | + |
| 651 | +mcs_return mcs_io_read(int fd, void *dta, size_t size, struct timeval *timeout_in) { |
| 652 | + unsigned long long start_ms = 0; |
| 653 | + unsigned long long timeout_ms = 0; |
| 654 | + unsigned long long now_ms = 0; |
| 655 | + |
| 656 | + if (timeout_in != NULL) { |
| 657 | + start_ms = __get_time_ms(NULL); |
| 658 | + timeout_ms = __get_time_ms(timeout_in); |
| 659 | + now_ms = start_ms; |
| 660 | + } |
| 661 | + |
| 662 | + char *data = dta; |
| 663 | + size_t done = 0; |
| 664 | + struct pollfd pfd[1]; |
| 665 | + |
| 666 | + while (done < size) { |
| 667 | + pfd[0].fd = fd; |
| 668 | + pfd[0].events = POLLIN; |
| 669 | + pfd[0].revents = 0; |
| 670 | + |
| 671 | + int timeout = INFTIM; |
| 672 | + if (timeout_in != NULL) { |
| 673 | + if (timeout_ms == 0) { |
| 674 | + /* ensure we poll at least once */ |
| 675 | + timeout = 0; |
| 676 | + } else { |
| 677 | + unsigned long long taken_ms = now_ms - start_ms; |
| 678 | + if (taken_ms >= timeout_ms) { |
| 679 | + /* just check (boundary case) */ |
| 680 | + timeout = 0; |
| 681 | + } else { |
| 682 | + unsigned long long left_ms = timeout_ms - taken_ms; |
| 683 | + timeout = (left_ms > INT_MAX) ? INT_MAX : left_ms; |
| 684 | + } |
| 685 | + } |
| 686 | + } |
| 687 | + int s = poll(pfd, 1, timeout); |
| 688 | + if (s == 0) { |
| 689 | + return MCS_TIMEOUT; |
| 690 | + } |
| 691 | + |
| 692 | + if (s != 1 || (pfd[0].revents & (POLLERR|POLLHUP|POLLNVAL)) || !(pfd[0].revents & POLLIN)) { |
| 693 | + return MCS_FAILURE; |
| 694 | + } |
| 695 | + |
| 696 | + ssize_t n = read(fd, data + done, 1); |
| 697 | + if (n == -1 || n == 0) { |
| 698 | + return MCS_FAILURE; |
| 699 | + } |
| 700 | + |
| 701 | + done += (size_t) n; |
| 702 | + now_ms = __get_time_ms(NULL); |
| 703 | + } |
| 704 | + |
| 705 | + return MCS_SUCCESS; |
| 706 | +} |
| 707 | +#endif |
629 | 708 |
|
630 | 709 | void mcs_io_reset(int fd) {
|
631 | 710 | (void) fd;
|
|
0 commit comments