diff options
author | wtc%netscape.com <devnull@localhost> | 1999-01-27 03:12:16 +0000 |
---|---|---|
committer | wtc%netscape.com <devnull@localhost> | 1999-01-27 03:12:16 +0000 |
commit | f5f0c32856af5ff53f6184f5bd40415697c65af9 (patch) | |
tree | a665cf96a597ba24401a9b40cc0730e9d579808c | |
parent | be8886c0c9dda78af92d492ec563e4b40e8af594 (diff) | |
download | nspr-hg-f5f0c32856af5ff53f6184f5bd40415697c65af9.tar.gz |
Bugsplat bug #340901: On AIX, PR_TransmitFile calls the new send_file()
system call if it is available. The patch is contributed by IBM's
Anthony Moore <anthonym@npec.netscape.com>.
-rw-r--r-- | pr/src/md/unix/unix_errors.c | 9 | ||||
-rw-r--r-- | pr/src/pthreads/ptio.c | 204 |
2 files changed, 209 insertions, 4 deletions
diff --git a/pr/src/md/unix/unix_errors.c b/pr/src/md/unix/unix_errors.c index b5bd7fa8..1c09f879 100644 --- a/pr/src/md/unix/unix_errors.c +++ b/pr/src/md/unix/unix_errors.c @@ -1525,8 +1525,15 @@ void _MD_unix_map_lockf_error(int err) } } +#ifdef AIX +void _MD_aix_map_sendfile_error(int oserror) +#endif + #ifdef HPUX11 void _MD_hpux_map_sendfile_error(int oserror) +#endif + +#if defined(AIX) || defined(HPUX11) { PRErrorCode prerror; @@ -1560,4 +1567,4 @@ void _MD_hpux_map_sendfile_error(int oserror) } PR_SetError(prerror, oserror); } -#endif /* HPUX11 */ +#endif /* defined(AIX) || defined(HPUX11) */ diff --git a/pr/src/pthreads/ptio.c b/pr/src/pthreads/ptio.c index 8bacb9b5..3607da99 100644 --- a/pr/src/pthreads/ptio.c +++ b/pr/src/pthreads/ptio.c @@ -44,12 +44,71 @@ #ifdef AIX /* To pick up sysconf() */ #include <unistd.h> +#include <dlfcn.h> /* for dlopen */ #else /* To pick up getrlimit() etc. */ #include <sys/time.h> #include <sys/resource.h> #endif +/* + * The send_file() system call is available in AIX 4.3.2 or later. + * If this file is compiled on an older AIX system, it attempts to + * look up the send_file symbol at run time to determine whether + * we can use the faster PR_TransmitFile implementation based on + * send_file(). On AIX 4.3.2 or later, we can safely skip this + * runtime function dispatching and just use the send_file based + * implementation. + */ +#ifdef AIX +#ifdef HAVE_SEND_FILE + +#define AIX_SEND_FILE(a, b, c) send_file(a, b, c) + +#else /* HAVE_SEND_FILE */ + +/* + * The following definitions match those in <sys/socket.h> + * on AIX 4.3.2. + */ + +/* + * Structure for the send_file() system call + */ +struct sf_parms { + /* --------- header parms ---------- */ + void *header_data; /* Input/Output. Points to header buf */ + uint_t header_length; /* Input/Output. Length of the header */ + /* --------- file parms ------------ */ + int file_descriptor; /* Input. File descriptor of the file */ + unsigned long long file_size; /* Output. Size of the file */ + unsigned long long file_offset; /* Input/Output. Starting offset */ + long long file_bytes; /* Input/Output. no. of bytes to send */ + /* --------- trailer parms --------- */ + void *trailer_data; /* Input/Output. Points to trailer buf */ + uint_t trailer_length; /* Input/Output. Length of the trailer */ + /* --------- return info ----------- */ + unsigned long long bytes_sent; /* Output. no. of bytes sent */ +}; + +/* + * Flags for the send_file() system call + */ +#define SF_CLOSE 0x00000001 /* close the socket after completion */ +#define SF_REUSE 0x00000002 /* reuse socket. not supported */ +#define SF_DONT_CACHE 0x00000004 /* don't apply network buffer cache */ +#define SF_SYNC_CACHE 0x00000008 /* sync/update network buffer cache */ + +/* + * prototype: size_t send_file(int *, struct sf_parms *, uint_t); + */ +static ssize_t (*pt_aix_sendfile_fptr)() = NULL; + +#define AIX_SEND_FILE(a, b, c) (*pt_aix_sendfile_fptr)(a, b, c) + +#endif /* HAVE_SEND_FILE */ +#endif /* AIX */ + #include "primpl.h" /* On Alpha Linux, these are already defined in sys/socket.h */ @@ -136,7 +195,8 @@ static PRBool IsValidNetAddrLen(const PRNetAddr *addr, PRInt32 addr_len) #if (defined(LINUX) && defined(__GLIBC__) && __GLIBC__ >= 2 \ && !defined(__alpha)) typedef socklen_t pt_SockLen; -#elif defined(AIX) || (defined(LINUX) && defined(__alpha)) +#elif (defined(AIX) && !defined(AIX4_1)) \ + || (defined(LINUX) && defined(__alpha)) typedef PRSize pt_SockLen; #else typedef PRIntn pt_SockLen; @@ -1042,6 +1102,31 @@ static PRBool pt_recvfrom_cont(pt_Continuation *op, PRInt16 revents) PR_FALSE : PR_TRUE; } /* pt_recvfrom_cont */ +#ifdef AIX +static PRBool pt_aix_transmitfile_cont(pt_Continuation *op, PRInt16 revents) +{ + struct sf_parms *sf_struct = (struct sf_parms *) op->arg2.buffer; + int rv; + + rv = AIX_SEND_FILE(&op->arg1.osfd, sf_struct, op->arg4.flags); + op->syserrno = errno; + + if (rv != -1) { + op->result.code += sf_struct->bytes_sent; + } else if (op->syserrno != EWOULDBLOCK && op->syserrno != EAGAIN) { + op->result.code = -1; + } else { + return PR_FALSE; + } + + if (rv == 1) { /* more data to send */ + return PR_FALSE; + } + + return PR_TRUE; +} +#endif /* AIX */ + #ifdef HPUX11 static PRBool pt_hpux_transmitfile_cont(pt_Continuation *op, PRInt16 revents) { @@ -1051,10 +1136,11 @@ static PRBool pt_hpux_transmitfile_cont(pt_Continuation *op, PRInt16 revents) count = sendfile(op->arg1.osfd, op->filedesc, op->arg3.offset, 0, hdtrl, op->arg4.flags); PR_ASSERT(count <= op->nbytes_to_send); + op->syserrno = errno; if (count != -1) { op->result.code += count; - } else if (errno != EWOULDBLOCK && errno != EAGAIN) { + } else if (op->syserrno != EWOULDBLOCK && op->syserrno != EAGAIN) { op->result.code = -1; } else { return PR_FALSE; @@ -1884,6 +1970,112 @@ static PRInt32 pt_RecvFrom(PRFileDesc *fd, void *buf, PRInt32 amount, return bytes; } /* pt_RecvFrom */ +#ifdef AIX +#ifndef HAVE_SEND_FILE +static pthread_once_t pt_aix_sendfile_once_block = PTHREAD_ONCE_INIT; + +static void pt_aix_sendfile_init_routine(void) +{ + void *handle = dlopen(NULL, RTLD_NOW | RTLD_GLOBAL); + pt_aix_sendfile_fptr = (ssize_t (*)()) dlsym(handle, "send_file"); + dlclose(handle); +} + +/* + * pt_AIXDispatchTransmitFile + */ +static PRInt32 pt_AIXDispatchTransmitFile(PRFileDesc *sd, PRFileDesc *fd, + const void *headers, PRInt32 hlen, PRTransmitFileFlags flags, + PRIntervalTime timeout) +{ + int rv; + + rv = pthread_once(&pt_aix_sendfile_once_block, + pt_aix_sendfile_init_routine); + PR_ASSERT(0 == rv); + if (pt_aix_sendfile_fptr) { + return pt_AIXTransmitFile(sd, fd, headers, hlen, flags, timeout); + } else { + return _PR_UnixTransmitFile(sd, fd, headers, hlen, flags, timeout); + } +} +#endif /* !HAVE_SEND_FILE */ + +/* + * pt_AIXTransmitFile + * + * Send file fd across socket sd. If headers is non-NULL, 'hlen' + * bytes of headers is sent before sending the file. + * + * 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 send_file() system + * call available in AIX 4.3.2. + */ + +static PRInt32 pt_AIXTransmitFile(PRFileDesc *sd, PRFileDesc *fd, + const void *headers, PRInt32 hlen, PRTransmitFileFlags flags, + PRIntervalTime timeout) +{ + struct sf_parms sf_struct; + uint_t send_flags; + ssize_t rv; + int syserrno; + PRInt32 count; + + sf_struct.header_data = (void *) headers; /* cast away the 'const' */ + sf_struct.header_length = hlen; + sf_struct.file_descriptor = fd->secret->md.osfd; + sf_struct.file_size = 0; + sf_struct.file_offset = 0; + sf_struct.file_bytes = -1; + sf_struct.trailer_data = NULL; + sf_struct.trailer_length = 0; + sf_struct.bytes_sent = 0; + + send_flags = 0; + + do { + rv = AIX_SEND_FILE(&sd->secret->md.osfd, &sf_struct, send_flags); + } while (rv == -1 && (syserrno = errno) == EINTR); + + if (rv == -1) { + if (syserrno == EAGAIN || syserrno == EWOULDBLOCK) { + count = 0; /* Not a real error. Need to continue. */ + } else { + count = -1; + } + } else { + count = sf_struct.bytes_sent; + } + + if ((rv == 1) || ((rv == -1) && (count == 0))) { + pt_Continuation op; + + op.arg1.osfd = sd->secret->md.osfd; + op.arg2.buffer = &sf_struct; + op.arg4.flags = send_flags; + op.result.code = count; + op.timeout = timeout; + op.function = pt_aix_transmitfile_cont; + op.event = POLLOUT | POLLPRI; + count = pt_Continue(&op); + syserrno = op.syserrno; + } + + if (count == -1) { + _MD_aix_map_sendfile_error(syserrno); + return -1; + } + if (flags & PR_TRANSMITFILE_CLOSE_SOCKET) { + PR_Close(sd); + } + return count; +} +#endif /* AIX */ + #ifdef HPUX11 /* * pt_HPUXTransmitFile @@ -1966,7 +2158,7 @@ static PRInt32 pt_HPUXTransmitFile(PRFileDesc *sd, PRFileDesc *fd, if (count == -1) { _MD_hpux_map_sendfile_error(syserrno); - return -1; + return -1; } if (flags & PR_TRANSMITFILE_CLOSE_SOCKET) { PR_Close(sd); @@ -1989,6 +2181,12 @@ static PRInt32 pt_TransmitFile( #ifdef HPUX11 return pt_HPUXTransmitFile(sd, fd, headers, hlen, flags, timeout); +#elif defined(AIX) +#ifdef HAVE_SEND_FILE + return pt_AIXTransmitFile(sd, fd, headers, hlen, flags, timeout); +#else + return pt_AIXDispatchTransmitFile(sd, fd, headers, hlen, flags, timeout); +#endif /* HAVE_SEND_FILE */ #else return _PR_UnixTransmitFile(sd, fd, headers, hlen, flags, timeout); #endif |