-
Notifications
You must be signed in to change notification settings - Fork 654
Commit
Some platforms don't support sendfile() (netbsd, openbsd), others don't support arbitrary file descriptors (freebsd, darwin). Emulate sendfile() if need be.
- Loading branch information
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -245,21 +245,131 @@ static ssize_t uv__fs_readlink(uv_fs_t* req) { | |
} | ||
|
||
|
||
__attribute__((unused)) | ||
static ssize_t uv__fs_sendfile_emul(uv_fs_t* req) { | ||
int reset_nbio; | ||
int use_pread; | ||
off_t offset; | ||
ssize_t nsent; | ||
ssize_t nread; | ||
ssize_t nwritten; | ||
size_t buflen; | ||
size_t len; | ||
ssize_t n; | ||
int in_fd; | ||
int out_fd; | ||
char buf[8192]; | ||
|
||
len = req->len; | ||
in_fd = req->flags; | ||
out_fd = req->file; | ||
offset = req->off; | ||
use_pread = 1; | ||
reset_nbio = 0; | ||
|
||
/* Here are the rules regarding errors: | ||
* | ||
* 1. Read errors are reported only if nsent==0, otherwise we return nsent. | ||
* The user needs to know that some data has already been sent, to stop | ||
* him from sending it twice. | ||
* | ||
* 2. Write errors are always reported. Write errors are bad because they | ||
* mean data loss: we've read data but we can't write it out... | ||
This comment has been minimized.
Sorry, something went wrong.
This comment has been minimized.
Sorry, something went wrong.
bnoordhuis
Author
Contributor
|
||
*/ | ||
for (nsent = 0; (size_t) nsent < len; ) { | ||
buflen = len - nsent; | ||
|
||
if (buflen > sizeof(buf)) | ||
buflen = sizeof(buf); | ||
|
||
do { | ||
if (use_pread) | ||
nread = pread(in_fd, buf, buflen, offset); | ||
else | ||
nread = read(in_fd, buf, buflen); | ||
} | ||
while (nread == -1 && errno == EINTR); | ||
|
||
if (nread == 0) | ||
goto out; | ||
|
||
if (nread == -1) { | ||
if (use_pread && nsent == 0 && (errno == EIO || errno == ESPIPE)) { | ||
use_pread = 0; | ||
continue; | ||
} | ||
|
||
if (nsent == 0) | ||
nsent = -1; | ||
|
||
goto out; | ||
} | ||
|
||
for (nwritten = 0; nwritten < nread; ) { | ||
do | ||
This comment has been minimized.
Sorry, something went wrong. |
||
n = write(out_fd, buf + nwritten, nread - nwritten); | ||
while (n == -1 && errno == EINTR); | ||
|
||
if (n == -1) { | ||
if (errno == EAGAIN || errno == EWOULDBLOCK) { | ||
This comment has been minimized.
Sorry, something went wrong.
piscisaureus
|
||
uv__nonblock(out_fd, 0); | ||
reset_nbio = 1; | ||
continue; | ||
} | ||
|
||
nsent = -1; | ||
goto out; | ||
} | ||
|
||
nwritten += n; | ||
} | ||
|
||
offset += nread; | ||
nsent += nread; | ||
} | ||
|
||
out: | ||
if (reset_nbio) | ||
uv__nonblock(out_fd, 1); | ||
|
||
if (nsent != -1) | ||
req->off = offset; | ||
|
||
return nsent; | ||
} | ||
|
||
|
||
static ssize_t uv__fs_sendfile(uv_fs_t* req) { | ||
/* req->file is the out_fd, req->flags the in_fd */ | ||
int in_fd; | ||
int out_fd; | ||
|
||
in_fd = req->flags; | ||
out_fd = req->file; | ||
|
||
#if defined(__sun) | ||
{ | ||
struct stat s; | ||
|
||
if (fstat(in_fd, &s) == -1) | ||
return -1; | ||
|
||
if (!S_ISREG(s.st_mode)) | ||
return uv__fs_sendfile_emul(req); | ||
|
||
if (fstat(out_fd, &s) == -1) | ||
return -1; | ||
|
||
if (!S_ISSOCK(s.st_mode)) | ||
return uv__fs_sendfile_emul(req); | ||
} | ||
#endif | ||
|
||
#if defined(__linux__) || defined(__sun) | ||
return sendfile(req->file, req->flags, &req->off, req->len); | ||
return sendfile(out_fd, in_fd, &req->off, req->len); | ||
#elif defined(__APPLE__) || defined(__FreeBSD__) | ||
return sendfile(req->flags, | ||
req->file, | ||
req->off, | ||
req->len, | ||
NULL, | ||
&req->off, | ||
0); | ||
return sendfile(in_fd, out_fd, req->off, req->len, NULL, &req->off, 0); | ||
#else | ||
errno = ENOSYS; | ||
return -1; | ||
return uv__fs_sendfile_emul(req); | ||
#endif | ||
} | ||
|
||
|
1 comment
on commit b77b648
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
mostly lgtm, take care of the thread safety issue
Is it not an idea to return nwritten iff use_pread is true?