00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018 #include <errno.h>
00019 #include <stdlib.h>
00020 #include <sys/poll.h>
00021 #include <sys/types.h>
00022 #include <sys/fcntl.h>
00023
00024 #include "IO.h"
00025
00026 #include "debug/Log.h"
00027 #include "util/ScratchBuffer.h"
00028 #include "util/StringBuffer.h"
00029 #include "thread/Notifier.h"
00030
00031 namespace oasys {
00032
00033
00036 class COWIoVec {
00037 public:
00038 COWIoVec(const struct iovec* iov, int iovcnt)
00039 : iov_(const_cast<struct iovec*>(iov)),
00040 iovcnt_(iovcnt),
00041 bytes_left_(0),
00042 copied_(false),
00043 dynamic_iov_(0)
00044 {
00045 for (int i=0; i<iovcnt_; ++i) {
00046 bytes_left_ += iov_[i].iov_len;
00047 }
00048 }
00049
00050 ~COWIoVec() {
00051 if (dynamic_iov_ != 0) {
00052 free(iov_);
00053 dynamic_iov_ = 0;
00054 }
00055 }
00056
00060 void consume(size_t cc) {
00061 ASSERT(bytes_left_ >= cc);
00062
00063
00064 if (!copied_ && cc == bytes_left_) {
00065 iov_ = 0;
00066 bytes_left_ = 0;
00067 return;
00068 }
00069
00070 if (!copied_) {
00071 copy();
00072 }
00073
00074
00075 bytes_left_ -= cc;
00076 while (cc > 0) {
00077 ASSERT(iovcnt_ > 0);
00078
00079 if (iov_[0].iov_len <= cc) {
00080 cc -= iov_[0].iov_len;
00081 --iovcnt_;
00082 ++iov_;
00083 } else {
00084 iov_[0].iov_base = reinterpret_cast<char*>
00085 (iov_[0].iov_base) + cc;
00086 iov_[0].iov_len -= cc;
00087 cc = 0;
00088 break;
00089 }
00090 }
00091
00092
00093 if (bytes_left_ == 0) {
00094 iov_ = 0;
00095 }
00096 }
00097
00098 void copy() {
00099 ASSERT(!copied_);
00100
00101 copied_ = true;
00102 if (iovcnt_ <= 16) {
00103 memcpy(static_iov_, iov_,
00104 iovcnt_ * sizeof(struct iovec));
00105 iov_ = static_iov_;
00106 } else {
00107 dynamic_iov_ = static_cast<struct iovec*>
00108 (malloc(iovcnt_ * sizeof(struct iovec)));
00109 memcpy(dynamic_iov_, iov_, iovcnt_* sizeof(struct iovec));
00110 iov_ = dynamic_iov_;
00111 }
00112 }
00113
00114 const struct iovec* iov() { return iov_; }
00115 int iovcnt() { return iovcnt_; }
00116 size_t bytes_left() { return bytes_left_; }
00117
00118 private:
00119 struct iovec* iov_;
00120 int iovcnt_;
00121 size_t bytes_left_;
00122
00123 bool copied_;
00124 struct iovec static_iov_[16];
00125 struct iovec* dynamic_iov_;
00126 };
00127
00128
00129 const char*
00130 IO::ioerr2str(int err)
00131 {
00132 switch (err) {
00133 case IOEOF: return "eof";
00134 case IOERROR: return "error";
00135 case IOTIMEOUT: return "timeout";
00136 case IOINTR: return "intr";
00137 }
00138
00139 NOTREACHED;
00140 }
00141
00142
00143 int
00144 IO::open(const char* path, int flags, int* errnop, const char* log)
00145 {
00146 int fd = ::open(path, flags);
00147 if (errnop) *errnop = errno;
00148
00149 if (log) {
00150 logf(log, LOG_DEBUG, "open %s (flags 0x%x): fd %d", path, flags, fd);
00151 }
00152 return fd;
00153 }
00154
00155
00156 int
00157 IO::open(const char* path, int flags, mode_t mode,
00158 int* errnop, const char* log)
00159 {
00160 int fd = ::open(path, flags, mode);
00161 if (errnop) *errnop = errno;
00162
00163 if (log) {
00164 logf(log, LOG_DEBUG, "open %s (flags 0x%x mode 0x%x): fd %d",
00165 path, flags, (u_int)mode, fd);
00166 }
00167 return fd;
00168 }
00169
00170
00171 int
00172 IO::close(int fd, const char* log, const char* filename)
00173 {
00174 int ret = ::close(fd);
00175 if (log) {
00176 logf(log, LOG_DEBUG, "close %s fd %d: %d", filename, fd, ret);
00177 }
00178 return ret;
00179 }
00180
00181
00182 int
00183 IO::unlink(const char* path, const char* log)
00184 {
00185 int ret = ::unlink(path);
00186 if (log) {
00187 logf(log, LOG_DEBUG, "unlink %s: %d", path, ret);
00188 }
00189
00190 return ret;
00191 }
00192
00193
00194 int
00195 IO::lseek(int fd, off_t offset, int whence, const char* log)
00196 {
00197 int cc = ::lseek(fd, offset, whence);
00198 if (log) {
00199 logf(log, LOG_DEBUG, "lseek %lu %s -> %d",
00200 (long unsigned int)offset,
00201 (whence == SEEK_SET) ? "SEEK_SET" :
00202 (whence == SEEK_CUR) ? "SEEK_CUR" :
00203 (whence == SEEK_END) ? "SEEK_END" :
00204 "SEEK_INVALID",
00205 cc);
00206 }
00207
00208 return cc;
00209 }
00210
00211
00212 int
00213 IO::truncate(int fd, off_t length, const char* log)
00214 {
00215 int ret = ftruncate(fd, length);
00216 if (log) {
00217 logf(log, LOG_DEBUG, "truncate %lu: %d", (long unsigned int)length, ret);
00218 }
00219
00220 return ret;
00221 }
00222
00223
00224 int
00225 IO::mkstemp(char* templ, const char* log)
00226 {
00227 int ret = ::mkstemp(templ);
00228 if (log) {
00229 logf(log, LOG_DEBUG, "mkstemp %s: %d", templ, ret);
00230 }
00231
00232 return ret;
00233 }
00234
00235
00236 int
00237 IO::stat(const char* path, struct stat* buf, const char* log)
00238 {
00239 int ret = ::stat(path, buf);
00240 if (log) {
00241 logf(log, LOG_DEBUG, "stat %s: %d", path, ret);
00242 }
00243
00244 return ret;
00245 }
00246
00247
00248 int
00249 IO::lstat(const char* path, struct stat* buf, const char* log)
00250 {
00251 int ret = ::lstat(path, buf);
00252 if (log) {
00253 logf(log, LOG_DEBUG, "stat %s: %d", path, ret);
00254 }
00255
00256 return ret;
00257 }
00258
00259
00260 int
00261 IO::read(int fd, char* bp, size_t len,
00262 Notifier* intr, const char* log)
00263 {
00264 struct iovec iov;
00265 iov.iov_base = bp;
00266 iov.iov_len = len;
00267 return rwdata(READV, fd, &iov, 1, 0, -1, 0, 0, intr, false, log);
00268 }
00269
00270
00271 int
00272 IO::readv(int fd, const struct iovec* iov, int iovcnt,
00273 Notifier* intr, const char* log)
00274 {
00275 return rwdata(READV, fd, iov, iovcnt, 0, -1, 0, 0, intr, false, log);
00276 }
00277
00278
00279 int
00280 IO::readall(int fd, char* bp, size_t len,
00281 Notifier* intr, const char* log)
00282 {
00283 struct iovec iov;
00284 iov.iov_base = bp;
00285 iov.iov_len = len;
00286
00287 return rwvall(READV, fd, &iov, 1, -1, 0, intr, "readall", log);
00288 }
00289
00290
00291 int
00292 IO::readvall(int fd, const struct iovec* iov, int iovcnt,
00293 Notifier* intr, const char* log)
00294 {
00295 return rwvall(READV, fd, iov, iovcnt, -1, 0, intr, "readvall", log);
00296 }
00297
00298
00299
00300 int
00301 IO::timeout_read(int fd, char* bp, size_t len, int timeout_ms,
00302 Notifier* intr, const char* log)
00303 {
00304 struct iovec iov;
00305 iov.iov_base = bp;
00306 iov.iov_len = len;
00307
00308 struct timeval start;
00309 gettimeofday(&start, 0);
00310
00311 return rwdata(READV, fd, &iov, 1, 0, timeout_ms, 0,
00312 &start, intr, false, log);
00313 }
00314
00315
00316 int
00317 IO::timeout_readv(int fd, const struct iovec* iov, int iovcnt, int timeout_ms,
00318 Notifier* intr, const char* log)
00319 {
00320 struct timeval start;
00321 gettimeofday(&start, 0);
00322
00323 return rwdata(READV, fd, iov, iovcnt, 0, timeout_ms, 0,
00324 &start, intr, false, log);
00325 }
00326
00327
00328 int
00329 IO::timeout_readall(int fd, char* bp, size_t len, int timeout_ms,
00330 Notifier* intr, const char* log)
00331 {
00332 struct iovec iov;
00333 iov.iov_base = bp;
00334 iov.iov_len = len;
00335
00336 struct timeval start;
00337 gettimeofday(&start, 0);
00338
00339 return rwvall(READV, fd, &iov, 1, timeout_ms, &start,
00340 intr, "timeout_readall", log);
00341 }
00342
00343
00344 int
00345 IO::timeout_readvall(int fd, const struct iovec* iov, int iovcnt,
00346 int timeout_ms, Notifier* intr, const char* log)
00347 {
00348 struct timeval start;
00349 gettimeofday(&start, 0);
00350
00351 return rwvall(READV, fd, iov, iovcnt, timeout_ms, &start, intr,
00352 "timeout_readvall", log);
00353 }
00354
00355
00356 int
00357 IO::recv(int fd, char* bp, size_t len, int flags,
00358 Notifier* intr, const char* log)
00359 {
00360 struct iovec iov;
00361 iov.iov_base = bp;
00362 iov.iov_len = len;
00363 return rwdata(RECV, fd, &iov, 1, flags, -1, 0, 0, intr, false, log);
00364 }
00365
00366
00367 int
00368 IO::recvfrom(int fd, char* bp, size_t len, int flags,
00369 struct sockaddr* from, socklen_t* fromlen,
00370 Notifier* intr, const char* log)
00371 {
00372 struct iovec iov;
00373 iov.iov_base = bp;
00374 iov.iov_len = len;
00375
00376 RwDataExtraArgs args;
00377 args.recvfrom.from = from;
00378 args.recvfrom.fromlen = fromlen;
00379 return rwdata(RECVFROM, fd, &iov, 1, flags, -1, &args, 0, intr,
00380 false, log);
00381 }
00382
00383
00384 int
00385 IO::recvmsg(int fd, struct msghdr* msg, int flags,
00386 Notifier* intr, const char* log)
00387 {
00388 RwDataExtraArgs args;
00389 args.msg_hdr = msg;
00390 return rwdata(RECVMSG, fd, 0, 0, flags, -1, &args, 0,
00391 intr, false, log);
00392 }
00393
00394
00395
00396 int
00397 IO::write(int fd, const char* bp, size_t len,
00398 Notifier* intr, const char* log)
00399 {
00400 struct iovec iov;
00401 iov.iov_base = const_cast<char*>(bp);
00402 iov.iov_len = len;
00403 return rwdata(WRITEV, fd, &iov, 1, 0, -1, 0, 0,
00404 intr, false, log);
00405 }
00406
00407
00408 int
00409 IO::writev(int fd, const struct iovec* iov, int iovcnt,
00410 Notifier* intr, const char* log)
00411 {
00412 return rwdata(WRITEV, fd, iov, iovcnt, 0, -1, 0, 0,
00413 intr, false, log);
00414 }
00415
00416
00417 int
00418 IO::writeall(int fd, const char* bp, size_t len,
00419 Notifier* intr, const char* log)
00420 {
00421 struct iovec iov;
00422 iov.iov_base = const_cast<char*>(bp);
00423 iov.iov_len = len;
00424
00425 return rwvall(WRITEV, fd, &iov, 1, -1, 0, intr, "writeall", log);
00426 }
00427
00428
00429 int
00430 IO::writevall(int fd, const struct iovec* iov, int iovcnt,
00431 Notifier* intr, const char* log)
00432 {
00433 return rwvall(WRITEV, fd, iov, iovcnt, -1, 0, intr, "writevall", log);
00434 }
00435
00436
00437 int
00438 IO::timeout_write(int fd, const char* bp, size_t len, int timeout_ms,
00439 Notifier* intr, const char* log)
00440 {
00441 struct iovec iov;
00442 iov.iov_base = const_cast<char*>(bp);
00443 iov.iov_len = len;
00444 return rwdata(WRITEV, fd, &iov, 1, 0, timeout_ms, 0, 0,
00445 intr, false, log);
00446 }
00447
00448
00449 int
00450 IO::timeout_writev(int fd, const struct iovec* iov, int iovcnt, int timeout_ms,
00451 Notifier* intr, const char* log)
00452 {
00453 return rwdata(WRITEV, fd, iov, iovcnt, 0, timeout_ms, 0, 0,
00454 intr, false, log);
00455 }
00456
00457
00458 int
00459 IO::timeout_writeall(int fd, const char* bp, size_t len, int timeout_ms,
00460 Notifier* intr, const char* log)
00461 {
00462 struct iovec iov;
00463 iov.iov_base = const_cast<char*>(bp);
00464 iov.iov_len = len;
00465
00466 struct timeval start;
00467 gettimeofday(&start, 0);
00468
00469 return rwvall(WRITEV, fd, &iov, 1, timeout_ms, &start, intr,
00470 "timeout_writeall", log);
00471 }
00472
00473
00474 int
00475 IO::timeout_writevall(int fd, const struct iovec* iov, int iovcnt,
00476 int timeout_ms, Notifier* intr, const char* log)
00477 {
00478 struct timeval start;
00479 gettimeofday(&start, 0);
00480
00481 return rwvall(WRITEV, fd, iov, iovcnt, timeout_ms, &start, intr,
00482 "timeout_writevall", log);
00483 }
00484
00485
00486 int
00487 IO::send(int fd, const char* bp, size_t len, int flags,
00488 Notifier* intr, const char* log)
00489 {
00490 struct iovec iov;
00491 iov.iov_base = const_cast<char*>(bp);
00492 iov.iov_len = len;
00493 return rwdata(SEND, fd, &iov, 1, flags, -1, 0, 0, intr, false, log);
00494 }
00495
00496
00497 int
00498 IO::sendto(int fd, char* bp, size_t len, int flags,
00499 const struct sockaddr* to, socklen_t tolen,
00500 Notifier* intr, const char* log)
00501 {
00502 struct iovec iov;
00503 iov.iov_base = bp;
00504 iov.iov_len = len;
00505
00506 RwDataExtraArgs args;
00507 args.sendto.to = to;
00508 args.sendto.tolen = tolen;
00509
00510 return rwdata(SENDTO, fd, &iov, 1, flags, -1, &args, 0,
00511 intr, false, log);
00512 }
00513
00514
00515 int
00516 IO::sendmsg(int fd, const struct msghdr* msg, int flags,
00517 Notifier* intr, const char* log)
00518 {
00519 RwDataExtraArgs args;
00520 args.msg_hdr = msg;
00521
00522 return rwdata(SENDMSG, fd, 0, 0, flags, -1, &args, 0,
00523 intr, false, log);
00524 }
00525
00526
00527 int
00528 IO::poll_single(int fd, short events, short* revents, int timeout_ms,
00529 Notifier* intr, const char* log)
00530 {
00531 struct pollfd fds;
00532 fds.fd = fd;
00533 fds.events = events;
00534
00535 int cc = poll_multiple(&fds, 1, timeout_ms, intr, log);
00536 if (revents != 0) {
00537 *revents = fds.revents;
00538 }
00539
00540 return cc;
00541 }
00542
00543
00544 int
00545 IO::poll_multiple(struct pollfd* fds, int nfds, int timeout_ms,
00546 Notifier* intr, const char* log)
00547 {
00548 struct timeval start;
00549 if (timeout_ms > 0) {
00550 gettimeofday(&start, 0);
00551 }
00552
00553 int cc = poll_with_notifier(intr, fds, nfds, timeout_ms,
00554 (timeout_ms > 0) ? &start : 0, log);
00555 ASSERT(cc != 0);
00556 if (cc > 0) {
00557 return cc;
00558 } else {
00559 return cc;
00560 }
00561 }
00562
00563
00564 int
00565 IO::get_nonblocking(int fd, bool *nonblockingp, const char* log)
00566 {
00567 int flags = 0;
00568 ASSERT(nonblockingp);
00569
00570 if ((flags = fcntl(fd, F_GETFL)) < 0) {
00571 if (log) log_debug_p(log, "get_nonblocking: fcntl GETFL err %s",
00572 strerror(errno));
00573 return -1;
00574 }
00575
00576 *nonblockingp = (flags & O_NONBLOCK);
00577 if (log) log_debug_p(log, "get_nonblocking: %s mode",
00578 *nonblockingp ? "nonblocking" : "blocking");
00579 return 0;
00580 }
00581
00582
00583 int
00584 IO::set_nonblocking(int fd, bool nonblocking, const char* log)
00585 {
00586 int flags = 0;
00587 bool already = 0;
00588
00589 if ((flags = fcntl(fd, F_GETFL)) < 0) {
00590 if (log) log_debug_p(log, "set_nonblocking: fcntl GETFL err %s",
00591 strerror(errno));
00592 return -1;
00593 }
00594
00595 if (nonblocking) {
00596 if (flags & O_NONBLOCK) {
00597 already = 1;
00598 goto done;
00599 }
00600 flags = flags | O_NONBLOCK;
00601 } else {
00602 if (!(flags & O_NONBLOCK)) {
00603 already = 1;
00604 goto done;
00605 }
00606
00607 flags = flags & ~O_NONBLOCK;
00608 }
00609
00610 if (fcntl(fd, F_SETFL, flags) < 0) {
00611 if (log) log_debug_p(log, "set_nonblocking: fcntl SETFL err %s",
00612 strerror(errno));
00613 return -1;
00614 }
00615
00616 done:
00617 if (log) log_debug_p(log, "set_nonblocking: %s mode %s",
00618 nonblocking ? "nonblocking" : "blocking",
00619 already ? "already set" : "set");
00620 return 0;
00621 }
00622
00623
00624 int
00625 IO::poll_with_notifier(
00626 Notifier* intr,
00627 struct pollfd* fds,
00628 size_t nfds,
00629 int timeout,
00630 const struct timeval* start_time,
00631 const char* log
00632 )
00633 {
00634 ASSERT(! (timeout > 0 && start_time == 0));
00635 ASSERT(timeout >= -1);
00636
00637 oasys::ScratchBuffer<struct pollfd*,
00638 16 * sizeof(struct pollfd)> intr_poll_set;
00639 struct pollfd* poll_set;
00640
00641 if (intr == 0) {
00642 poll_set = fds;
00643 } else {
00644 intr_poll_set.buf(sizeof(struct pollfd) * (nfds + 1));
00645 poll_set = intr_poll_set.buf();
00646
00647 for (size_t i=0; i<nfds; ++i) {
00648 poll_set[i].fd = fds[i].fd;
00649 poll_set[i].events = fds[i].events;
00650 poll_set[i].revents = 0;
00651 }
00652 poll_set[nfds].fd = intr->read_fd();
00653 poll_set[nfds].events = POLLIN | POLLPRI | POLLERR;
00654 ++nfds;
00655 }
00656
00657
00658 retry:
00659 int cc = ::poll(poll_set, nfds, timeout);
00660 if (cc < 0 && errno == EINTR) {
00661 if (timeout > 0) {
00662 timeout = adjust_timeout(timeout, start_time);
00663 }
00664 goto retry;
00665 }
00666
00667 if (cc < 0)
00668 {
00669 return IOERROR;
00670 }
00671 else if (cc == 0)
00672 {
00673 if (log) {
00674 log_debug_p(log, "poll_with_notifier timed out");
00675 }
00676 return IOTIMEOUT;
00677 }
00678 else
00679 {
00680 #ifdef __APPLE__
00681
00682 if (cc > (int)nfds) {
00683 if (log) {
00684 log_warn_p(log,
00685 "poll_with_notifier: returned bogus high value %d, "
00686 "capping to %zu", cc, nfds);
00687 }
00688 cc = nfds;
00689 }
00690 #endif
00691
00692 if (log)
00693 {
00694 StringBuffer buf;
00695 for (size_t i=0; i<nfds; ++i)
00696 {
00697 buf.appendf("0x%hx ", poll_set[i].revents);
00698 }
00699 log_debug_p(log,
00700 "poll_with_notifier: %d/%zu fds ready, status %s",
00701 cc, nfds, buf.c_str());
00702 }
00703
00704
00705
00706
00707
00708
00709
00710
00711
00712
00713 bool got_event = false;
00714 for (size_t i=0; i<((intr != 0) ? (nfds - 1) : nfds); ++i)
00715 {
00716 if (poll_set[i].revents &
00717 (poll_set[i].events | POLLERR | POLLHUP | POLLNVAL))
00718 {
00719 got_event = true;
00720 fds[i].revents = poll_set[i].revents;
00721 }
00722 }
00723
00724 ASSERT(! (intr == 0 && !got_event));
00725 if (got_event) {
00726 if (log) {
00727 logf(log, LOG_DEBUG,
00728 "poll_with_notifier: normal fd has event");
00729 }
00730
00731 if (intr != 0 && (poll_set[nfds - 1].revents &
00732 (POLLIN | POLLPRI | POLLERR)) )
00733 {
00734 ASSERT(cc > 1);
00735 return cc - 1;
00736 }
00737 else
00738 {
00739 return cc;
00740 }
00741 }
00742
00743
00744 if (intr != 0 && (poll_set[nfds - 1].revents & POLLERR))
00745 {
00746 if (log) {
00747 log_debug_p(log,
00748 "poll_with_notifier: error in notifier fd!");
00749 }
00750
00751 return IOERROR;
00752
00753
00754
00755 }
00756 else if (intr != 0 &&
00757 (poll_set[nfds - 1].revents & (POLLIN | POLLPRI)) )
00758 {
00759 if (log) {
00760 log_debug_p(log, "poll_with_notifier: interrupted");
00761 }
00762 intr->drain_pipe(1);
00763
00764 return IOINTR;
00765 }
00766
00767 PANIC("poll_with_notifier: should not have left poll");
00768 }
00769
00770 NOTREACHED;
00771 }
00772
00773
00774 int
00775 IO::rwdata(
00776 IO_Op_t op,
00777 int fd,
00778 const struct iovec* iov,
00779 int iovcnt,
00780 int flags,
00781 int timeout,
00782 RwDataExtraArgs* args,
00783 const struct timeval* start_time,
00784 Notifier* intr,
00785 bool ignore_eagain,
00786 const char* log
00787 )
00788 {
00789 ASSERT(! ((op == READV || op == WRITEV) &&
00790 (iov == 0 || flags != 0 || args != 0)));
00791 ASSERT(! ((op == RECV || op == SEND) &&
00792 (iovcnt != 1 | args != 0)));
00793 ASSERT(! ((op == RECVFROM || op == SENDTO) &&
00794 (iovcnt != 1 || args == 0)));
00795 ASSERT(! ((op == RECVMSG || op == SENDMSG) &&
00796 (iov != 0 && args == 0)));
00797 ASSERT(timeout >= -1);
00798 ASSERT(! (timeout > -1 && start_time == 0));
00799
00800 struct pollfd poll_fd;
00801 poll_fd.fd = fd;
00802 switch (op) {
00803 case READV: case RECV: case RECVFROM: case RECVMSG:
00804 poll_fd.events = POLLIN | POLLPRI;
00805 break;
00806 case WRITEV: case SEND: case SENDTO: case SENDMSG:
00807 poll_fd.events = POLLOUT;
00808 break;
00809 default:
00810 PANIC("Unknown IO type");
00811 }
00812
00813 int cc;
00814 while (true)
00815 {
00816 if (intr || timeout > -1) {
00817 cc = poll_with_notifier(intr, &poll_fd, 1, timeout,
00818 start_time, log);
00819 if (cc == IOERROR || cc == IOTIMEOUT || cc == IOINTR) {
00820 return cc;
00821 }
00822 }
00823
00824 switch (op) {
00825 case READV:
00826 cc = ::readv(fd, iov, iovcnt);
00827 if (log) log_debug_p(log, "::readv() fd %d cc %d", fd, cc);
00828 break;
00829 case RECV:
00830 cc = ::recv(fd, iov[0].iov_base, iov[0].iov_len, flags);
00831 if (log) log_debug_p(log, "::recv() fd %d %p/%zu cc %d",
00832 fd, iov[0].iov_base, iov[0].iov_len, cc);
00833 break;
00834 case RECVFROM:
00835 cc = ::recvfrom(fd, iov[0].iov_base, iov[0].iov_len, flags,
00836 args->recvfrom.from,
00837 args->recvfrom.fromlen);
00838 if (log) log_debug_p(log, "::recvfrom() fd %d %p/%zu cc %d",
00839 fd, iov[0].iov_base, iov[0].iov_len, cc);
00840 break;
00841 case RECVMSG:
00842 cc = ::sendmsg(fd, args->msg_hdr, flags);
00843 if (log) log_debug_p(log, "::recvmsg() fd %d %p cc %d",
00844 fd, args->msg_hdr, cc);
00845 break;
00846 case WRITEV:
00847 cc = ::writev(fd, iov, iovcnt);
00848 if (log) log_debug_p(log, "::writev() fd %d cc %d", fd, cc);
00849 break;
00850 case SEND:
00851 cc = ::send(fd, iov[0].iov_base, iov[0].iov_len, flags);
00852 if (log) log_debug_p(log, "::send() fd %d %p/%zu cc %d",
00853 fd, iov[0].iov_base, iov[0].iov_len, cc);
00854 break;
00855 case SENDTO:
00856 cc = ::sendto(fd, iov[0].iov_base, iov[0].iov_len, flags,
00857 args->sendto.to, args->sendto.tolen);
00858 if (log) log_debug_p(log, "::sendto() fd %d %p/%zu cc %d",
00859 fd, iov[0].iov_base, iov[0].iov_len, cc);
00860 break;
00861 case SENDMSG:
00862 cc = ::sendmsg(fd, args->msg_hdr, flags);
00863 if (log) log_debug_p(log, "::sendmsg() fd %d %p cc %d",
00864 fd, args->msg_hdr, cc);
00865 break;
00866 default:
00867 PANIC("Unknown IO type");
00868 }
00869
00870 if (cc < 0 &&
00871 ( (errno == EAGAIN && ignore_eagain) || errno == EINTR) )
00872 {
00873 if (timeout > 0) {
00874 timeout = adjust_timeout(timeout, start_time);
00875 }
00876 continue;
00877 }
00878
00879 if (cc < 0) {
00880 if (errno == EAGAIN) {
00881 return IOAGAIN;
00882 } else {
00883 return IOERROR;
00884 }
00885 } else if (cc == 0) {
00886 return IOEOF;
00887 } else {
00888 return cc;
00889 }
00890 }
00891
00892 NOTREACHED;
00893 }
00894
00895
00896 int
00897 IO::rwvall(
00898 IO_Op_t op,
00899 int fd,
00900 const struct iovec* iov,
00901 int iovcnt,
00902 int timeout,
00903 const struct timeval* start,
00904 Notifier* intr,
00905 const char* fcn_name,
00906 const char* log
00907 )
00908 {
00909 (void)fcn_name;
00910 ASSERT(op == READV || op == WRITEV);
00911 ASSERT(! (timeout != -1 && start == 0));
00912
00913 COWIoVec cow_iov(iov, iovcnt);
00914 int total_bytes = cow_iov.bytes_left();
00915
00916 while (cow_iov.bytes_left() > 0) {
00917 int cc = rwdata(op, fd, cow_iov.iov(), cow_iov.iovcnt(),
00918 0, timeout, 0, start, intr, true, log);
00919 if (cc < 0) {
00920 if (log && cc != IOTIMEOUT && cc != IOINTR) {
00921 log_debug_p(log, "%s %s %s",
00922 fcn_name, ioerr2str(cc), strerror(errno));
00923 }
00924 return cc;
00925 } else if (cc == 0) {
00926 if (log) {
00927 log_debug_p(log, "%s eof", fcn_name);
00928 }
00929
00930
00931
00932 return IOEOF;
00933 } else {
00934 cow_iov.consume(cc);
00935 if (log) {
00936 log_debug_p(log, "%s %d bytes %zu left %d total",
00937 fcn_name, cc, cow_iov.bytes_left(), total_bytes);
00938 }
00939
00940 if (timeout > 0) {
00941 timeout = adjust_timeout(timeout, start);
00942 }
00943 }
00944 }
00945
00946 return total_bytes;
00947 }
00948
00949
00950 int
00951 IO::adjust_timeout(int timeout, const struct timeval* start)
00952 {
00953 struct timeval now;
00954 int err = gettimeofday(&now, 0);
00955 ASSERT(err == 0);
00956
00957 now.tv_sec -= start->tv_sec;
00958 now.tv_usec -= start->tv_usec;
00959 timeout -= now.tv_sec * 1000 + now.tv_usec / 1000;
00960 if (timeout < 0) {
00961 timeout = 0;
00962 }
00963
00964 return timeout;
00965 }
00966
00967 }