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