FileHandleImplUNIX.cpp

Go to the documentation of this file.
00001 /****************** <VPR heading BEGIN do not edit this line> *****************
00002  *
00003  * VR Juggler Portable Runtime
00004  *
00005  * Original Authors:
00006  *   Allen Bierbaum, Patrick Hartling, Kevin Meinert, Carolina Cruz-Neira
00007  *
00008  * -----------------------------------------------------------------
00009  * File:          $RCSfile$
00010  * Date modified: $Date: 2005-01-17 22:34:01 -0600 (Mon, 17 Jan 2005) $
00011  * Version:       $Revision: 16635 $
00012  * -----------------------------------------------------------------
00013  *
00014  ****************** <VPR heading END do not edit this line> ******************/
00015 
00016 /*************** <auto-copyright.pl BEGIN do not edit this line> **************
00017  *
00018  * VR Juggler is (C) Copyright 1998-2005 by Iowa State University
00019  *
00020  * Original Authors:
00021  *   Allen Bierbaum, Christopher Just,
00022  *   Patrick Hartling, Kevin Meinert,
00023  *   Carolina Cruz-Neira, Albert Baker
00024  *
00025  * This library is free software; you can redistribute it and/or
00026  * modify it under the terms of the GNU Library General Public
00027  * License as published by the Free Software Foundation; either
00028  * version 2 of the License, or (at your option) any later version.
00029  *
00030  * This library is distributed in the hope that it will be useful,
00031  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00032  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00033  * Library General Public License for more details.
00034  *
00035  * You should have received a copy of the GNU Library General Public
00036  * License along with this library; if not, write to the
00037  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
00038  * Boston, MA 02111-1307, USA.
00039  *
00040  *************** <auto-copyright.pl END do not edit this line> ***************/
00041 
00042 #include <vpr/vprConfig.h>
00043 
00044 #include <stdio.h>
00045 #include <string.h>
00046 #include <unistd.h>
00047 #include <sys/types.h>
00048 #include <sys/stat.h>
00049 #include <fcntl.h>
00050 
00051 // Enable BSD compatibility in sys/ioctl.h on Solaris.
00052 #ifdef VPR_OS_Solaris
00053 #  define BSD_COMP
00054 #endif
00055 
00056 #include <sys/ioctl.h>
00057 #include <sys/time.h>
00058 #include <unistd.h>
00059 #include <errno.h>
00060 
00061 #ifdef HAVE_SYS_FILE_H
00062 #  include <sys/file.h>
00063 #endif
00064 
00065 #include <vpr/Util/Debug.h>
00066 #include <vpr/md/POSIX/IO/FileHandleImplUNIX.h>
00067 
00068 
00069 namespace vpr
00070 {
00071 
00072 // ============================================================================
00073 // Public methods.
00074 // ============================================================================
00075 
00076 // Constructor for unnamed file-based devices.  This initializes the member
00077 // variables to reasonable defaults and stores the given file name for
00078 // later use.
00079 FileHandleImplUNIX::FileHandleImplUNIX()
00080    : mOpen(false)
00081    , mOpenBlocking(true)
00082    , mBlocking(true)
00083    , mFdesc(-1)
00084    , mOpenMode(O_RDWR)
00085 {
00086    /* Do nothing. */ ;
00087 }
00088 
00089 // Constructor.  This initializes the member variables to reasonable defaults
00090 // and stores the given file name for later use.
00091 FileHandleImplUNIX::FileHandleImplUNIX(const std::string& file_name)
00092    : mName(file_name)
00093    , mOpen(false)
00094    , mOpenBlocking(true)
00095    , mBlocking(true)
00096    , mFdesc(-1)
00097    , mOpenMode(O_RDWR)
00098 {
00099    /* Do nothing. */ ;
00100 }
00101 
00102 // Destructor.  If the file handle is in an open state, it is closed.
00103 FileHandleImplUNIX::~FileHandleImplUNIX()
00104 {
00105    if ( mOpen )
00106    {
00107       close();
00108    }
00109 }
00110 
00111 // Open the file handle.
00112 vpr::ReturnStatus FileHandleImplUNIX::open()
00113 {
00114    vpr::ReturnStatus status;
00115 
00116    int open_flags(mOpenMode);
00117 
00118    if ( ! mOpenBlocking )
00119    {
00120       open_flags |= O_NONBLOCK;
00121    }
00122 
00123    mFdesc = ::open(mName.c_str(), open_flags);
00124 
00125    // If the file handle was not returned successfully, print an error
00126    // message explaining why.
00127    if ( mFdesc == -1 )
00128    {
00129       // If we are opening in non-blocking mode, we do not want to bomb out.
00130       if ( errno == EWOULDBLOCK && ! mOpenBlocking )
00131       {
00132          status.setCode(vpr::ReturnStatus::WouldBlock);
00133          mOpen = true;
00134       }
00135       // Otherwise, report the error.
00136       else
00137       {
00138          vprDEBUG(vprDBG_ERROR, vprDBG_CRITICAL_LVL)
00139             << "[vpr::FileHandleImplUNIX::open()] Could not open " << mName
00140             << ": " << strerror(errno) << std::endl << vprDEBUG_FLUSH;
00141          status.setCode(ReturnStatus::Fail);
00142          mOpen = false;
00143       }
00144    }
00145    // Otherwise, set mOpen to true.
00146    else
00147    {
00148       mOpen     = true;
00149       mBlocking = mOpenBlocking;
00150    }
00151 
00152    return status;
00153 }
00154 
00155 // Close the file handle.
00156 vpr::ReturnStatus FileHandleImplUNIX::close()
00157 {
00158    vpr::ReturnStatus status;
00159 
00160    vprDEBUG(vprDBG_ALL, vprDBG_VERB_LVL)
00161       << "[vpr::FileHandleImplUNIX::close()] Closing file descriptor "
00162       << mFdesc << std::endl << vprDEBUG_FLUSH;
00163 
00164    if ( ::close(mFdesc) == -1 )
00165    {
00166       vprDEBUG(vprDBG_ALL, vprDBG_WARNING_LVL)
00167          << "[vpr::FileHandleImplUNIX::close()] Could not close " << mName
00168          << ": " << strerror(errno) << std::endl << vprDEBUG_FLUSH;
00169       status.setCode(ReturnStatus::Fail);
00170    }
00171    else
00172    {
00173       mFdesc = -1;
00174       mOpen  = false;
00175    }
00176 
00177    return status;
00178 }
00179 
00180 // Reconfigure the file handle so that it is in blocking mode.
00181 vpr::ReturnStatus FileHandleImplUNIX::setBlocking(bool blocking)
00182 {
00183    vpr::ReturnStatus retval;
00184 
00185    if ( ! mOpen )
00186    {
00187       mOpenBlocking = blocking;
00188    }
00189    else
00190    {
00191       int cur_flags, new_flags;
00192 
00193       // Get the current flags.
00194       cur_flags = getFlags();
00195 
00196       if ( blocking )
00197       {
00198 #ifdef _SGI_SOURCE
00199          // On IRIX, mask FNONBLK and FNDELAY.  We mask FNDELAY to ensure that
00200          // it is not set by the operating system at some level.
00201          new_flags = cur_flags & ~(FNONBLK | FNDELAY);
00202 #else
00203          // On everything else, mask O_NONBLOCK and O_NDELAY.  We mask O_NDELAY
00204          // to ensure that it is not set by the operating system at some level.
00205          new_flags = cur_flags & ~(O_NONBLOCK | O_NDELAY);
00206 #endif
00207       }
00208       else
00209       {
00210 #ifdef _SVR4_SOURCE
00211          // On SysV, set FNONBLK.  We do not set FNDELAY because it just adds
00212          // confusion.  FNONBLK is preferred.
00213          new_flags = cur_flags | FNONBLK;
00214 #else
00215          // On everything else, set O_NONBLOCK.  We do not set O_NDELAY because
00216          // it just adds confusion.  O_NONBLOCK is preferred.
00217          new_flags = cur_flags | O_NONBLOCK;
00218 #endif
00219       }
00220 
00221       // Set the file descriptor to be blocking with the new flags.
00222       if ( setFlags(new_flags) == -1 )
00223       {
00224          vprDEBUG(vprDBG_ERROR, vprDBG_CRITICAL_LVL)
00225             << "[vpr::FileHandleImplUNIX::setBlocking()] Failed to set "
00226             << (blocking ? "blocking" : "non-blocking") << " state on "
00227             << mName << ": " << strerror(errno) << std::endl << vprDEBUG_FLUSH;
00228          retval.setCode(ReturnStatus::Fail);
00229       }
00230       else
00231       {
00232          mBlocking = blocking;
00233       }
00234    }
00235 
00236    return retval;
00237 }
00238 
00239 vpr::IOSys::Handle FileHandleImplUNIX::getHandle() const
00240 {
00241 #ifdef VPR_USE_NSPR
00242    vprDEBUG(vprDBG_ALL, vprDBG_CRITICAL_LVL)
00243        << "ERROR: Cannot get handle for UNIX file descriptor with NSPR!\n";
00244    return vpr::IOSys::NullHandle;
00245 #else
00246    return mFdesc;
00247 #endif
00248 }
00249 
00250 void FileHandleImplUNIX::setOpenReadOnly()
00251 {
00252    mOpenMode = O_RDONLY;
00253 }
00254 
00255 void FileHandleImplUNIX::setOpenWriteOnly()
00256 {
00257    mOpenMode = O_WRONLY;
00258 }
00259 
00260 void FileHandleImplUNIX::setOpenReadWrite()
00261 {
00262    mOpenMode = O_RDWR;
00263 }
00264 
00265 // Reconfigure the file handle to be in append mode.
00266 vpr::ReturnStatus FileHandleImplUNIX::setAppend(bool append)
00267 {
00268    int cur_flags, new_flags, retval;
00269    vpr::ReturnStatus status;
00270 
00271    // Get the current flags.
00272    cur_flags = getFlags();
00273 
00274    // Set O_APPEND.
00275    if ( append )
00276    {
00277       new_flags = cur_flags | O_APPEND;
00278    }
00279    // Clear O_APPEND.
00280    else
00281    {
00282       new_flags = cur_flags & ~O_APPEND;
00283    }
00284 
00285    // Set the file descriptor to be blocking with the new flags.
00286    retval = setFlags(new_flags);
00287 
00288    if ( retval == -1 )
00289    {
00290       vprDEBUG(vprDBG_ERROR, vprDBG_CRITICAL_LVL)
00291          << "[vpr::FileHandleImplUNIX::setAppend()] Failed to "
00292          << (append ? "enable" : "disable") << " append mode on "
00293          << mName << ": " << strerror(errno) << std::endl << vprDEBUG_FLUSH;
00294       status.setCode(ReturnStatus::Fail);
00295    }
00296 
00297    return status;
00298 }
00299 
00300 // Reconfigure the file handle so that writes are synchronous.
00301 vpr::ReturnStatus FileHandleImplUNIX::setSynchronousWrite(bool sync)
00302 {
00303    vpr::ReturnStatus status;
00304 #if ! defined(_POSIX_SOURCE) && defined(O_SYNC) && defined(O_ASYNC)
00305    int cur_flags, new_flags, retval;
00306 
00307    // Get the current flags.
00308    cur_flags = getFlags();
00309 
00310    // Synchronous writes.
00311    if ( sync )
00312    {
00313       new_flags = cur_flags | O_SYNC;
00314    }
00315    // Asynchronous writes.
00316    else
00317    {
00318       new_flags = cur_flags | O_ASYNC;
00319    }
00320 
00321    // Set the file descriptor to be blocking with the new flags.
00322    retval = setFlags(new_flags);
00323 
00324    if ( retval == -1 )
00325    {
00326       vprDEBUG(vprDBG_ERROR, vprDBG_CRITICAL_LVL)
00327          << "[vpr::FileHandleImplUNIX::setSynchronousWrite()] Failed to enable "
00328          << (sync ? "synchronous" : "asynchronous") << " writes on "
00329          << mName << ": " << strerror(errno) << std::endl << vprDEBUG_FLUSH;
00330       status.setCode(vpr::ReturnStatus::Fail);
00331    }
00332 #else
00333    vprDEBUG(vprDBG_ALL, vprDBG_CRITICAL_LVL)
00334       << "[vpr::FileHandleImplUNIX::setSynchronousWrite()] Cannot enable "
00335       << (sync ? "synchronous" : "asynchronous")
00336       << " writes on this platform!\n" << vprDEBUG_FLUSH;
00337    status.setCode(vpr::ReturnStatus::Fail);
00338 #endif
00339 
00340    return status;
00341 }
00342 
00343 bool FileHandleImplUNIX::isReadOnly() const
00344 {
00345    return (mOpenMode == O_RDONLY);
00346 }
00347 
00348 bool FileHandleImplUNIX::isWriteOnly() const
00349 {
00350    return (mOpenMode == O_WRONLY);
00351 }
00352 
00353 bool FileHandleImplUNIX::isReadWrite() const
00354 {
00355    return (mOpenMode == O_RDWR);
00356 }
00357 
00358 vpr::ReturnStatus FileHandleImplUNIX::getReadBufferSize(vpr::Int32& buffer) const
00359 {
00360    vpr::ReturnStatus status;
00361 
00362    if ( ioctl(mFdesc, FIONREAD, &buffer) == -1 )
00363    {
00364       status.setCode(vpr::ReturnStatus::Fail);
00365    }
00366 
00367    return status;
00368 }
00369 
00370 // ============================================================================
00371 // Protected methods.
00372 // ============================================================================
00373 
00374 // Read the specified number of bytes from the file handle into the given
00375 // bufer.
00376 vpr::ReturnStatus FileHandleImplUNIX::read_i(void* buffer,
00377                                              const vpr::Uint32 length,
00378                                              vpr::Uint32& bytesRead,
00379                                              const vpr::Interval timeout)
00380 {
00381    vpr::ReturnStatus status;
00382 
00383    status = isReadable(timeout);
00384 
00385    if ( status.success() )
00386    {
00387       ssize_t bytes;
00388 
00389       bytes = ::read(mFdesc, buffer, length);
00390 
00391       // Something went wrong while attempting to read from the file.
00392       if ( bytes < 0 )
00393       {
00394          bytesRead = 0;
00395 
00396          if ( errno == EAGAIN && ! mBlocking )
00397          {
00398             status.setCode(vpr::ReturnStatus::WouldBlock);
00399          }
00400          // If the error is EAGAIN and we are in non-blocking mode, we do not
00401          // bother to print the message.
00402          if ( ! (errno == EAGAIN && ! mBlocking) )
00403          {
00404             vprDEBUG(vprDBG_ERROR, vprDBG_CRITICAL_LVL)
00405                << "[vpr::FileHandleImplUNIX::read_i()] Error reading from "
00406                << mName << ": " << strerror(errno) << std::endl
00407                << vprDEBUG_FLUSH;
00408             status.setCode(ReturnStatus::Fail);
00409          }
00410       }
00411       // If 0 bytes were read or an error was returned, we print an error
00412       // message.
00413       else if ( bytes == 0 && errno != 0 )
00414       {
00415          // XXX: Failure status may not be exactly what we want to return.
00416          status.setCode(ReturnStatus::Fail);
00417          bytesRead = 0;
00418 //     errno != ENOENT
00419          vprDEBUG(vprDBG_ERROR, vprDBG_WARNING_LVL)
00420             << "[vpr::FileHandleImplUNIX::read_i()] Nothing read from "
00421             << mName << ": " << strerror(errno) << std::endl << vprDEBUG_FLUSH;
00422       }
00423       else
00424       {
00425          bytesRead = bytes;
00426       }
00427    }
00428    else
00429    {
00430       bytesRead = 0;
00431    }
00432 
00433    return status;
00434 }
00435 
00436 // Read exactly the specified number of bytes from the file handle into the
00437 // given buffer.  This is baesd on the readn() function given on pages 51-2 of
00438 // _Effective TCP/IP Programming_ by Jon D. Snader.
00439 vpr::ReturnStatus FileHandleImplUNIX::readn_i(void* buffer,
00440                                               const vpr::Uint32 buffer_size,
00441                                               vpr::Uint32& bytesRead,
00442                                               const vpr::Interval timeout)
00443 {
00444    size_t bytes_left;
00445    ssize_t bytes;
00446    vpr::ReturnStatus status;
00447 
00448    if ( vpr::Interval::NoTimeout != timeout )
00449    {
00450       vprDEBUG(vprDBG_ALL,vprDBG_WARNING_LVL) << "Timeout not supported\n"
00451                                               << vprDEBUG_FLUSH;
00452    }
00453 
00454    bytesRead = 0;
00455    bytes_left = buffer_size;
00456 
00457    while ( bytes_left > 0 )
00458    {
00459       vprDEBUG(vprDBG_ALL, vprDBG_HVERB_LVL)
00460          << "[vpr::FileHandleImplUNIX::readn_i()] Reading " << bytes_left
00461          << " bytes from file handle " << mFdesc << std::endl
00462          << vprDEBUG_FLUSH;
00463 
00464       bytes = ::read(mFdesc, buffer, bytes_left);
00465 
00466       vprDEBUG_NEXT(vprDBG_ALL, vprDBG_HVERB_LVL)
00467          << "Read " << bytes << " bytes from file handle " << mFdesc
00468          << std::endl << vprDEBUG_FLUSH;
00469 
00470       // Read error.
00471       if ( bytes < 0 )
00472       {
00473          // Restart the read process if we were interrupted by the OS.
00474          if ( errno == EINTR )
00475          {
00476             continue;
00477          }
00478          // Otherwise, we have an error situation, so return failure status.
00479          else
00480          {
00481             status.setCode(ReturnStatus::Fail);
00482             bytesRead = 0;
00483             return status;
00484          }
00485       }
00486       // We have read EOF, so there is nothing more to read.  At this point,
00487       // bytesRead contains an accurate count of the bytes read so far
00488       // (posisbly less than buffer_size).
00489       else if ( bytes == 0 )
00490       {
00491          vprDEBUG(vprDBG_ALL, vprDBG_HVERB_LVL)
00492             << "[vpr::FileHandleImplUNIX::readn_i()] Read EOF with "
00493             << bytes_left << " bytes left to read from file handle "
00494             << mFdesc << " and " << bytesRead << " bytes read in total."
00495             << std::endl << vprDEBUG_FLUSH;
00496 
00497          return status;
00498       }
00499       else
00500       {
00501          buffer = (void*) ((char*) buffer + bytes);
00502          bytes_left -= bytes;
00503          bytesRead  += bytes;
00504       }
00505    }
00506 
00507    return status;
00508 }
00509 
00510 // Write the buffer to the file handle.
00511 vpr::ReturnStatus FileHandleImplUNIX::write_i(const void* buffer,
00512                                               const vpr::Uint32 length,
00513                                               vpr::Uint32& bytesWritten,
00514                                               const vpr::Interval timeout)
00515 {
00516    vpr::ReturnStatus status;
00517 
00518    status = isWriteable(timeout);
00519 
00520    if ( status.success() )
00521    {
00522       ssize_t bytes;
00523 
00524       bytes = ::write(mFdesc, buffer, length);
00525 
00526       if ( bytes <= 0 )
00527       {
00528          bytesWritten = 0;
00529 
00530          if ( errno == EAGAIN && ! mBlocking )
00531          {
00532             status.setCode(vpr::ReturnStatus::WouldBlock);
00533          }
00534          else
00535          {
00536             vprDEBUG(vprDBG_ERROR, vprDBG_CRITICAL_LVL)
00537                << "[vpr::FileHandleImplUNIX::write_i()] Error writing to "
00538                << mName << ": " << strerror(errno) << std::endl
00539                << vprDEBUG_FLUSH;
00540             status.setCode(ReturnStatus::Fail);
00541          }
00542       }
00543       else
00544       {
00545          bytesWritten = bytes;
00546       }
00547    }
00548 
00549    return status;
00550 }
00551 
00552 vpr::Uint32 FileHandleImplUNIX::availableBytes() const
00553 {
00554    int result;
00555 
00556    if ( ioctl(mFdesc, FIONREAD, &result) < 0 )
00557    {
00558       result = 0;
00559    }
00560 
00561    return result;
00562 }
00563 
00564 // Get the current file handle flags.
00565 int FileHandleImplUNIX::getFlags() const
00566 {
00567    return fcntl(mFdesc, F_GETFL, 0);
00568 }
00569 
00570 // Overwrite the current file handle flags with the given value.
00571 int FileHandleImplUNIX::setFlags(const int flags)
00572 {
00573    return fcntl(mFdesc, F_SETFL, flags);
00574 }
00575 
00576 vpr::ReturnStatus FileHandleImplUNIX::isReadable(const vpr::Interval timeout) const
00577 {
00578    vpr::ReturnStatus ready;
00579    fd_set read_set;
00580    int num_events;
00581    struct timeval timeout_obj;
00582 
00583    if ( mFdesc == -1 )
00584    {
00585       ready.setCode(vpr::ReturnStatus::Fail);
00586    }
00587    else
00588    {
00589       if ( timeout == vpr::Interval::NoWait )
00590       {
00591          timeout_obj.tv_sec  = 0;
00592          timeout_obj.tv_usec = 0;
00593       }
00594       else
00595       {
00596          if ( timeout.msec() >= 1000 )
00597          {
00598             timeout_obj.tv_sec  = timeout.msec() / 1000;
00599             timeout_obj.tv_usec = (timeout.msec() % 1000) * 1000000;
00600          }
00601          else
00602          {
00603             timeout_obj.tv_sec  = 0;
00604             timeout_obj.tv_usec = timeout.msec() * 1000;
00605          }
00606       }
00607 
00608       FD_ZERO(&read_set);
00609       FD_SET(mFdesc, &read_set);
00610 
00611       num_events = select(mFdesc + 1, &read_set, NULL, NULL,
00612                           (timeout != vpr::Interval::NoTimeout) ? &timeout_obj :
00613                                                                   NULL);
00614 
00615       if ( num_events == 0 )
00616       {
00617          if ( ! FD_ISSET(mFdesc, &read_set) )
00618          {
00619             ready.setCode(vpr::ReturnStatus::Timeout);
00620          }
00621       }
00622       else if ( num_events < 0 )
00623       {
00624          ready.setCode(vpr::ReturnStatus::Fail);
00625       }
00626    }
00627 
00628    return ready;
00629 }
00630 
00631 vpr::ReturnStatus FileHandleImplUNIX::isWriteable(const vpr::Interval timeout) const
00632 {
00633    vpr::ReturnStatus ready;
00634    fd_set write_set;
00635    int num_events;
00636    struct timeval timeout_obj;
00637 
00638    if ( mFdesc == -1 )
00639    {
00640       ready.setCode(vpr::ReturnStatus::Fail);
00641    }
00642    else
00643    {
00644       if ( timeout == vpr::Interval::NoWait )
00645       {
00646          timeout_obj.tv_sec  = 0;
00647          timeout_obj.tv_usec = 0;
00648       }
00649       else
00650       {
00651          if ( timeout.msec() >= 1000 )
00652          {
00653             timeout_obj.tv_sec  = timeout.msec() / 1000;
00654             timeout_obj.tv_usec = (timeout.msec() % 1000) * 1000000;
00655          }
00656          else
00657          {
00658             timeout_obj.tv_sec  = 0;
00659             timeout_obj.tv_usec = timeout.msec() * 1000;
00660          }
00661       }
00662 
00663       FD_ZERO(&write_set);
00664       FD_SET(mFdesc, &write_set);
00665 
00666       num_events = select(mFdesc + 1, NULL, &write_set, NULL,
00667                           (timeout != vpr::Interval::NoTimeout) ? &timeout_obj :
00668                                                                   NULL);
00669 
00670       if ( num_events == 0 )
00671       {
00672          if ( ! FD_ISSET(mFdesc, &write_set) )
00673          {
00674             ready.setCode(vpr::ReturnStatus::Timeout);
00675          }
00676       }
00677       else if ( num_events < 0 )
00678       {
00679          ready.setCode(vpr::ReturnStatus::Fail);
00680       }
00681    }
00682 
00683    return ready;
00684 }
00685 
00686 } // End of vpr namespace

Generated on Thu Jan 4 10:52:09 2007 for VR Juggler Portable Runtime by  doxygen 1.5.1