IO.cc

Go to the documentation of this file.
00001 /*
00002  * IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. By
00003  * downloading, copying, installing or using the software you agree to
00004  * this license. If you do not agree to this license, do not download,
00005  * install, copy or use the software.
00006  * 
00007  * Intel Open Source License 
00008  * 
00009  * Copyright (c) 2004 Intel Corporation. All rights reserved. 
00010  * 
00011  * Redistribution and use in source and binary forms, with or without
00012  * modification, are permitted provided that the following conditions are
00013  * met:
00014  * 
00015  *   Redistributions of source code must retain the above copyright
00016  *   notice, this list of conditions and the following disclaimer.
00017  * 
00018  *   Redistributions in binary form must reproduce the above copyright
00019  *   notice, this list of conditions and the following disclaimer in the
00020  *   documentation and/or other materials provided with the distribution.
00021  * 
00022  *   Neither the name of the Intel Corporation nor the names of its
00023  *   contributors may be used to endorse or promote products derived from
00024  *   this software without specific prior written permission.
00025  *  
00026  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00027  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00028  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
00029  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE INTEL OR
00030  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
00031  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
00032  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
00033  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
00034  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00035  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
00036  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
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         // common case, all the bytes are gone on the first run
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         // consume the iovecs
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         // For safety
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; // already nonblocking
00619             goto done;
00620         }
00621         flags = flags | O_NONBLOCK;
00622     } else {
00623         if (!(flags & O_NONBLOCK)) {
00624             already = 1; // already blocking
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     // poll loop
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         // there's some strange bug in the poll emulation
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         // Always prioritize getting data before interrupt via notifier
00726 
00727         // XXX/demmer actually, to deal with the (rather unlikely)
00728         // case in which external IO events are generated faster than
00729         // the thread can service them, this can result in starving
00730         // the interrupt, which should instead take precedence, so the
00731         // order of the checks should be reversed. given the rarity of
00732         // this chance, it's a low priority item to fix
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         // We got notified
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; // Technically this is not an error with
00773                             // the IO, but there should be some kind
00774                             // of signal here that things are not
00775                             // right
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     } // while (true)
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 } // namespace oasys

Generated on Fri Dec 22 14:47:59 2006 for DTN Reference Implementation by  doxygen 1.5.1