on Linux, save a few syscalls by using sendto/sendmsg with MSG_MORE

instead of write/writev + setsockopt TCP_CORK
master
leitner 10 years ago
parent a691887e75
commit 953eb639b2

@ -127,6 +127,9 @@ int64 iob_send(int64 s,io_batch* b) {
int64 sent; int64 sent;
long i; long i;
long headers; long headers;
#ifdef MSG_MORE
int docork;
#endif
#ifdef HAVE_BSDSENDFILE #ifdef HAVE_BSDSENDFILE
long trailers; long trailers;
#endif #endif
@ -188,6 +191,45 @@ eagain:
} }
} }
#else #else
/* Linux has two ways to coalesce sent data; either setsockopt
* TCP_CORK or sendto/sendmsg with MSG_MORE. MSG_MORE saves syscalls
* in one scenario: when there is n buffers and then possibly one
* file to send. If there is more buffers after the file, then we
* need to use TCP_CORK to prevent the TCP push after the file. */
#ifdef MSG_MORE
if (e+i==last)
docork=-1; /* no files, only buffer, so no need for TCP_CORK or MSG_MORE */
else
docork=!(e+i+1==last);
if (docork>0)
setsockopt(s,IPPROTO_TCP,TCP_CORK,(int[]){ 1 },sizeof(int));
if (headers) {
if (docork<0) { /* write+writev */
if (headers==1) /* cosmetics for strace */
sent=write(s,v[0].iov_base,v[0].iov_len);
else
sent=writev(s,v,headers);
} else {
if (headers==1) /* cosmetics for strace */
sent=sendto(s,v[0].iov_base,v[0].iov_len,MSG_MORE, NULL, 0);
else {
struct msghdr msg;
memset(&msg,0,sizeof(msg));
msg.msg_iov=v;
msg.msg_iovlen=headers;
sent=sendmsg(s,&msg,MSG_MORE);
}
}
if (sent==-1) {
if (errno==EAGAIN) {
io_eagain_write(s);
return -1;
}
sent=-3;
}
} else
sent=io_sendfile(s,e->fd,e->offset,e->n);
#else /* !MSG_MORE */
#ifdef TCP_CORK #ifdef TCP_CORK
if (b->bufs && b->files && !b->next) { if (b->bufs && b->files && !b->next) {
static int one=1; static int one=1;
@ -208,16 +250,23 @@ eagain:
} }
} else } else
sent=io_sendfile(s,e->fd,e->offset,e->n); sent=io_sendfile(s,e->fd,e->offset,e->n);
#endif /* !MSG_MORE */
#endif #endif
if (sent>0) if (sent>0)
total+=sent; total+=sent;
else else
return total?total:(uint64)sent; return total?total:(uint64)sent;
if ((uint64)sent==b->bytesleft) { if ((uint64)sent==b->bytesleft) {
#ifdef MSG_MORE
if (docork==1) {
#endif
#ifdef TCP_CORK #ifdef TCP_CORK
if (b->bufs && b->files) { if (b->bufs && b->files) {
static int zero=0; static int zero=0;
setsockopt(s,IPPROTO_TCP,TCP_CORK,&zero,sizeof(zero)); setsockopt(s,IPPROTO_TCP,TCP_CORK,&zero,sizeof(zero));
}
#endif
#ifdef MSG_MORE
} }
#endif #endif
iob_reset(b); iob_reset(b);

@ -17,9 +17,12 @@ int main() {
assert(iob_addbuf(b,"Huhu",4)); assert(iob_addbuf(b,"Huhu",4));
assert(iob_addbuf(b," fnord\n",7)); assert(iob_addbuf(b," fnord\n",7));
assert(iob_addfile(b,fd,10,10)); assert(iob_addfile(b,fd,10,10));
iob_send(1,b);
#if 0
do { do {
r=iob_write(1,b,write_cb); r=iob_write(1,b,write_cb);
} while (r>0); } while (r>0);
#endif
iob_free(b); iob_free(b);
return 0; return 0;
} }

Loading…
Cancel
Save