io.c

Go to the documentation of this file.
00001 #include "config.h"
00002 
00003 #include "headers.h"
00004 #include "error.h"
00005 #include "fd.h"
00006 #include "io.h"
00007 
00008 /** I/O state data. */
00009 IO io;
00010 
00011 /** Initialize I/O state data.
00012  * \return 0 for success.  (This function does not fail.)
00013  */
00014 int ioInit(void)
00015 {
00016         /** Initlalize the input file path to null. */
00017         io.in_path = 0;
00018         /** Initialize the input file descriptor to standard input. */
00019         io.in = STDIN_FILENO;
00020         /** Initialize the output file descriptor to standard output. */
00021         io.out = STDOUT_FILENO;
00022         /** Set the initial end-of-file flags to false (or zero). */
00023         io.eof_in = 0;
00024         io.eof_out = 0;
00025         /** Initialize the ring buffer. */
00026         io.buffer_used = 0;
00027         io.buffer_head = 0;
00028         io.buffer_size = DEFAULT_BUFFER_SIZE;
00029         io.buffer = 0;
00030         /** Initialize the byte-counters. */
00031         io.last_read = 0;
00032         io.last_write = 0;
00033         io.total_size = 0;
00034         io.total_size_known = 0;
00035         io.total_read = 0;
00036         io.total_write = 0;
00037         io.continue_size = 0;
00038         /** Initialize the I/O timeout to 1 millisecond. */
00039         io.timeout = 1; /* 1/1000000 second */
00040         /** Initialize the current time and the throttle counts. */
00041         io.current_time = time(0);
00042         io.throttle_count = 1;
00043         io.throttle = MAX_UINT64;
00044         /** Initialize the default block size to 512 bytes. */
00045         io.block_size = 512; /* 0.5k default */
00046         return(0);
00047 }
00048 
00049 #ifdef HAVE_SIGNAL_H
00050 /** A signal handler for control-C.
00051  *
00052  * \param signo The signal number.
00053  */
00054 static void sig_int(int signo)
00055 {
00056         /** Return I/O streams to a default state before exiting. */
00057         fdEnd(io.in);
00058         fdEnd(io.out);
00059         exit(1);
00060 }
00061 #endif
00062 
00063 #ifdef HAVE_SYSCONF
00064 #       if HAVE_DECL__SC_PAGE_SIZE == 1
00065 #               define PAGESIZE _SC_PAGE_SIZE
00066 #       else
00067 #               if HAVE_DECL__SC_PAGESIZE == 1
00068 #                       define PAGESIZE _SC_PAGESIZE
00069 #               endif
00070 #       endif
00071 #       ifndef PAGESIZE
00072 #               warning I dont know how to retrieve the size of a page using sysconf.
00073 #               warning Assuming page size is DEFAULT_PAGE_SIZE bytes.
00074 #               undef HAVE_SYSCONF
00075 #       endif
00076 #endif
00077 
00078 /** Prepare I/O
00079  *
00080  * \return 0 for success, non-zero for failure.
00081  */
00082 int ioBegin(void)
00083 {
00084         /** If memalign() or posix_memalign() is available, then allocate memory on
00085          * a page boundary.  If sysconf() is available, find out what the page size
00086          * is for this machine, otherwise assume that a page is 8192 bytes.
00087          */
00088 #if defined(USE_MEMALIGN) \
00089         && (defined(HAVE_POSIX_MEMALIGN) || defined(HAVE_MEMALIGN))
00090         long page_size = 0;
00091 
00092 #       ifdef HAVE_SYSCONF
00093         page_size = sysconf(PAGESIZE);
00094 #       else
00095         page_size = DEFAULT_PAGE_SIZE;
00096 #       endif
00097 #endif
00098 
00099         /** Allocate memory for the ring buffer. */
00100 #undef USED_MEMALIGN
00101 #ifdef USE_MEMALIGN
00102 #       if defined(HAVE_POSIX_MEMALIGN)
00103 #               define USED_MEMALIGN
00104         if (
00105                 /** Incorporating patch provided by Doncho N. Gunchev
00106                  * Closes bug: [ 1158420 ] glibc detects invalid free on exit (Fedora Core 3)
00107                  * */
00108                 posix_memalign((void*)&io.buffer, page_size, sizeof(char) * io.buffer_size) != 0
00109                 )
00110         {
00111                 print_error(stderr, "Memory allocation failed");
00112                 return(1);
00113         }
00114 /*
00115 #       elif defined(HAVE_MEMALIGN)
00116 #               if defined(USE_MEMALIGN_BOUNDARY_SIZE)
00117 #                       define USED_MEMALIGN
00118                         io.buffer = (char *)memalign(page_size, sizeof(char) * io.buffer_size);
00119 #               elif defined(USE_MEMALIGN_SIZE_BOUNDARY)
00120 #                       define USED_MEMALIGN
00121                         io.buffer = (char *)memalign(sizeof(char) * io.buffer_size, page_size);
00122 #               endif
00123 */
00124 #       endif
00125 #endif
00126 #ifndef USED_MEMALIGN
00127         io.buffer = (char *)malloc(sizeof(char) * io.buffer_size);
00128 #endif
00129         if (io.buffer == 0) {
00130                 print_error(stderr, "Memory allocation failed");
00131                 return(1);
00132         }
00133         /** If we have signal(), then set up a signal handler to catch control-C's.
00134          */
00135 #ifdef HAVE_SIGNAL_H
00136         if (signal(SIGINT, sig_int) == SIG_ERR) {
00137                 print_error(stderr, "Could not install SIGINT signal handler");
00138                 print_error(stderr, "Control-C events will not reset non-blocking I/O");
00139         }
00140 #endif
00141         /** Prepare the I/O file descriptors. */
00142         fdBegin(io.in);
00143         fdBegin(io.out);
00144         return(0);
00145 }
00146 
00147 /** Shut down I/O
00148  *
00149  * \return 0 for success.  (This function does not fail.)
00150  */
00151 int ioEnd(void)
00152 {
00153         /** Free the I/O buffer. */
00154         free(io.buffer);
00155         io.buffer = 0;
00156         io.buffer_used = 0;
00157         /** Return the file descriptors to their previous state. */
00158         fdEnd(io.in);
00159         fdEnd(io.out);
00160         return(0);
00161 }
00162 
00163 /** Check to see if I/O is ready. */
00164 void ioCheck(void)
00165 {
00166         static fd_set rset, wset;
00167         static struct timeval to;
00168         
00169         to.tv_sec = 0;
00170         /** Wait for up to io.timeout milliseconds for a change in I/O state. */
00171         to.tv_usec = io.timeout;
00172         io.in_ready = 1;
00173         io.out_ready = 1;
00174         FD_ZERO(&rset);
00175         FD_ZERO(&wset);
00176         if (io.buffer_used != io.buffer_size) FD_SET(io.in, &rset);
00177         if (io.buffer_used) FD_SET(io.out, &wset);
00178         /** Check to see if I/O is ready. */
00179         if (select( ((io.in<io.out)?io.out:io.in)+1, 
00180                 &rset, &wset, 0, &to) == -1) {
00181                 if (errno != EINTR) {
00182                         print_error(stderr, "select() failed");
00183                         return;
00184                 }
00185         }
00186         /** Set the I/O ready flags in I/O state data. */
00187         if (!FD_ISSET(io.in, &rset))
00188                 io.in_ready = 0;
00189         if (!FD_ISSET(io.out, &wset))
00190                 io.out_ready = 0;
00191 }
00192 
00193 /** Read input
00194  *
00195  * \return 0 for success, non-zero for failure.
00196  */
00197 int ioRead(void)
00198 {
00199         int num_read = 0;
00200         int end = 0;
00201         int avail = 0;
00202 #ifdef USE_IOVEC
00203         int num = 0;
00204         struct iovec vec[2] = { { 0 } };
00205 #endif
00206 
00207         /** If we've reached out throttle count for this second, return. */
00208         if ((io.current_time == time(0))
00209                 && (io.throttle_count >= io.throttle)) {
00210                 return(0);
00211         }
00212         if (io.current_time != time(0)) {
00213                 io.throttle_count = 0;
00214                 io.current_time = time(0);
00215         }
00216         /** If there is nothing to read yet, return. */
00217         if (!io.in_ready) return(0);
00218         io.last_read = 0;
00219         /** If we've reached the end of input, return. */
00220         if (io.eof_in) return(0);
00221         /** If the buffer is full, return. */
00222         if (io.buffer_used == io.buffer_size) return(0);
00223         /** Calculate the location and size of the free space in the buffer. */
00224         end = (io.buffer_used + io.buffer_head) % io.buffer_size;
00225         avail = io.buffer_size - io.buffer_used;
00226         /** If the free space in the buffer is greater than the number of bytes left
00227          * to be read in this second, throttle the input.
00228          */
00229         if ((io.throttle - io.throttle_count) < avail)
00230                 avail = io.throttle - io.throttle_count;
00231 #ifdef USE_IOVEC
00232         /** If using iovec I/O, set up vec[] with the proper information and then
00233          * read using iovec I/O.
00234          */
00235         vec[num  ].iov_base = io.buffer + end;
00236         if (end+avail <= io.buffer_size)
00237                 vec[num++].iov_len  = avail;
00238         else {
00239                 vec[num++].iov_len  = io.buffer_size - end;
00240                 vec[num  ].iov_base = io.buffer;
00241                 vec[num++].iov_len  = avail - (io.buffer_size - end);
00242         }
00243         num_read = readv(io.in, vec, num);
00244 #else
00245         /** If not using iovec, then read input into the next available chunk of
00246          * linear buffer space.
00247          */
00248         if (end+avail <= io.buffer_size) {
00249                 num_read = read(io.in,
00250                         io.buffer + end,
00251                         avail);
00252         }
00253         else {
00254                 num_read = read(io.in,
00255                         io.buffer + end,
00256                         io.buffer_size - end);
00257         }
00258 #endif
00259         /** Check for end of file. */
00260         if (num_read == 0) {
00261                 io.eof_in = 1;
00262                 return(0);
00263         }
00264         /** Check for an error. */
00265         if ((num_read < 0) && (errno == EAGAIN))
00266                 num_read = 0;
00267         if (num_read < 0) return(num_read);
00268         /** Update I/O byte counters. */
00269         io.buffer_used += num_read;
00270         io.last_read = num_read;
00271         io.total_read += num_read;
00272         io.throttle_count += num_read;
00273         return(0);
00274 }
00275 
00276 /** Write data
00277  *
00278  * \return 0 for success, non-zero for failure.
00279  */
00280 int ioWrite(void)
00281 {
00282         int num_written = 0;
00283 #ifdef USE_IOVEC
00284         int num = 0;
00285         struct iovec vec[2] = { { 0 } };
00286 #endif
00287 
00288         /** If output is not ready, return. */
00289         if (!io.out_ready) return(0);
00290         io.last_write = 0;
00291 #ifdef USE_IOVEC
00292         /** If using iovec I/O, set up vec[] with the correct information and then
00293          * write.
00294          */
00295         vec[num  ].iov_base = io.buffer + io.buffer_head;
00296         if (io.buffer_head + io.buffer_used <= io.buffer_size)
00297                 vec[num++].iov_len  = io.buffer_used;
00298         else {
00299                 vec[num++].iov_len  = io.buffer_size - io.buffer_head;
00300                 vec[num  ].iov_base = io.buffer;
00301                 vec[num++].iov_len  = io.buffer_used - (io.buffer_size - io.buffer_head);
00302         }
00303         num_written = writev(io.out, vec, num);
00304 #else
00305         /** If not using iovec, then write the next chunk of linear data from the
00306          * buffer.
00307          */
00308         if (io.buffer_head + io.buffer_used <= io.buffer_size) {
00309                 num_written = write(io.out,
00310                         io.buffer + io.buffer_head,
00311                         io.buffer_used);
00312         }
00313         else {
00314                 num_written = write(io.out,
00315                         io.buffer + io.buffer_head,
00316                         io.buffer_size - io.buffer_head);
00317         }
00318 #endif
00319         /** Check for end of file. */
00320         if (num_written == 0) {
00321                 io.eof_out = 1;
00322                 return(0);
00323         }
00324         /** Check for an error. */
00325         if ((num_written < 0) && (errno == EAGAIN))
00326                 num_written = 0;
00327         if (num_written < 0) return(num_written);
00328         /** Update the I/O byte counters. */
00329         io.buffer_used -= num_written;
00330         io.buffer_head = (io.buffer_head + num_written) % io.buffer_size;
00331         io.last_write = num_written;
00332         io.total_write += num_written;
00333         return(0);
00334 }
00335 
00336 /** Check to see if we're done copying input to output
00337  *
00338  * \return 1 if done, 0 otherwise.
00339  */
00340 int ioIsDone(void)
00341 {
00342         if ((io.eof_in && (io.buffer_used == 0)) || io.eof_out) return(1);
00343         return(0);
00344 }
00345 

Generated on Thu Jun 28 09:13:03 2007 for bar by  doxygen 1.5.1