diff options
author | Eric Wong <normalperson@yhbt.net> | 2013-01-17 01:11:04 +0000 |
---|---|---|
committer | Eric Wong <normalperson@yhbt.net> | 2013-01-17 01:28:59 +0000 |
commit | 14e0684507c06439ee9c7a731fd6ca90b7b9adcb (patch) | |
tree | ca804fbdee3981c192a527c2102b203ddc82cd94 /trywrite.c | |
parent | 37026af96dec638aa850d604003bf7218d90037d (diff) | |
download | cmogstored-14e0684507c06439ee9c7a731fd6ca90b7b9adcb.tar.gz |
This saves several setsockopt() syscalls and reduces system CPU usage.
Diffstat (limited to 'trywrite.c')
-rw-r--r-- | trywrite.c | 54 |
1 files changed, 52 insertions, 2 deletions
@@ -10,7 +10,7 @@ struct mog_wbuf { unsigned char buf[FLEXIBLE_ARRAY_MEMBER]; }; -static void * wbuf_new(size_t total, struct iovec *iov, int iovcnt) +static void * wbuf_newv(size_t total, struct iovec *iov, int iovcnt) { struct mog_wbuf *wbuf = xmalloc(sizeof(struct mog_wbuf) + total); void *dst = wbuf->buf; @@ -25,6 +25,16 @@ static void * wbuf_new(size_t total, struct iovec *iov, int iovcnt) return wbuf; } +static void * wbuf_new(void *buf, size_t len) +{ + struct iovec iov; + + iov.iov_base = buf; + iov.iov_len = len; + + return wbuf_newv(len, &iov, 1); +} + enum mog_write_state mog_tryflush(int fd, struct mog_wbuf **x) { struct mog_wbuf *wbuf = *x; @@ -82,7 +92,7 @@ retry: return NULL; } else if (w < 0) { switch (errno) { - case_EAGAIN: return wbuf_new(total, iov, iovcnt); + case_EAGAIN: return wbuf_newv(total, iov, iovcnt); case EINTR: goto retry; } return MOG_WR_ERROR; @@ -117,3 +127,43 @@ retry: goto retry; } } + +/* + * returns + * - NULL on full write + * - MOG_WR_ERROR on error (and sets errno) + * - address to a new mog_wbuf with unbuffered contents on partial write + */ +void * mog_trysend(int fd, void *buf, size_t len, off_t more) +{ + if (MOG_MSG_MORE) { + int flags = more > 0 ? MSG_MORE : 0; + + while (len > 0) { + ssize_t w = send(fd, buf, len, flags); + + if (w == (ssize_t)len) + return NULL; /* all done */ + + if (w < 0) { + switch (errno) { + case_EAGAIN: return wbuf_new(buf, len); + case EINTR: continue; + } + return MOG_WR_ERROR; + } else { + buf = (char *)buf + w; + len -= w; + } + } + + return NULL; + } else { + struct iovec iov; + + iov.iov_base = buf; + iov.iov_len = len; + + return mog_trywritev(fd, &iov, 1); + } +} |