зеркало из https://github.com/mozilla/pjs.git
Bugzilla bug 132208: implemented PR_SendFile on Linux with the sendfile
system call and the TCP_CORK socket option. r=jgmyers. Modified Files: _linux.h unix_errors.c ptio.c
This commit is contained in:
Родитель
a5d7e5a2e9
Коммит
f643d5b33d
|
@ -470,4 +470,6 @@ extern int __syscall_poll(struct pollfd *ufds, unsigned long int nfds,
|
|||
/* For writev() */
|
||||
#include <sys/uio.h>
|
||||
|
||||
extern void _MD_linux_map_sendfile_error(int err);
|
||||
|
||||
#endif /* nspr_linux_defs_h___ */
|
||||
|
|
|
@ -847,3 +847,10 @@ void _MD_solaris_map_sendfile_error(int err)
|
|||
_MD_unix_map_default_error(err) ;
|
||||
}
|
||||
#endif /* SOLARIS */
|
||||
|
||||
#ifdef LINUX
|
||||
void _MD_linux_map_sendfile_error(int err)
|
||||
{
|
||||
_MD_unix_map_default_error(err) ;
|
||||
}
|
||||
#endif /* LINUX */
|
||||
|
|
|
@ -173,11 +173,21 @@ static ssize_t (*pt_aix_sendfile_fptr)() = NULL;
|
|||
#endif /* HAVE_SEND_FILE */
|
||||
#endif /* AIX */
|
||||
|
||||
#ifdef LINUX
|
||||
#include <sys/sendfile.h>
|
||||
#endif
|
||||
|
||||
#include "primpl.h"
|
||||
|
||||
/* On Alpha Linux, these are already defined in sys/socket.h */
|
||||
#if !(defined(LINUX) && defined(__alpha))
|
||||
#include <netinet/tcp.h> /* TCP_NODELAY, TCP_MAXSEG */
|
||||
#ifdef LINUX
|
||||
/* TCP_CORK is not defined in <netinet/tcp.h> on Red Hat Linux 6.0 */
|
||||
#ifndef TCP_CORK
|
||||
#define TCP_CORK 3
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(SOLARIS)
|
||||
|
@ -339,6 +349,15 @@ struct pt_Continuation
|
|||
int nbytes_to_send; /* size of header and file */
|
||||
#endif /* SOLARIS */
|
||||
|
||||
#ifdef LINUX
|
||||
/*
|
||||
* For sendfile()
|
||||
*/
|
||||
int in_fd; /* descriptor of file to send */
|
||||
off_t offset;
|
||||
size_t count;
|
||||
#endif /* LINUX */
|
||||
|
||||
PRIntervalTime timeout; /* client (relative) timeout */
|
||||
|
||||
PRInt16 event; /* flags for poll()'s events */
|
||||
|
@ -1059,6 +1078,33 @@ static PRBool pt_solaris_sendfile_cont(pt_Continuation *op, PRInt16 revents)
|
|||
}
|
||||
#endif /* SOLARIS */
|
||||
|
||||
#ifdef LINUX
|
||||
static PRBool pt_linux_sendfile_cont(pt_Continuation *op, PRInt16 revents)
|
||||
{
|
||||
ssize_t rv;
|
||||
off_t oldoffset;
|
||||
|
||||
oldoffset = op->offset;
|
||||
rv = sendfile(op->arg1.osfd, op->in_fd, &op->offset, op->count);
|
||||
op->syserrno = errno;
|
||||
|
||||
if (rv == -1) {
|
||||
if (op->syserrno != EWOULDBLOCK && op->syserrno != EAGAIN) {
|
||||
op->result.code = -1;
|
||||
return PR_TRUE;
|
||||
}
|
||||
rv = 0;
|
||||
}
|
||||
PR_ASSERT(rv == op->offset - oldoffset);
|
||||
op->result.code += rv;
|
||||
if (rv < op->count) {
|
||||
op->count -= rv;
|
||||
return PR_FALSE;
|
||||
}
|
||||
return PR_TRUE;
|
||||
}
|
||||
#endif /* LINUX */
|
||||
|
||||
void _PR_InitIO(void)
|
||||
{
|
||||
#if defined(DEBUG)
|
||||
|
@ -2427,6 +2473,126 @@ static PRInt32 pt_SolarisDispatchSendFile(PRFileDesc *sd, PRSendFileData *sfd,
|
|||
|
||||
#endif /* SOLARIS */
|
||||
|
||||
#ifdef LINUX
|
||||
/*
|
||||
* pt_LinuxSendFile
|
||||
*
|
||||
* Send file sfd->fd across socket sd. If specified, header and trailer
|
||||
* buffers are sent before and after the file, respectively.
|
||||
*
|
||||
* PR_TRANSMITFILE_CLOSE_SOCKET flag - close socket after sending file
|
||||
*
|
||||
* return number of bytes sent or -1 on error
|
||||
*
|
||||
* This implementation takes advantage of the sendfile() system
|
||||
* call available in Linux kernel 2.2 or higher.
|
||||
*/
|
||||
|
||||
static PRInt32 pt_LinuxSendFile(PRFileDesc *sd, PRSendFileData *sfd,
|
||||
PRTransmitFileFlags flags, PRIntervalTime timeout)
|
||||
{
|
||||
struct stat statbuf;
|
||||
size_t file_nbytes_to_send;
|
||||
PRInt32 count = 0;
|
||||
ssize_t rv;
|
||||
int syserrno;
|
||||
off_t offset;
|
||||
PRBool tcp_cork_enabled = PR_FALSE;
|
||||
int tcp_cork;
|
||||
|
||||
if (sfd->file_nbytes == 0) {
|
||||
/* Get file size */
|
||||
if (fstat(sfd->fd->secret->md.osfd, &statbuf) == -1) {
|
||||
_PR_MD_MAP_FSTAT_ERROR(errno);
|
||||
return -1;
|
||||
}
|
||||
file_nbytes_to_send = statbuf.st_size - sfd->file_offset;
|
||||
} else {
|
||||
file_nbytes_to_send = sfd->file_nbytes;
|
||||
}
|
||||
|
||||
if (sfd->hlen != 0 || sfd->tlen != 0) {
|
||||
tcp_cork = 1;
|
||||
if (setsockopt(sd->secret->md.osfd, SOL_TCP, TCP_CORK,
|
||||
&tcp_cork, sizeof tcp_cork) == -1) {
|
||||
_PR_MD_MAP_SETSOCKOPT_ERROR(errno);
|
||||
return -1;
|
||||
}
|
||||
tcp_cork_enabled = PR_TRUE;
|
||||
}
|
||||
|
||||
if (sfd->hlen != 0) {
|
||||
count = PR_Send(sd, sfd->header, sfd->hlen, 0, timeout);
|
||||
if (count == -1) {
|
||||
goto failed;
|
||||
}
|
||||
}
|
||||
|
||||
if (file_nbytes_to_send != 0) {
|
||||
offset = sfd->file_offset;
|
||||
do {
|
||||
rv = sendfile(sd->secret->md.osfd, sfd->fd->secret->md.osfd,
|
||||
&offset, file_nbytes_to_send);
|
||||
} while (rv == -1 && (syserrno = errno) == EINTR);
|
||||
if (rv == -1) {
|
||||
if (syserrno != EAGAIN && syserrno != EWOULDBLOCK) {
|
||||
_MD_linux_map_sendfile_error(syserrno);
|
||||
count = -1;
|
||||
goto failed;
|
||||
}
|
||||
rv = 0;
|
||||
}
|
||||
PR_ASSERT(rv == offset - sfd->file_offset);
|
||||
count += rv;
|
||||
|
||||
if (rv < file_nbytes_to_send) {
|
||||
pt_Continuation op;
|
||||
|
||||
op.arg1.osfd = sd->secret->md.osfd;
|
||||
op.in_fd = sfd->fd->secret->md.osfd;
|
||||
op.offset = offset;
|
||||
op.count = file_nbytes_to_send - rv;
|
||||
op.result.code = count;
|
||||
op.timeout = timeout;
|
||||
op.function = pt_linux_sendfile_cont;
|
||||
op.event = POLLOUT | POLLPRI;
|
||||
count = pt_Continue(&op);
|
||||
syserrno = op.syserrno;
|
||||
if (count == -1) {
|
||||
_MD_linux_map_sendfile_error(syserrno);
|
||||
goto failed;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (sfd->tlen != 0) {
|
||||
rv = PR_Send(sd, sfd->trailer, sfd->tlen, 0, timeout);
|
||||
if (rv == -1) {
|
||||
count = -1;
|
||||
goto failed;
|
||||
}
|
||||
count += rv;
|
||||
}
|
||||
|
||||
failed:
|
||||
if (tcp_cork_enabled) {
|
||||
tcp_cork = 0;
|
||||
if (setsockopt(sd->secret->md.osfd, SOL_TCP, TCP_CORK,
|
||||
&tcp_cork, sizeof tcp_cork) == -1 && count != -1) {
|
||||
_PR_MD_MAP_SETSOCKOPT_ERROR(errno);
|
||||
count = -1;
|
||||
}
|
||||
}
|
||||
if (count != -1) {
|
||||
if (flags & PR_TRANSMITFILE_CLOSE_SOCKET) {
|
||||
PR_Close(sd);
|
||||
}
|
||||
PR_ASSERT(count == sfd->hlen + sfd->tlen + file_nbytes_to_send);
|
||||
}
|
||||
return count;
|
||||
}
|
||||
#endif /* LINUX */
|
||||
|
||||
#ifdef AIX
|
||||
extern int _pr_aix_send_file_use_disabled;
|
||||
#endif
|
||||
|
@ -2467,6 +2633,8 @@ static PRInt32 pt_SendFile(
|
|||
#else
|
||||
return(pt_SolarisDispatchSendFile(sd, sfd, flags, timeout));
|
||||
#endif /* HAVE_SENDFILEV */
|
||||
#elif defined(LINUX)
|
||||
return(pt_LinuxSendFile(sd, sfd, flags, timeout));
|
||||
#else
|
||||
return(PR_EmulateSendFile(sd, sfd, flags, timeout));
|
||||
#endif
|
||||
|
|
Загрузка…
Ссылка в новой задаче