contrib/oul/oufgl/asyncio.cxx
Go to the documentation of this file.
00001 // This is oul/oufgl/asyncio.cxx
00002 #include "asyncio.h"
00003 //:
00004 // \file
00005 #include <vcl_sys/types.h>
00006 #include <vcl_cerrno.h>
00007 #include <vcl_cassert.h>
00008 
00009 //: Initialise shared state to "no operation in progress"
00010 
00011 volatile sig_atomic_t AsyncIO_Shared_State::complete = 1;
00012 
00013 // Set complete flag when completion signal arrives. Currently ignores
00014 // the signal number (see the warning at the start of the header)
00015 
00016 void AsyncIO_Shared_State::signal_handler(int)
00017 {
00018   complete = 1;
00019 }
00020 
00021 //: Constructor - perform I/O on file descriptor fd, using sig as completion signal.
00022 // Note that SIGUSR1,2 may be used by the linuxthreads library.
00023 
00024 AsyncIO::AsyncIO(int fd, int sig)
00025 {
00026   cb.aio_fildes = fd;
00027   cb.aio_reqprio = 0;
00028   cb.aio_sigevent.sigev_notify = SIGEV_SIGNAL;
00029   cb.aio_sigevent.sigev_signo = sig;
00030   cb.aio_lio_opcode = LIO_NOP;
00031   // Remaining cb fields are filled in by read() or write()
00032   signal(sig, &AsyncIO_Shared_State::signal_handler);
00033 }
00034 
00035 //: Destructor - disconnect signal handler
00036 
00037 AsyncIO::~AsyncIO()
00038 {
00039   signal(cb.aio_sigevent.sigev_signo, SIG_DFL);
00040 }
00041 
00042 //: Begin reading n bytes into buf starting at current file position
00043 
00044 int AsyncIO::read(volatile void *buf, vcl_size_t n)
00045 {
00046   // Only one op allowed at a time. Note that aio_read() itself never
00047   // returns EBUSY.
00048 
00049   if (!complete)
00050     return EBUSY;
00051 
00052   off_t pos = lseek(cb.aio_fildes, 0, SEEK_CUR);
00053   if (pos == -1)
00054     return errno;
00055   else
00056     return read(buf, n, pos);
00057 }
00058 
00059 //: Begin reading n bytes into buf starting at absolute file position pos
00060 
00061 int AsyncIO::read(volatile void *buf, vcl_size_t n, off_t pos)
00062 {
00063   // Only one op allowed at a time. Note that aio_read() itself never
00064   // returns EBUSY.
00065 
00066   if (!complete)
00067     return EBUSY;
00068 
00069   complete = 0;
00070   cb.aio_buf = buf;
00071   cb.aio_nbytes = n;
00072   cb.aio_offset = pos;
00073 
00074   // Initiate read - mark as complete if initiation fails
00075 
00076   if (aio_read(&cb) != 0)
00077   {
00078     complete = 1;
00079     return errno;
00080   }
00081   else
00082     return 0;
00083 }
00084 
00085 //: Begin writing n bytes from buf starting at current file position
00086 
00087 int AsyncIO::write(volatile void *buf, vcl_size_t n)
00088 {
00089   // Only one op allowed at a time. Note that aio_write() itself never
00090   // returns EBUSY.
00091 
00092   if (!complete)
00093     return EBUSY;
00094 
00095   off_t pos = lseek(cb.aio_fildes, 0, SEEK_CUR);
00096   if (pos == -1)
00097     return errno;
00098   else
00099     return write(buf, n, pos);
00100 }
00101 
00102 //: Begin writing n bytes from buf starting at absolute file position pos
00103 
00104 int AsyncIO::write(volatile void *buf, vcl_size_t n, off_t pos)
00105 {
00106   // Only one op allowed at a time. Note that aio_write() itself never
00107   // returns EBUSY.
00108 
00109   if (!complete)
00110     return EBUSY;
00111 
00112   complete = 0;
00113   cb.aio_buf = buf;
00114   cb.aio_nbytes = n;
00115   cb.aio_offset = pos;
00116 
00117   // Initiate write - mark as complete if initiation fails
00118 
00119   if (aio_write(&cb) != 0)
00120   {
00121     complete = 1;
00122     return errno;
00123   }
00124   else
00125     return 0;
00126 }
00127 
00128 //: Wait for I/O to complete, then return status.
00129 // If suspend is true (the default), block the calling process while waiting,
00130 // otherwise continuously poll for completion
00131 // (not recommended, but may be more reliable).
00132 
00133 int AsyncIO::wait_for_completion(bool suspend)
00134 {
00135   int status;
00136 
00137   if (!complete)
00138   {
00139     if (suspend)
00140     {
00141       const struct aiocb *aio_list[1] = { &cb };
00142       // Delivery of the completion signal might cause EINTR, so wait for
00143       // either success or some other status
00144       while (aio_suspend(aio_list, 1, NULL) == -1)
00145         if (errno != EINTR)
00146           return errno;
00147     }
00148     else
00149       while (aio_error(&cb) == EINPROGRESS)
00150         /* wait */ ;
00151     assert(complete);      // Just in case...
00152   }
00153   if ((status = aio_error(&cb)) != 0)
00154     return status;
00155   else if (aio_return(&cb) == -1)
00156     return errno;
00157   else
00158     return 0;
00159 }