📄 ptio.c
字号:
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- *//* * The contents of this file are subject to the Mozilla Public * License Version 1.1 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or * implied. See the License for the specific language governing * rights and limitations under the License. * * The Original Code is the Netscape Portable Runtime (NSPR). * * The Initial Developer of the Original Code is Netscape * Communications Corporation. Portions created by Netscape are * Copyright (C) 1998-2000 Netscape Communications Corporation. All * Rights Reserved. * * Contributor(s): * * Alternatively, the contents of this file may be used under the * terms of the GNU General Public License Version 2 or later (the * "GPL"), in which case the provisions of the GPL are applicable * instead of those above. If you wish to allow use of your * version of this file only under the terms of the GPL and not to * allow others to use your version of this file under the MPL, * indicate your decision by deleting the provisions above and * replace them with the notice and other provisions required by * the GPL. If you do not delete the provisions above, a recipient * may use your version of this file under either the MPL or the * GPL. *//*** File: ptio.c** Descritpion: Implemenation of I/O methods for pthreads*/#if defined(_PR_PTHREADS)#if defined(_PR_POLL_WITH_SELECT)/* set fd limit for select(), before including system header files */#define FD_SETSIZE (16 * 1024)#endif#include <pthread.h>#include <string.h> /* for memset() */#include <sys/types.h>#include <dirent.h>#include <fcntl.h>#include <unistd.h>#include <sys/socket.h>#include <sys/stat.h>#include <sys/uio.h>#include <sys/file.h>#include <sys/ioctl.h>#if defined(SOLARIS) || defined(UNIXWARE)#include <sys/filio.h> /* to pick up FIONREAD */#endif#ifdef _PR_POLL_AVAILABLE#include <poll.h>#endif#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#ifdef SOLARIS/* * Define HAVE_SENDFILEV if the system has the sendfilev() system call. * Code built this way won't run on a system without sendfilev(). * We can define HAVE_SENDFILEV by default when the minimum release * of Solaris that NSPR supports has sendfilev(). */#ifdef HAVE_SENDFILEV#include <sys/sendfile.h>#define SOLARIS_SENDFILEV(a, b, c, d) sendfilev((a), (b), (c), (d))#else#include <dlfcn.h> /* for dlopen *//* * Match the definitions in <sys/sendfile.h>. */typedef struct sendfilevec { int sfv_fd; /* input fd */ uint_t sfv_flag; /* flags */ off_t sfv_off; /* offset to start reading from */ size_t sfv_len; /* amount of data */} sendfilevec_t;#define SFV_FD_SELF (-2)/* * extern ssize_t sendfilev(int, const struct sendfilevec *, int, size_t *); */static ssize_t (*pt_solaris_sendfilev_fptr)() = NULL;#define SOLARIS_SENDFILEV(a, b, c, d) \ (*pt_solaris_sendfilev_fptr)((a), (b), (c), (d))#endif /* HAVE_SENDFILEV */#endif /* SOLARIS *//* * 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_SendFile/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 SF_CLOSE#define HAVE_SEND_FILE#endif#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 */#ifdef LINUX#include <sys/sendfile.h>#endif#include "primpl.h"#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#if defined(SOLARIS)#define _PRSockOptVal_t char *#elif defined(IRIX) || defined(OSF1) || defined(AIX) || defined(HPUX) \ || defined(LINUX) || defined(FREEBSD) || defined(BSDI) || defined(VMS) \ || defined(NTO) || defined(OPENBSD) || defined(DARWIN) \ || defined(UNIXWARE)#define _PRSockOptVal_t void *#else#error "Cannot determine architecture"#endif#if (defined(HPUX) && !defined(HPUX10_30) && !defined(HPUX11))#define _PRSelectFdSetArg_t int *#elif defined(AIX4_1)#define _PRSelectFdSetArg_t void *#elif defined(IRIX) || (defined(AIX) && !defined(AIX4_1)) \ || defined(OSF1) || defined(SOLARIS) \ || defined(HPUX10_30) || defined(HPUX11) || defined(LINUX) \ || defined(FREEBSD) || defined(NETBSD) || defined(OPENBSD) \ || defined(BSDI) || defined(VMS) || defined(NTO) || defined(DARWIN) \ || defined(UNIXWARE)#define _PRSelectFdSetArg_t fd_set *#else#error "Cannot determine architecture"#endifstatic PRFileDesc *pt_SetMethods( PRIntn osfd, PRDescType type, PRBool isAcceptedSocket, PRBool imported);static PRLock *_pr_flock_lock; /* For PR_LockFile() etc. */static PRCondVar *_pr_flock_cv; /* For PR_LockFile() etc. */static PRLock *_pr_rename_lock; /* For PR_Rename() *//**************************************************************************//* These two functions are only used in assertions. */#if defined(DEBUG)PRBool IsValidNetAddr(const PRNetAddr *addr){ if ((addr != NULL) && (addr->raw.family != AF_UNIX) && (addr->raw.family != PR_AF_INET6) && (addr->raw.family != AF_INET)) { return PR_FALSE; } return PR_TRUE;}static PRBool IsValidNetAddrLen(const PRNetAddr *addr, PRInt32 addr_len){ /* * The definition of the length of a Unix domain socket address * is not uniform, so we don't check it. */ if ((addr != NULL) && (addr->raw.family != AF_UNIX) && (PR_NETADDR_SIZE(addr) != addr_len)) {#if defined(LINUX) && __GLIBC__ == 2 && __GLIBC_MINOR__ == 1 /* * In glibc 2.1, struct sockaddr_in6 is 24 bytes. In glibc 2.2 * and in the 2.4 kernel, struct sockaddr_in6 has the scope_id * field and is 28 bytes. It is possible for socket functions * to return an addr_len greater than sizeof(struct sockaddr_in6). * We need to allow that. (Bugzilla bug #77264) */ if ((PR_AF_INET6 == addr->raw.family) && (sizeof(addr->ipv6) == addr_len)) { return PR_TRUE; }#endif return PR_FALSE; } return PR_TRUE;}#endif /* DEBUG *//*****************************************************************************//************************* I/O Continuation machinery ************************//*****************************************************************************//* * The polling interval defines the maximum amount of time that a thread * might hang up before an interrupt is noticed. */#define PT_DEFAULT_POLL_MSEC 5000#if defined(_PR_POLL_WITH_SELECT)#define PT_DEFAULT_SELECT_SEC (PT_DEFAULT_POLL_MSEC/PR_MSEC_PER_SEC)#define PT_DEFAULT_SELECT_USEC \ ((PT_DEFAULT_POLL_MSEC % PR_MSEC_PER_SEC) * PR_USEC_PER_MSEC)#endif/* * pt_SockLen is the type for the length of a socket address * structure, used in the address length argument to bind, * connect, accept, getsockname, getpeername, etc. Posix.1g * defines this type as socklen_t. It is size_t or int on * most current systems. */#if defined(HAVE_SOCKLEN_T) \ || (defined(LINUX) && defined(__GLIBC__) && __GLIBC__ >= 2)typedef socklen_t pt_SockLen;#elif (defined(AIX) && !defined(AIX4_1)) \ || defined(VMS)typedef PRSize pt_SockLen;#elsetypedef PRIntn pt_SockLen;#endiftypedef struct pt_Continuation pt_Continuation;typedef PRBool (*ContinuationFn)(pt_Continuation *op, PRInt16 revents);typedef enum pr_ContuationStatus{ pt_continuation_pending, pt_continuation_done} pr_ContuationStatus;struct pt_Continuation{ /* The building of the continuation operation */ ContinuationFn function; /* what function to continue */ union { PRIntn osfd; } arg1; /* #1 - the op's fd */ union { void* buffer; } arg2; /* #2 - primary transfer buffer */ union { PRSize amount; /* #3 - size of 'buffer', or */ pt_SockLen *addr_len; /* - length of address */#ifdef HPUX11 /* * For sendfile() */ struct file_spec { off_t offset; /* offset in file to send */ size_t nbytes; /* length of file data to send */ size_t st_size; /* file size */ } file_spec;#endif } arg3; union { PRIntn flags; } arg4; /* #4 - read/write flags */ union { PRNetAddr *addr; } arg5; /* #5 - send/recv address */#ifdef HPUX11 /* * For sendfile() */ int filedesc; /* descriptor of file to send */ int nbytes_to_send; /* size of header and file */#endif /* HPUX11 */ #ifdef SOLARIS /* * For sendfilev() */ 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 */ /* ** The representation and notification of the results of the operation. ** These function can either return an int return code or a pointer to ** some object. */ union { PRSize code; void *object; } result; PRIntn syserrno; /* in case it failed, why (errno) */ pr_ContuationStatus status; /* the status of the operation */};#if defined(DEBUG)PTDebug pt_debug; /* this is shared between several modules */PR_IMPLEMENT(void) PT_GetStats(PTDebug* here) { *here = pt_debug; }PR_IMPLEMENT(void) PT_FPrintStats(PRFileDesc *debug_out, const char *msg){ PTDebug stats; char buffer[100]; PRExplodedTime tod; PRInt64 elapsed, aMil; PT_GetStats(&stats); /* a copy */ PR_ExplodeTime(stats.timeStarted, PR_LocalTimeParameters, &tod); (void)PR_FormatTime(buffer, sizeof(buffer), "%T", &tod); LL_SUB(elapsed, PR_Now(), stats.timeStarted); LL_I2L(aMil, 1000000); LL_DIV(elapsed, elapsed, aMil); if (NULL != msg) PR_fprintf(debug_out, "%s", msg); PR_fprintf( debug_out, "\tstarted: %s[%lld]\n", buffer, elapsed); PR_fprintf( debug_out, "\tlocks [created: %u, destroyed: %u]\n", stats.locks_created, stats.locks_destroyed); PR_fprintf( debug_out, "\tlocks [acquired: %u, released: %u]\n", stats.locks_acquired, stats.locks_released); PR_fprintf( debug_out, "\tcvars [created: %u, destroyed: %u]\n", stats.cvars_created, stats.cvars_destroyed); PR_fprintf( debug_out, "\tcvars [notified: %u, delayed_delete: %u]\n", stats.cvars_notified, stats.delayed_cv_deletes);} /* PT_FPrintStats */#endif /* DEBUG */#if defined(_PR_POLL_WITH_SELECT)/* * OSF1 and HPUX report the POLLHUP event for a socket when the * shutdown(SHUT_WR) operation is called for the remote end, even though * the socket is still writeable. Use select(), instead of poll(), to * workaround this problem. */static void pt_poll_now_with_select(pt_Continuation *op){ PRInt32 msecs; fd_set rd, wr, *rdp, *wrp; struct timeval tv; PRIntervalTime epoch, now, elapsed, remaining; PRBool wait_for_remaining; PRThread *self = PR_GetCurrentThread(); PR_ASSERT(PR_INTERVAL_NO_WAIT != op->timeout); PR_ASSERT(op->arg1.osfd < FD_SETSIZE); switch (op->timeout) { case PR_INTERVAL_NO_TIMEOUT: tv.tv_sec = PT_DEFAULT_SELECT_SEC; tv.tv_usec = PT_DEFAULT_SELECT_USEC; do { PRIntn rv; if (op->event & POLLIN) { FD_ZERO(&rd); FD_SET(op->arg1.osfd, &rd); rdp = &rd; } else rdp = NULL; if (op->event & POLLOUT) { FD_ZERO(&wr); FD_SET(op->arg1.osfd, &wr); wrp = ≀
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -