X-Spam-Check-By: sourceware.org Date: Wed, 10 May 2006 04:19:19 -0700 From: clayne AT anodized DOT com To: cygwin AT cygwin DOT com Cc: dave DOT korn AT artimi DOT com Subject: Re: readv() questions Message-ID: <20060510111919.GN18330@ns1.anodized.com> References: <20060509143556 DOT GI18330 AT ns1 DOT anodized DOT com> <02ab01c67378$71ad2440$a501a8c0 AT CAM DOT ARTIMI DOT COM> <20060510051135 DOT GK18330 AT ns1 DOT anodized DOT com> Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <20060510051135.GK18330@ns1.anodized.com> User-Agent: Mutt/1.5.11 X-Assp-Spam-Prob: 0.00000 X-Assp-Whitelisted: Yes X-Assp-Envelope-From: clayne AT ns1 DOT anodized DOT com X-IsSubscribed: yes Mailing-List: contact cygwin-help AT cygwin DOT com; run by ezmlm Precedence: bulk List-Unsubscribe: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: cygwin-owner AT cygwin DOT com Mail-Followup-To: cygwin AT cygwin DOT com Delivered-To: mailing list cygwin AT cygwin DOT com On Tue, May 09, 2006 at 10:11:35PM -0700, clayne AT anodized DOT com wrote: > > So far so good, but if anyone sees anything glaring might as well point it > out - although this is not really CW related at this point. > > -cl Just to follow up on this.. I did take your advice fully Dave, and decided to just modify the partial iovec in place and restore a copy of it after handling the partial situation. Reason being that it's beneficial to set an iovec array once and pass it to read or writev on every call (if one is using relatively non changing locations assigned to each iov_base per vector - if not, it still works anyways). So far so good, I setup a test case and have transfered over 20,000,000 records via 6 iovecs each at around ~20-70 bytes average record size. I've also verified that partials are occuring, in addition to both mid-vector and mid-array. 200K/sec - so I think we can rest assured race conditions are out of the picture. My code was the culprit, cygwin's was not :). In case anyone needs the code for any purpose (I know that I searched usenet and web quite a bit looking for any references to short|trunc|partial, etc. WRT readv()/writev() and found very little, so this may come in handy to others. -cl /* header */ #ifndef __NIOV_H #define __NIOV_H #define n_recv_iov(a,b,c,d) \ n_iov_generic(a,b,c,d,N_IOV_RECV) #define n_send_iov(a,b,c,d) \ n_iov_generic(a,b,c,d,N_IOV_SEND) enum n_iov_type__ { N_IOV_RECV, N_IOV_SEND }; typedef enum n_iov_type__ n_iov_type; ssize_t n_iov_generic(const int, struct iovec *, ssize_t, const int, n_iov_type); ssize_t n_iov_offset(const struct iovec *, const ssize_t, ssize_t *); ssize_t n_iov_total(const struct iovec *, const ssize_t); #endif /* __NIOV_H */ /* module */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "niov.h" #define _POSIX_SOURCE 1 ssize_t n_iov_offset(const struct iovec *v, const ssize_t c, ssize_t *os) { ssize_t l, cv; /* * compute filled iovec count and set any partial offset in "os". * "os" should point to the number of bytes previously read when * called. */ for (cv = 0; cv < c; cv++) { if ((l = v[cv].iov_len) > *os) break; *os -= l; } return cv; } ssize_t n_iov_total(const struct iovec *v, const ssize_t c) { ssize_t cv, bt; for (cv = bt = 0; cv < c; cv++) bt += v[cv].iov_len; return bt; } ssize_t n_iov_generic(const int s, struct iovec *v, ssize_t c, const int t, n_iov_type nt) { struct timeval to; struct iovec iov_o = { NULL, 0 }; fd_set fds, fds_m, *rfds = NULL, *wfds = NULL; ssize_t (*nf_iov)(int, const struct iovec *, ssize_t); ssize_t cv, b, be, bt; int res; switch (nt) { case N_IOV_RECV: nf_iov = readv; rfds = &fds; break; case N_IOV_SEND: nf_iov = writev; wfds = &fds; break; default: break; } FD_ZERO(&fds_m); FD_SET(s, &fds_m); for (bt = 0, be = n_iov_total(v, c); bt < be; ) { fds = fds_m; to.tv_sec = t; to.tv_usec = 0; b = nf_iov(s, v, c); if (b == -1) { switch (errno) { case EWOULDBLOCK: case EINTR: break; default: perror(nt == N_IOV_RECV ? "readv" : "writev"); bt = -1; break; } if (bt == -1) break; } else if (b && (bt += b) < be) { /* * short count situation. * * if not within mid-vector, advance past filled, else * temporarily modify original iovec to make up the * difference and restore on exit. */ /* if previously saved, restore before modify */ if (iov_o.iov_base) { memcpy(v, &iov_o, sizeof(*v)); iov_o.iov_base = NULL; } /* * cv = filled vectors returned, advance past these. * b = mid-vector offset in case of partial vector. */ cv = n_iov_offset(v, c, &b); v += cv; c -= cv; /* if mid-vector, save original before modifying */ if (b) { memcpy(&iov_o, v, sizeof(*v)); v->iov_base = (char *)v->iov_base + b; v->iov_len -= b; } continue; } else { break; } if ((res = select(s + 1, rfds, wfds, NULL, &to)) == 0) { bt = -1; /* timeout */ break; } else if (res == -1) { perror("select"); /* never happen */ bt = -1; break; } } /* restore original if still modified */ if (iov_o.iov_base) memcpy(v, &iov_o, sizeof(iov_o)); return bt; } -- Unsubscribe info: http://cygwin.com/ml/#unsubscribe-simple Problem reports: http://cygwin.com/problems.html Documentation: http://cygwin.com/docs.html FAQ: http://cygwin.com/faq/