summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorwtc%netscape.com <devnull@localhost>1999-01-27 03:12:16 +0000
committerwtc%netscape.com <devnull@localhost>1999-01-27 03:12:16 +0000
commitf5f0c32856af5ff53f6184f5bd40415697c65af9 (patch)
treea665cf96a597ba24401a9b40cc0730e9d579808c
parentbe8886c0c9dda78af92d492ec563e4b40e8af594 (diff)
downloadnspr-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.c9
-rw-r--r--pr/src/pthreads/ptio.c204
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