diff options
author | Arthur de Jong <arthur@arthurdejong.org> | 2008-02-15 17:52:14 +0100 |
---|---|---|
committer | Arthur de Jong <arthur@arthurdejong.org> | 2008-02-15 17:52:14 +0100 |
commit | a603163c68f95a0fa57b741c5428a8e14333fc38 (patch) | |
tree | 5fa4d706a21ef102b29d12022137c90c36ecb47b /common/tio.c | |
parent | 33d5235b2f4c99785073cf9983609432da5cc795 (diff) |
split out the flushing of the buffers to separate functions and see if we can flush some data from the buffer if it is overflowing before growing the buffer
git-svn-id: http://arthurdejong.org/svn/nss-pam-ldapd/nss-ldapd@635 ef36b2f9-881f-0410-afb5-c4e39611909c
Diffstat (limited to 'common/tio.c')
-rw-r--r-- | common/tio.c | 122 |
1 files changed, 84 insertions, 38 deletions
diff --git a/common/tio.c b/common/tio.c index c37fb46..e4b0d30 100644 --- a/common/tio.c +++ b/common/tio.c @@ -300,21 +300,55 @@ int tio_skip(TFILE *fp, size_t count) return tio_read(fp,NULL,count); } -/* write all the data in the buffer to the stream */ -int tio_flush(TFILE *fp) +/* the caller has assured us that we can write to the file descriptor + and we give it a shot */ +static int tio_writebuf(TFILE *fp) { - struct timeval deadline; - struct sigaction act,oldact; int rv; -/* -FIXME: we have a race condition here (setting and restoring the signal mask), this is a critical region that should be locked -*/ + struct sigaction act,oldact; + /* FIXME: we have a race condition here (setting and restoring the signal mask), this is a critical region that should be locked */ /* set up sigaction */ memset(&act,0,sizeof(struct sigaction)); act.sa_sigaction=NULL; act.sa_handler=SIG_IGN; sigemptyset(&act.sa_mask); act.sa_flags=SA_RESTART; + /* ignore SIGPIPE */ + if (sigaction(SIGPIPE,&act,&oldact)!=0) + return -1; /* error setting signal handler */ + /* write the buffer */ + rv=write(fp->fd,fp->writebuffer.buffer+fp->writebuffer.start,fp->writebuffer.len); + /* restore the old handler for SIGPIPE */ + if (sigaction(SIGPIPE,&oldact,NULL)!=0) + return -1; /* error restoring signal handler */ + /* check for errors */ + if ((rv==0)||((rv<0)&&(errno!=EINTR)&&(errno!=EAGAIN))) + return -1; /* something went wrong with the write */ + /* skip the written part in the buffer */ + if (rv>0) + { + fp->writebuffer.start+=rv; + fp->writebuffer.len-=rv; +#ifdef DEBUG_TIO_STATS + fp->byteswritten+=rv; +#endif /* DEBUG_TIO_STATS */ + /* reset start if len is 0 */ + if (fp->writebuffer.len==0) + fp->writebuffer.start=0; + /* move contents of the buffer to the front if it will save enough room */ + if (fp->writebuffer.start>=(fp->writebuffer.size/4)) + { + memmove(fp->writebuffer.buffer,fp->writebuffer.buffer+fp->writebuffer.start,fp->writebuffer.len); + fp->writebuffer.start=0; + } + } + return 0; +} + +/* write all the data in the buffer to the stream */ +int tio_flush(TFILE *fp) +{ + struct timeval deadline; /* build a time by which we should be finished */ tio_tv_prepare(&deadline,&(fp->writetimeout)); /* loop until we have written our buffer */ @@ -323,33 +357,39 @@ FIXME: we have a race condition here (setting and restoring the signal mask), th /* wait until we can write */ if (tio_select(fp->fd,0,&deadline)) return -1; - /* ignore SIGPIPE */ - if (sigaction(SIGPIPE,&act,&oldact)!=0) - return -1; /* error setting signal handler */ - /* write the buffer */ - rv=write(fp->fd,fp->writebuffer.buffer+fp->writebuffer.start,fp->writebuffer.len); - /* restore the old handler for SIGPIPE */ - if (sigaction(SIGPIPE,&oldact,NULL)!=0) - return -1; /* error restoring signal handler */ - /* check for errors */ - if ((rv==0)||((rv<0)&&(errno!=EINTR)&&(errno!=EAGAIN))) - return -1; /* something went wrong with the write */ - /* skip the written part in the buffer */ - if (rv>0) - { - fp->writebuffer.start+=rv; - fp->writebuffer.len-=rv; -#ifdef DEBUG_TIO_STATS - fp->byteswritten+=rv; -#endif /* DEBUG_TIO_STATS */ - } + /* write one block */ + if (tio_writebuf(fp)) + return -1; } - /* clear buffer and we're done */ - fp->writebuffer.start=0; - fp->writebuffer.len=0; return 0; } +/* try a single write of data in the buffer if the file descriptor + will accept data */ +static int tio_flush_nonblock(TFILE *fp) +{ + struct timeval tv; + fd_set fdset; + int rv; + /* prepare our filedescriptorset */ + FD_ZERO(&fdset); + FD_SET(fp->fd,&fdset); + /* set the timeout to 0 to poll */ + tv.tv_sec=0; + tv.tv_usec=0; + /* wait for activity */ + rv=select(FD_SETSIZE,NULL,&fdset,NULL,&tv); + /* check if any file descriptors were ready (timeout) or we were + interrupted */ + if ((rv==0)||((rv<0)&&(errno==EINTR))) + return 0; + /* any other errors? */ + if (rv<0) + return -1; + /* so file descriptor will accept writes */ + return tio_writebuf(fp); +} + int tio_write(TFILE *fp, const void *buf, size_t count) { size_t fr; @@ -368,6 +408,20 @@ int tio_write(TFILE *fp, const void *buf, size_t count) fp->writebuffer.len+=count; return 0; } + else if (fr > 0) + { + /* fill the buffer with data that will fit */ + memcpy(fp->writebuffer.buffer+fp->writebuffer.start+fp->writebuffer.len,ptr,fr); + fp->writebuffer.len+=fr; + ptr+=fr; + count-=fr; + } + /* try to flush some of the data that is in the buffer */ + if (tio_flush_nonblock(fp)) + return -1; + /* if we have room now, try again */ + if (fp->writebuffer.size>(fp->writebuffer.start+fp->writebuffer.len)) + continue; /* try to grow the buffer */ if (fp->writebuffer.size<fp->writebuffer.maxsize) { @@ -382,14 +436,6 @@ int tio_write(TFILE *fp, const void *buf, size_t count) continue; /* try again */ } } - /* fill the buffer with data that will fit */ - if (fr > 0) - { - memcpy(fp->writebuffer.buffer+fp->writebuffer.start+fp->writebuffer.len,ptr,fr); - fp->writebuffer.len+=fr; - ptr+=fr; - count-=fr; - } /* write the buffer to the stream */ if (tio_flush(fp)) return -1; |