IO.cc

Go to the documentation of this file.
00001 /*
00002  *    Copyright 2004-2006 Intel Corporation
00003  * 
00004  *    Licensed under the Apache License, Version 2.0 (the "License");
00005  *    you may not use this file except in compliance with the License.
00006  *    You may obtain a copy of the License at
00007  * 
00008  *        http://www.apache.org/licenses/LICENSE-2.0
00009  * 
00010  *    Unless required by applicable law or agreed to in writing, software
00011  *    distributed under the License is distributed on an "AS IS" BASIS,
00012  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00013  *    See the License for the specific language governing permissions and
00014  *    limitations under the License.
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         // common case, all the bytes are gone on the first run
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         // consume the iovecs
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         // For safety
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; // already nonblocking
00598             goto done;
00599         }
00600         flags = flags | O_NONBLOCK;
00601     } else {
00602         if (!(flags & O_NONBLOCK)) {
00603             already = 1; // already blocking
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     // poll loop
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         // there's some strange bug in the poll emulation
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         // Always prioritize getting data before interrupt via notifier
00705 
00706         // XXX/demmer actually, to deal with the (rather unlikely)
00707         // case in which external IO events are generated faster than
00708         // the thread can service them, this can result in starving
00709         // the interrupt, which should instead take precedence, so the
00710         // order of the checks should be reversed. given the rarity of
00711         // this chance, it's a low priority item to fix
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         // We got notified
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; // Technically this is not an error with
00752                             // the IO, but there should be some kind
00753                             // of signal here that things are not
00754                             // right
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     } // while (true)
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             // XXX/demmer this is a strange case since we may have
00930             // actually read/written some amount before getting the
00931             // eof... 
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 } // namespace oasys

Generated on Thu Jun 7 12:54:27 2007 for DTN Reference Implementation by  doxygen 1.5.1