@ -0,0 +1,15 @@ | |||
#include "iob_internal.h" | |||
int iob_addbuf(io_batch* b,void* buf,uint64 n) { | |||
io_entry* e=array_allocate(&b->b,sizeof(io_entry), | |||
array_length(&b->b,sizeof(io_entry))); | |||
if (!e) return 0; | |||
e->type=FROMBUF; | |||
e->fd=-1; | |||
e->buf=buf; | |||
e->n=n; | |||
e->offset=0; | |||
b->bytesleft+=n; | |||
++b->bufs; | |||
return 1; | |||
} |
@ -0,0 +1,15 @@ | |||
#include "iob_internal.h" | |||
int iob_addfile(io_batch* b,int64 fd,uint64 off,uint64 n) { | |||
io_entry* e=array_allocate(&b->b,sizeof(io_entry), | |||
array_length(&b->b,sizeof(io_entry))); | |||
if (!e) return 0; | |||
e->type=FROMFILE; | |||
e->fd=fd; | |||
e->buf=0; | |||
e->n=n; | |||
e->offset=off; | |||
b->bytesleft+=n; | |||
++b->files; | |||
return 1; | |||
} |
@ -0,0 +1,17 @@ | |||
#include <stdlib.h> | |||
#include "iob_internal.h" | |||
io_batch* iob_new(int hint_entries) { | |||
io_batch* b=(io_batch*)malloc(sizeof(io_batch)); | |||
if (!b) return 0; | |||
if (hint_entries) { | |||
if (!array_allocate(&b->b,sizeof(io_entry),hint_entries)) { | |||
free(b); | |||
return 0; | |||
} | |||
array_trunc(&b->b); | |||
} | |||
b->next=b->bufs=b->files=0; | |||
b->bytesleft=0; | |||
return b; | |||
} |
@ -0,0 +1,7 @@ | |||
#include <stdlib.h> | |||
#include "iob_internal.h" | |||
void iob_reset(io_batch* b) { | |||
array_reset(&b->b); | |||
free(b); | |||
} |
@ -0,0 +1,83 @@ | |||
#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) | |||
#define BSD_SENDFILE | |||
#endif | |||
#include <sys/types.h> | |||
#include <sys/socket.h> | |||
#include <sys/uio.h> | |||
#include <errno.h> | |||
#include <alloca.h> | |||
#include "iob_internal.h" | |||
int64 iob_send(int64 s,io_batch* b) { | |||
io_entry* e,* last; | |||
struct iovec* v; | |||
int64 sent; | |||
long i; | |||
long headers; | |||
#ifdef BSD_SENDFILE | |||
long trailers; | |||
#endif | |||
if (b->bytesleft==0) return 0; | |||
last=array_start(&b->b)+array_bytes(&b->b); | |||
if (!(e=array_get(&b->b,sizeof(io_entry),b->next))) | |||
return -1; /* can't happen error */ | |||
v=alloca(b->bufs*sizeof(struct iovec)); | |||
#ifdef BSD_SENDFILE | |||
/* BSD sendfile can send headers and trailers. If we run on BSD, we | |||
* should try to exploit this. */ | |||
headers=trailers=0; | |||
#endif | |||
for (i=0; e+i<last; ++i) { | |||
if (e[i].type==FROMFILE) break; | |||
v[i].iov_base=e[i].buf+e[i].offset; | |||
v[i].iov_len=e[i].n-e[i].offset; | |||
} | |||
headers=i; | |||
#ifdef BSD_SENDFILE | |||
if (e[i].type==FROMFILE) { | |||
off_t sbytes; | |||
struct sf_hdtr hdr; | |||
int r; | |||
for (++i; e+i<last; ++i) { | |||
if (e[i].type==FROMFILE) break; | |||
v[i-1].iov_base=e[i].buf+e[i].offset; | |||
v[i-1].iov_len=e[i].n-e[i].offset; | |||
++trailers; | |||
} | |||
hdr.headers=v; hdr.hdr_cnt=headers; | |||
hdr.trailers=v+headers; hdr.trl_cnt=trailers; | |||
r=sendfile(e[headers].fd,s,e[headers].off,nbytes,&hdr,&sbytes,0); | |||
if (r==0) | |||
sent=b->bytesleft; | |||
else if (r==-1 && errno==EAGAIN) | |||
sent=sbytes; | |||
else | |||
sent=-1; | |||
} else | |||
sent=writev(s,v,headers); | |||
#else | |||
if (headers) | |||
sent=writev(s,v,headers); | |||
else | |||
sent=io_sendfile(s,e->fd,e->offset,e->n); | |||
#endif | |||
if (sent==b->bytesleft) | |||
b->bytesleft=0; | |||
else if (sent>0) { | |||
int64 rest=sent; | |||
b->bytesleft-=rest; | |||
for (i=0; e+i<last; ++i) { | |||
if (e[i].n-e[i].offset<rest) { | |||
rest-=e[i].n-e[i].offset; | |||
++b->next; | |||
} else { | |||
e[i].offset+=rest; | |||
break; | |||
} | |||
} | |||
} | |||
return sent; | |||
} |
@ -0,0 +1,14 @@ | |||
#ifndef _IOB_H | |||
#define _IOB_H | |||
#include "io.h" | |||
typedef struct io_batch io_batch; | |||
io_batch* iob_new(int hint_entries); | |||
int iob_addbuf(io_batch* b,void* buf,uint64 n); | |||
int iob_addfile(io_batch* b,int64 fd,uint64 off,uint64 n); | |||
int64 iob_send(int64 s,io_batch* b); | |||
void iob_reset(io_batch* b); | |||
#endif |
@ -0,0 +1,15 @@ | |||
#include "iob.h" | |||
#include "array.h" | |||
struct io_batch { | |||
array b; | |||
uint64 bytesleft; | |||
long next,bufs,files; | |||
}; | |||
typedef struct io_entry { | |||
enum { FROMBUF, FROMFILE } type; | |||
int64 fd; | |||
char* buf; | |||
uint64 offset,n; | |||
} io_entry; |