diff options
author | wtc%netscape.com <devnull@localhost> | 1998-09-25 20:34:39 +0000 |
---|---|---|
committer | wtc%netscape.com <devnull@localhost> | 1998-09-25 20:34:39 +0000 |
commit | a5cf3a954c0d28455f78eaffcd2067e961972933 (patch) | |
tree | cf0a94361c04135067133f9c138577166fbbb0be /pr | |
parent | 299a8c91a9d819a6d8e38032447c052271fc41e8 (diff) | |
download | nspr-hg-a5cf3a954c0d28455f78eaffcd2067e961972933.tar.gz |
NSPR20 v3.0 beta landing from NSPRPUB_RELEASE_3_0_LANDING_BRANCH.
Diffstat (limited to 'pr')
185 files changed, 20071 insertions, 8019 deletions
diff --git a/pr/include/MANIFEST b/pr/include/MANIFEST index 9cb2adea..6ef1b6d0 100644 --- a/pr/include/MANIFEST +++ b/pr/include/MANIFEST @@ -7,6 +7,7 @@ pratom.h prbit.h prclist.h prcmon.h +prcountr.h prcvar.h prdtoa.h prenv.h @@ -23,13 +24,16 @@ prmem.h prmon.h prmwait.h prnetdb.h +prolock.h prpdce.h prprf.h prproces.h prsystem.h prthread.h prtime.h +prtrace.h prtypes.h +prvrsion.h prwin16.h obsolete/protypes.h @@ -39,6 +43,3 @@ obsolete/probslet.h private/prpriv.h private/pprio.h private/pprthred.h - -md/prosdep.h -md/_macos.h diff --git a/pr/include/md/Makefile b/pr/include/md/Makefile index afb752ea..a365ef91 100644 --- a/pr/include/md/Makefile +++ b/pr/include/md/Makefile @@ -24,7 +24,11 @@ HEADERS = $(wildcard *.h) include $(MOD_DEPTH)/config/rules.mk ifeq ($(OS_ARCH),IRIX) -MDCPUCFG_H = _irix.cfg +ifeq ($(USE_64), 1) +MDCPUCFG_H = _irix64.cfg +else +MDCPUCFG_H = _irix32.cfg +endif endif ifeq ($(OS_ARCH),WINNT) @@ -55,12 +59,20 @@ ifeq ($(OS_ARCH),FreeBSD) MDCPUCFG_H = _freebsd.cfg endif +ifeq ($(OS_ARCH),OpenBSD) +MDCPUCFG_H = _openbsd.cfg +endif + ifeq ($(OS_ARCH),NetBSD) MDCPUCFG_H = _netbsd.cfg endif ifeq ($(OS_ARCH),HP-UX) -MDCPUCFG_H = _hpux.cfg +ifeq ($(USE_64), 1) +MDCPUCFG_H = _hpux64.cfg +else +MDCPUCFG_H = _hpux32.cfg +endif endif ifeq ($(OS_ARCH),Linux) diff --git a/pr/include/md/_aix.h b/pr/include/md/_aix.h index 7ea19b7f..cc7906c8 100644 --- a/pr/include/md/_aix.h +++ b/pr/include/md/_aix.h @@ -54,15 +54,31 @@ #define HAVE_DLL #define USE_DLFCN #define _PR_HAVE_SOCKADDR_LEN +#define _PR_POLL_AVAILABLE +#define _PR_USE_POLL +#define _PR_STAT_HAS_ONLY_ST_ATIME +/* Timer operations */ +#define AIX_TIMERS +#if defined(AIX_TIMERS) +extern PRIntervalTime _MD_AixGetInterval(void); +#define _MD_GET_INTERVAL _MD_AixGetInterval + +extern PRIntervalTime _MD_AixIntervalPerSec(void); +#define _MD_INTERVAL_PER_SEC _MD_AixIntervalPerSec + +#else /* defined(AIX_TIMERS) */ #define _MD_GET_INTERVAL _PR_UNIX_GetInterval #define _MD_INTERVAL_PER_SEC _PR_UNIX_TicksPerSecond +#endif /* defined(AIX_TIMERS) */ /* The atomic operations */ #include <sys/atomic_op.h> #define _PR_HAVE_ATOMIC_OPS +#define _PR_HAVE_ATOMIC_CAS #define _MD_INIT_ATOMIC() #define _MD_ATOMIC_INCREMENT(val) ((PRInt32)fetch_and_add((atomic_p)val, 1) + 1) +#define _MD_ATOMIC_ADD(ptr, val) ((PRInt32)fetch_and_add((atomic_p)ptr, val) + val) #define _MD_ATOMIC_DECREMENT(val) ((PRInt32)fetch_and_add((atomic_p)val, -1) - 1) #define _MD_ATOMIC_SET(val, newval) _AIX_AtomicSet(val, newval) @@ -138,6 +154,42 @@ struct _MDSegment { PRInt8 notused; }; +/* + * md-specific cpu structure field + */ +#define _PR_MD_MAX_OSFD FD_SETSIZE + +struct _MDCPU_Unix { + PRCList ioQ; + PRUint32 ioq_timeout; + PRInt32 ioq_max_osfd; + PRInt32 ioq_osfd_cnt; +#ifndef _PR_USE_POLL + fd_set fd_read_set, fd_write_set, fd_exception_set; + PRInt16 fd_read_cnt[_PR_MD_MAX_OSFD],fd_write_cnt[_PR_MD_MAX_OSFD], + fd_exception_cnt[_PR_MD_MAX_OSFD]; +#else + struct pollfd *ioq_pollfds; + int ioq_pollfds_size; +#endif /* _PR_USE_POLL */ +}; + +#define _PR_IOQ(_cpu) ((_cpu)->md.md_unix.ioQ) +#define _PR_ADD_TO_IOQ(_pq, _cpu) PR_APPEND_LINK(&_pq.links, &_PR_IOQ(_cpu)) +#define _PR_FD_READ_SET(_cpu) ((_cpu)->md.md_unix.fd_read_set) +#define _PR_FD_READ_CNT(_cpu) ((_cpu)->md.md_unix.fd_read_cnt) +#define _PR_FD_WRITE_SET(_cpu) ((_cpu)->md.md_unix.fd_write_set) +#define _PR_FD_WRITE_CNT(_cpu) ((_cpu)->md.md_unix.fd_write_cnt) +#define _PR_FD_EXCEPTION_SET(_cpu) ((_cpu)->md.md_unix.fd_exception_set) +#define _PR_FD_EXCEPTION_CNT(_cpu) ((_cpu)->md.md_unix.fd_exception_cnt) +#define _PR_IOQ_TIMEOUT(_cpu) ((_cpu)->md.md_unix.ioq_timeout) +#define _PR_IOQ_MAX_OSFD(_cpu) ((_cpu)->md.md_unix.ioq_max_osfd) +#define _PR_IOQ_OSFD_CNT(_cpu) ((_cpu)->md.md_unix.ioq_osfd_cnt) +#define _PR_IOQ_POLLFDS(_cpu) ((_cpu)->md.md_unix.ioq_pollfds) +#define _PR_IOQ_POLLFDS_SIZE(_cpu) ((_cpu)->md.md_unix.ioq_pollfds_size) + +#define _PR_IOQ_MIN_POLLFDS_SIZE(_cpu) 32 + struct _MDCPU { struct _MDCPU_Unix md_unix; }; diff --git a/pr/include/md/_bsdi.h b/pr/include/md/_bsdi.h index 3e3eca9f..2639b2e3 100644 --- a/pr/include/md/_bsdi.h +++ b/pr/include/md/_bsdi.h @@ -37,6 +37,8 @@ #define HAVE_BSD_FLOCK #define NEED_TIME_R #define _PR_HAVE_SOCKADDR_LEN +#define _PR_STAT_HAS_ST_ATIMESPEC +#define _PR_NO_LARGE_FILES #if defined(BSDI_2) #define PROT_NONE 0x0 @@ -110,6 +112,42 @@ struct _MDSegment { PRInt8 notused; }; +/* + * md-specific cpu structure field + */ +#define _PR_MD_MAX_OSFD FD_SETSIZE + +struct _MDCPU_Unix { + PRCList ioQ; + PRUint32 ioq_timeout; + PRInt32 ioq_max_osfd; + PRInt32 ioq_osfd_cnt; +#ifndef _PR_USE_POLL + fd_set fd_read_set, fd_write_set, fd_exception_set; + PRInt16 fd_read_cnt[_PR_MD_MAX_OSFD],fd_write_cnt[_PR_MD_MAX_OSFD], + fd_exception_cnt[_PR_MD_MAX_OSFD]; +#else + struct pollfd *ioq_pollfds; + int ioq_pollfds_size; +#endif /* _PR_USE_POLL */ +}; + +#define _PR_IOQ(_cpu) ((_cpu)->md.md_unix.ioQ) +#define _PR_ADD_TO_IOQ(_pq, _cpu) PR_APPEND_LINK(&_pq.links, &_PR_IOQ(_cpu)) +#define _PR_FD_READ_SET(_cpu) ((_cpu)->md.md_unix.fd_read_set) +#define _PR_FD_READ_CNT(_cpu) ((_cpu)->md.md_unix.fd_read_cnt) +#define _PR_FD_WRITE_SET(_cpu) ((_cpu)->md.md_unix.fd_write_set) +#define _PR_FD_WRITE_CNT(_cpu) ((_cpu)->md.md_unix.fd_write_cnt) +#define _PR_FD_EXCEPTION_SET(_cpu) ((_cpu)->md.md_unix.fd_exception_set) +#define _PR_FD_EXCEPTION_CNT(_cpu) ((_cpu)->md.md_unix.fd_exception_cnt) +#define _PR_IOQ_TIMEOUT(_cpu) ((_cpu)->md.md_unix.ioq_timeout) +#define _PR_IOQ_MAX_OSFD(_cpu) ((_cpu)->md.md_unix.ioq_max_osfd) +#define _PR_IOQ_OSFD_CNT(_cpu) ((_cpu)->md.md_unix.ioq_osfd_cnt) +#define _PR_IOQ_POLLFDS(_cpu) ((_cpu)->md.md_unix.ioq_pollfds) +#define _PR_IOQ_POLLFDS_SIZE(_cpu) ((_cpu)->md.md_unix.ioq_pollfds_size) + +#define _PR_IOQ_MIN_POLLFDS_SIZE(_cpu) 32 + struct _MDCPU { struct _MDCPU_Unix md_unix; }; diff --git a/pr/include/md/_darwin.cfg b/pr/include/md/_darwin.cfg index 73fc491c..a0787fc9 100644 --- a/pr/include/md/_darwin.cfg +++ b/pr/include/md/_darwin.cfg @@ -27,8 +27,14 @@ #define RHAPOSDY #endif +#if defined(i386) +#undef IS_BIG_ENDIAN +#define IS_LITTLE_ENDIAN 1 +#else #undef IS_LITTLE_ENDIAN #define IS_BIG_ENDIAN 1 +#endif + #define HAVE_LONG_LONG #undef HAVE_ALIGNED_DOUBLES #define HAVE_ALIGNED_LONGLONGS 1 @@ -53,6 +59,7 @@ #define PR_BITS_PER_FLOAT 32 #define PR_BITS_PER_DOUBLE 64 #define PR_BITS_PER_WORD 32 +#define PR_BITS_PER_DWORD 64 #define PR_BITS_PER_BYTE_LOG2 3 #define PR_BITS_PER_SHORT_LOG2 4 @@ -117,3 +124,4 @@ #endif /* NO_NSPR_10_SUPPORT */ #endif /* nspr_cpucfg___ */ + diff --git a/pr/include/md/_darwin.h b/pr/include/md/_darwin.h index 052da11f..476b8e38 100644 --- a/pr/include/md/_darwin.h +++ b/pr/include/md/_darwin.h @@ -38,24 +38,23 @@ #define _MD_MMAP_FLAGS MAP_PRIVATE #undef HAVE_STACK_GROWING_UP -#define HAVE_WEAK_MALLOC_SYMBOLS -/* do this until I figure out the rhapsody dll stuff. */ #define HAVE_DLL -#define USE_RLD -#define _PR_HAVE_SOCKADDR_LEN +#define _PR_HAVE_SOCKADDR_LEN +#define _PR_STAT_HAS_ST_ATIMESPEC +#define _PR_TIMESPEC_HAS_TS_SEC +#define _PR_NO_LARGE_FILES #define USE_SETJMP -#ifndef _PR_PTHREADS +#if !defined(_PR_PTHREADS) #include <setjmp.h> #define PR_CONTEXT_TYPE jmp_buf -#define CONTEXT(_th) ((_th)->md.context) - -#define _MD_GET_SP(_th) (_th)->md.context[0] -#define PR_NUM_GCREGS _JBLEN +#define CONTEXT(_th) ((_th)->md.context) +#define _MD_GET_SP(_th) (((struct sigcontext *) (_th)->md.context)->sc_onstack) +#define PR_NUM_GCREGS _JBLEN /* ** Initialize a thread context to run "_main()" when started @@ -66,7 +65,7 @@ if (setjmp(CONTEXT(_thread))) { \ _main(); \ } \ - _MD_GET_SP(_thread) = (int) ((_sp) - 64); \ + _MD_GET_SP(_thread) = (unsigned char*) ((_sp) - 64); \ } #define _MD_SWITCH_CONTEXT(_thread) \ @@ -113,6 +112,42 @@ struct _MDSegment { PRInt8 notused; }; +/* + * md-specific cpu structure field + */ +#define _PR_MD_MAX_OSFD FD_SETSIZE + +struct _MDCPU_Unix { + PRCList ioQ; + PRUint32 ioq_timeout; + PRInt32 ioq_max_osfd; + PRInt32 ioq_osfd_cnt; +#ifndef _PR_USE_POLL + fd_set fd_read_set, fd_write_set, fd_exception_set; + PRInt16 fd_read_cnt[_PR_MD_MAX_OSFD],fd_write_cnt[_PR_MD_MAX_OSFD], + fd_exception_cnt[_PR_MD_MAX_OSFD]; +#else + struct pollfd *ioq_pollfds; + int ioq_pollfds_size; +#endif /* _PR_USE_POLL */ +}; + +#define _PR_IOQ(_cpu) ((_cpu)->md.md_unix.ioQ) +#define _PR_ADD_TO_IOQ(_pq, _cpu) PR_APPEND_LINK(&_pq.links, &_PR_IOQ(_cpu)) +#define _PR_FD_READ_SET(_cpu) ((_cpu)->md.md_unix.fd_read_set) +#define _PR_FD_READ_CNT(_cpu) ((_cpu)->md.md_unix.fd_read_cnt) +#define _PR_FD_WRITE_SET(_cpu) ((_cpu)->md.md_unix.fd_write_set) +#define _PR_FD_WRITE_CNT(_cpu) ((_cpu)->md.md_unix.fd_write_cnt) +#define _PR_FD_EXCEPTION_SET(_cpu) ((_cpu)->md.md_unix.fd_exception_set) +#define _PR_FD_EXCEPTION_CNT(_cpu) ((_cpu)->md.md_unix.fd_exception_cnt) +#define _PR_IOQ_TIMEOUT(_cpu) ((_cpu)->md.md_unix.ioq_timeout) +#define _PR_IOQ_MAX_OSFD(_cpu) ((_cpu)->md.md_unix.ioq_max_osfd) +#define _PR_IOQ_OSFD_CNT(_cpu) ((_cpu)->md.md_unix.ioq_osfd_cnt) +#define _PR_IOQ_POLLFDS(_cpu) ((_cpu)->md.md_unix.ioq_pollfds) +#define _PR_IOQ_POLLFDS_SIZE(_cpu) ((_cpu)->md.md_unix.ioq_pollfds_size) + +#define _PR_IOQ_MIN_POLLFDS_SIZE(_cpu) 32 + struct _MDCPU { struct _MDCPU_Unix md_unix; }; @@ -149,14 +184,14 @@ extern void _MD_YIELD(void); #endif /* ! _PR_PTHREADS */ -extern void _MD_EarlyInit(void); -extern PRIntervalTime _PR_UNIX_GetInterval(void); -extern PRIntervalTime _PR_UNIX_TicksPerSecond(void); - -#define _MD_EARLY_INIT _MD_EarlyInit +#define _MD_EARLY_INIT _MD_EarlyInit #define _MD_FINAL_INIT _PR_UnixInit -#define _MD_GET_INTERVAL _PR_UNIX_GetInterval -#define _MD_INTERVAL_PER_SEC _PR_UNIX_TicksPerSecond +#define _MD_GET_INTERVAL _PR_UNIX_GetInterval +#define _MD_INTERVAL_PER_SEC _PR_UNIX_TicksPerSecond + +extern void _MD_EarlyInit(void); +extern PRIntervalTime _PR_UNIX_GetInterval(void); +extern PRIntervalTime _PR_UNIX_TicksPerSecond(void); /* * We wrapped the select() call. _MD_SELECT refers to the built-in, diff --git a/pr/include/md/_dgux.cfg b/pr/include/md/_dgux.cfg index 4fb5dd46..4cde625a 100644 --- a/pr/include/md/_dgux.cfg +++ b/pr/include/md/_dgux.cfg @@ -71,9 +71,6 @@ #define PR_ALIGN_OF_DOUBLE 4 #define PR_ALIGN_OF_POINTER 4 -#define _PR_USE_POLL -#define _PR_POLL_AVAILABLE - #ifndef NO_NSPR_10_SUPPORT #define BYTES_PER_BYTE PR_BYTES_PER_BYTE diff --git a/pr/include/md/_dgux.h b/pr/include/md/_dgux.h index 2c3e4f49..f428e03a 100644 --- a/pr/include/md/_dgux.h +++ b/pr/include/md/_dgux.h @@ -44,6 +44,8 @@ #define NEED_STRFTIME_LOCK #define NEED_TIME_R #define _PR_NEED_STRCASECMP +#define _PR_POLL_AVAILABLE +#define _PR_USE_POLL #define USE_SETJMP diff --git a/pr/include/md/_freebsd.h b/pr/include/md/_freebsd.h index 916c11c2..6e459fb5 100644 --- a/pr/include/md/_freebsd.h +++ b/pr/include/md/_freebsd.h @@ -37,6 +37,8 @@ #define HAVE_DLL #define USE_DLFCN #define _PR_HAVE_SOCKADDR_LEN +#define _PR_STAT_HAS_ST_ATIMESPEC +#define _PR_NO_LARGE_FILES #define USE_SETJMP @@ -106,6 +108,42 @@ struct _MDSegment { PRInt8 notused; }; +/* + * md-specific cpu structure field + */ +#define _PR_MD_MAX_OSFD FD_SETSIZE + +struct _MDCPU_Unix { + PRCList ioQ; + PRUint32 ioq_timeout; + PRInt32 ioq_max_osfd; + PRInt32 ioq_osfd_cnt; +#ifndef _PR_USE_POLL + fd_set fd_read_set, fd_write_set, fd_exception_set; + PRInt16 fd_read_cnt[_PR_MD_MAX_OSFD],fd_write_cnt[_PR_MD_MAX_OSFD], + fd_exception_cnt[_PR_MD_MAX_OSFD]; +#else + struct pollfd *ioq_pollfds; + int ioq_pollfds_size; +#endif /* _PR_USE_POLL */ +}; + +#define _PR_IOQ(_cpu) ((_cpu)->md.md_unix.ioQ) +#define _PR_ADD_TO_IOQ(_pq, _cpu) PR_APPEND_LINK(&_pq.links, &_PR_IOQ(_cpu)) +#define _PR_FD_READ_SET(_cpu) ((_cpu)->md.md_unix.fd_read_set) +#define _PR_FD_READ_CNT(_cpu) ((_cpu)->md.md_unix.fd_read_cnt) +#define _PR_FD_WRITE_SET(_cpu) ((_cpu)->md.md_unix.fd_write_set) +#define _PR_FD_WRITE_CNT(_cpu) ((_cpu)->md.md_unix.fd_write_cnt) +#define _PR_FD_EXCEPTION_SET(_cpu) ((_cpu)->md.md_unix.fd_exception_set) +#define _PR_FD_EXCEPTION_CNT(_cpu) ((_cpu)->md.md_unix.fd_exception_cnt) +#define _PR_IOQ_TIMEOUT(_cpu) ((_cpu)->md.md_unix.ioq_timeout) +#define _PR_IOQ_MAX_OSFD(_cpu) ((_cpu)->md.md_unix.ioq_max_osfd) +#define _PR_IOQ_OSFD_CNT(_cpu) ((_cpu)->md.md_unix.ioq_osfd_cnt) +#define _PR_IOQ_POLLFDS(_cpu) ((_cpu)->md.md_unix.ioq_pollfds) +#define _PR_IOQ_POLLFDS_SIZE(_cpu) ((_cpu)->md.md_unix.ioq_pollfds_size) + +#define _PR_IOQ_MIN_POLLFDS_SIZE(_cpu) 32 + struct _MDCPU { struct _MDCPU_Unix md_unix; }; diff --git a/pr/include/md/_hpux.h b/pr/include/md/_hpux.h index 2675a97e..f9e312a4 100644 --- a/pr/include/md/_hpux.h +++ b/pr/include/md/_hpux.h @@ -43,6 +43,9 @@ #ifndef HAVE_STRERROR #define HAVE_STRERROR #endif +#define _PR_POLL_AVAILABLE +#define _PR_USE_POLL +#define _PR_STAT_HAS_ONLY_ST_ATIME #undef _PR_HAVE_ATOMIC_OPS @@ -117,6 +120,42 @@ struct _MDSegment { PRInt8 notused; }; +/* + * md-specific cpu structure field + */ +#define _PR_MD_MAX_OSFD FD_SETSIZE + +struct _MDCPU_Unix { + PRCList ioQ; + PRUint32 ioq_timeout; + PRInt32 ioq_max_osfd; + PRInt32 ioq_osfd_cnt; +#ifndef _PR_USE_POLL + fd_set fd_read_set, fd_write_set, fd_exception_set; + PRInt16 fd_read_cnt[_PR_MD_MAX_OSFD],fd_write_cnt[_PR_MD_MAX_OSFD], + fd_exception_cnt[_PR_MD_MAX_OSFD]; +#else + struct pollfd *ioq_pollfds; + int ioq_pollfds_size; +#endif /* _PR_USE_POLL */ +}; + +#define _PR_IOQ(_cpu) ((_cpu)->md.md_unix.ioQ) +#define _PR_ADD_TO_IOQ(_pq, _cpu) PR_APPEND_LINK(&_pq.links, &_PR_IOQ(_cpu)) +#define _PR_FD_READ_SET(_cpu) ((_cpu)->md.md_unix.fd_read_set) +#define _PR_FD_READ_CNT(_cpu) ((_cpu)->md.md_unix.fd_read_cnt) +#define _PR_FD_WRITE_SET(_cpu) ((_cpu)->md.md_unix.fd_write_set) +#define _PR_FD_WRITE_CNT(_cpu) ((_cpu)->md.md_unix.fd_write_cnt) +#define _PR_FD_EXCEPTION_SET(_cpu) ((_cpu)->md.md_unix.fd_exception_set) +#define _PR_FD_EXCEPTION_CNT(_cpu) ((_cpu)->md.md_unix.fd_exception_cnt) +#define _PR_IOQ_TIMEOUT(_cpu) ((_cpu)->md.md_unix.ioq_timeout) +#define _PR_IOQ_MAX_OSFD(_cpu) ((_cpu)->md.md_unix.ioq_max_osfd) +#define _PR_IOQ_OSFD_CNT(_cpu) ((_cpu)->md.md_unix.ioq_osfd_cnt) +#define _PR_IOQ_POLLFDS(_cpu) ((_cpu)->md.md_unix.ioq_pollfds) +#define _PR_IOQ_POLLFDS_SIZE(_cpu) ((_cpu)->md.md_unix.ioq_pollfds_size) + +#define _PR_IOQ_MIN_POLLFDS_SIZE(_cpu) 32 + struct _MDCPU { struct _MDCPU_Unix md_unix; }; @@ -150,8 +189,16 @@ struct _MDCPU { #define _MD_FINAL_INIT _PR_UnixInit #endif +#if defined(HPUX_LW_TIMER) +extern void _PR_HPUX_LW_IntervalInit(void); +extern PRIntervalTime _PR_HPUX_LW_GetInterval(void); +#define _MD_INTERVAL_INIT _PR_HPUX_LW_IntervalInit +#define _MD_GET_INTERVAL _PR_HPUX_LW_GetInterval +#define _MD_INTERVAL_PER_SEC() 1000 +#else #define _MD_GET_INTERVAL _PR_UNIX_GetInterval #define _MD_INTERVAL_PER_SEC _PR_UNIX_TicksPerSecond +#endif /* * We wrapped the select() call. _MD_SELECT refers to the built-in, @@ -160,8 +207,6 @@ struct _MDCPU { #define _MD_SELECT(nfds,r,w,e,tv) syscall(SYS_select,nfds,r,w,e,tv) #define _MD_POLL(fds,nfds,timeout) syscall(SYS_poll,fds,nfds,timeout) -extern void _MD_hpux_install_sigfpe_handler(void); - #ifdef HPUX11 extern void _MD_hpux_map_sendfile_error(int err); #if !defined(_PR_PTHREADS) diff --git a/pr/include/md/_hpux.cfg b/pr/include/md/_hpux32.cfg index 885af381..2889f693 100644 --- a/pr/include/md/_hpux.cfg +++ b/pr/include/md/_hpux32.cfg @@ -69,9 +69,9 @@ #define PR_ALIGN_OF_DOUBLE 8 #define PR_ALIGN_OF_POINTER 4 -#undef HAVE_LONG_LONG +#define HAVE_LONG_LONG #define HAVE_ALIGNED_DOUBLES -#undef HAVE_ALIGNED_LONGLONGS +#define HAVE_ALIGNED_LONGLONGS #ifndef NO_NSPR_10_SUPPORT diff --git a/pr/include/md/_hpux64.cfg b/pr/include/md/_hpux64.cfg new file mode 100644 index 00000000..f790215c --- /dev/null +++ b/pr/include/md/_hpux64.cfg @@ -0,0 +1,122 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "NPL"); you may not use this file except in + * compliance with the NPL. You may obtain a copy of the NPL at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the NPL is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL + * for the specific language governing rights and limitations under the + * NPL. + * + * The Initial Developer of this code under the NPL is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All Rights + * Reserved. + */ + +#ifndef nspr_cpucfg___ +#define nspr_cpucfg___ + +#ifndef XP_UNIX +#define XP_UNIX +#endif + +#ifndef HPUX +#define HPUX +#endif + +#undef IS_LITTLE_ENDIAN +#define IS_BIG_ENDIAN 1 +#define IS_64 + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 8 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 8 +#define PR_BYTES_PER_DWORD 8 + +#define PR_BYTES_PER_WORD_LOG2 3 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 64 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 64 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 6 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 6 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 4 +#define PR_ALIGN_OF_INT64 4 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 8 +#define PR_ALIGN_OF_POINTER 8 + +#define HAVE_LONG_LONG +#define HAVE_ALIGNED_DOUBLES +#define HAVE_ALIGNED_LONGLONGS + +#ifndef NO_NSPR_10_SUPPORT + +#define BYTES_PER_BYTE PR_BYTES_PER_BYTE +#define BYTES_PER_SHORT PR_BYTES_PER_SHORT +#define BYTES_PER_INT PR_BYTES_PER_INT +#define BYTES_PER_INT64 PR_BYTES_PER_INT64 +#define BYTES_PER_LONG PR_BYTES_PER_LONG +#define BYTES_PER_FLOAT PR_BYTES_PER_FLOAT +#define BYTES_PER_DOUBLE PR_BYTES_PER_DOUBLE +#define BYTES_PER_WORD PR_BYTES_PER_WORD +#define BYTES_PER_DWORD PR_BYTES_PER_DWORD + +#define BITS_PER_BYTE PR_BITS_PER_BYTE +#define BITS_PER_SHORT PR_BITS_PER_SHORT +#define BITS_PER_INT PR_BITS_PER_INT +#define BITS_PER_INT64 PR_BITS_PER_INT64 +#define BITS_PER_LONG PR_BITS_PER_LONG +#define BITS_PER_FLOAT PR_BITS_PER_FLOAT +#define BITS_PER_DOUBLE PR_BITS_PER_DOUBLE +#define BITS_PER_WORD PR_BITS_PER_WORD + +#define BITS_PER_BYTE_LOG2 PR_BITS_PER_BYTE_LOG2 +#define BITS_PER_SHORT_LOG2 PR_BITS_PER_SHORT_LOG2 +#define BITS_PER_INT_LOG2 PR_BITS_PER_INT_LOG2 +#define BITS_PER_INT64_LOG2 PR_BITS_PER_INT64_LOG2 +#define BITS_PER_LONG_LOG2 PR_BITS_PER_LONG_LOG2 +#define BITS_PER_FLOAT_LOG2 PR_BITS_PER_FLOAT_LOG2 +#define BITS_PER_DOUBLE_LOG2 PR_BITS_PER_DOUBLE_LOG2 +#define BITS_PER_WORD_LOG2 PR_BITS_PER_WORD_LOG2 + +#define ALIGN_OF_SHORT PR_ALIGN_OF_SHORT +#define ALIGN_OF_INT PR_ALIGN_OF_INT +#define ALIGN_OF_LONG PR_ALIGN_OF_LONG +#define ALIGN_OF_INT64 PR_ALIGN_OF_INT64 +#define ALIGN_OF_FLOAT PR_ALIGN_OF_FLOAT +#define ALIGN_OF_DOUBLE PR_ALIGN_OF_DOUBLE +#define ALIGN_OF_POINTER PR_ALIGN_OF_POINTER +#define ALIGN_OF_WORD PR_ALIGN_OF_WORD + +#define BYTES_PER_WORD_LOG2 PR_BYTES_PER_WORD_LOG2 +#define BYTES_PER_DWORD_LOG2 PR_BYTES_PER_DWORD_LOG2 +#define WORDS_PER_DWORD_LOG2 PR_WORDS_PER_DWORD_LOG2 + +#endif /* NO_NSPR_10_SUPPORT */ + +#endif /* nspr_cpucfg___ */ diff --git a/pr/include/md/_irix.h b/pr/include/md/_irix.h index 694b809b..b6b2b034 100644 --- a/pr/include/md/_irix.h +++ b/pr/include/md/_irix.h @@ -19,6 +19,13 @@ #ifndef nspr_irix_defs_h___ #define nspr_irix_defs_h___ +#define _PR_HAVE_ATOMIC_CAS + +/* + * MipsPro assembler defines _LANGUAGE_ASSEMBLY + */ +#ifndef _LANGUAGE_ASSEMBLY + #include "prclist.h" #include "prthread.h" #include <sys/ucontext.h> @@ -46,6 +53,11 @@ #define HAVE_DLL #define USE_DLFCN #define _PR_HAVE_ATOMIC_OPS +#define _PR_POLL_AVAILABLE +#define _PR_USE_POLL +#define _PR_STAT_HAS_ST_ATIM +#define _PR_HAVE_OFF64_T +#define HAVE_POINTER_LOCALTIME_R /* Initialization entry points */ PR_EXTERN(void) _MD_EarlyInit(void); @@ -57,11 +69,11 @@ PR_EXTERN(void) _MD_IrixInit(void); #define _MD_INIT_IO() /* Timer operations */ -PR_EXTERN(PRIntervalTime) _MD_GetInterval(void); -#define _MD_GET_INTERVAL _MD_GetInterval +PR_EXTERN(PRIntervalTime) _MD_IrixGetInterval(void); +#define _MD_GET_INTERVAL _MD_IrixGetInterval -PR_EXTERN(PRIntervalTime) _MD_IntervalPerSec(void); -#define _MD_INTERVAL_PER_SEC _MD_IntervalPerSec +PR_EXTERN(PRIntervalTime) _MD_IrixIntervalPerSec(void); +#define _MD_INTERVAL_PER_SEC _MD_IrixIntervalPerSec /* GC operations */ PR_EXTERN(void *) _MD_GetSP(PRThread *thread); @@ -71,6 +83,7 @@ PR_EXTERN(void *) _MD_GetSP(PRThread *thread); #include <mutex.h> #define _MD_INIT_ATOMIC() #define _MD_ATOMIC_INCREMENT(val) add_then_test((unsigned long*)val, 1) +#define _MD_ATOMIC_ADD(ptr, val) add_then_test((unsigned long*)ptr, (unsigned long)val) #define _MD_ATOMIC_DECREMENT(val) add_then_test((unsigned long*)val, 0xffffffff) #define _MD_ATOMIC_SET(val, newval) test_and_set((unsigned long*)val, newval) @@ -107,8 +120,8 @@ struct sproc_private_data { extern char *_nspr_sproc_private; #define _PR_PRDA() ((struct sproc_private_data *) _nspr_sproc_private) -#define _MD_CURRENT_THREAD() (_PR_PRDA()->me) #define _MD_SET_CURRENT_THREAD(_thread) _PR_PRDA()->me = (_thread) +#define _MD_THIS_THREAD() (_PR_PRDA()->me) #define _MD_LAST_THREAD() (_PR_PRDA()->last) #define _MD_SET_LAST_THREAD(_thread) _PR_PRDA()->last = (_thread) #define _MD_CURRENT_CPU() (_PR_PRDA()->cpu) @@ -120,13 +133,16 @@ extern char *_nspr_sproc_private; #define _MD_GET_SPROC_PID() (_PR_PRDA()->sproc_pid) PR_EXTERN(struct PRThread*) _MD_get_attached_thread(void); +PR_EXTERN(struct PRThread*) _MD_get_current_thread(void); #define _MD_GET_ATTACHED_THREAD() _MD_get_attached_thread() +#define _MD_CURRENT_THREAD() _MD_get_current_thread() #define _MD_CHECK_FOR_EXIT() { \ - if (_pr_irix_exit_now) { \ + if (_pr_irix_exit_now) { \ _PR_POST_SEM(_pr_irix_exit_sem); \ - exit(0); \ - } \ + _MD_Wakeup_CPUs(); \ + _exit(0); \ + } \ } #define _MD_ATTACH_THREAD(threadp) @@ -137,23 +153,26 @@ PR_EXTERN(struct PRThread*) _MD_get_attached_thread(void); extern struct _PRCPU *_pr_primordialCPU; extern usema_t *_pr_irix_exit_sem; extern PRInt32 _pr_irix_exit_now; +extern int _pr_irix_primoridal_cpu_fd[]; +extern PRInt32 _pr_irix_process_exit; +extern PRInt32 _pr_irix_process_exit_code; /* Thread operations */ #define _PR_LOCK_HEAP() { \ PRIntn _is; \ if (_pr_primordialCPU) { \ - if (_PR_MD_CURRENT_THREAD() && \ + if (_MD_GET_ATTACHED_THREAD() && \ !_PR_IS_NATIVE_THREAD( \ - _PR_MD_CURRENT_THREAD())) \ + _MD_GET_ATTACHED_THREAD())) \ _PR_INTSOFF(_is); \ _PR_LOCK(_pr_heapLock); \ } #define _PR_UNLOCK_HEAP() if (_pr_primordialCPU) { \ _PR_UNLOCK(_pr_heapLock); \ - if (_PR_MD_CURRENT_THREAD() && \ + if (_MD_GET_ATTACHED_THREAD() && \ !_PR_IS_NATIVE_THREAD( \ - _PR_MD_CURRENT_THREAD())) \ + _MD_GET_ATTACHED_THREAD())) \ _PR_INTSON(_is); \ } \ } @@ -179,7 +198,7 @@ struct _MDLock { #define _PR_LOCK(lock) { \ PRIntn _is; \ - PRThread *me = _PR_MD_CURRENT_THREAD(); \ + PRThread *me = _MD_GET_ATTACHED_THREAD(); \ if (me && !_PR_IS_NATIVE_THREAD(me)) \ _PR_INTSOFF(_is); \ ussetlock(lock); \ @@ -189,7 +208,7 @@ struct _MDLock { #define _PR_UNLOCK(lock) { \ PRIntn _is; \ - PRThread *me = _PR_MD_CURRENT_THREAD(); \ + PRThread *me = _MD_GET_ATTACHED_THREAD(); \ if (me && !_PR_IS_NATIVE_THREAD(me)) \ _PR_INTSOFF(_is); \ usunsetlock(lock); \ @@ -216,9 +235,6 @@ struct _MDThread { PRInt32 id; PRInt32 suspending_id; int errcode; - PRStatus *creation_status; /* points to the variable in which - * a newly created child thread is - * to store its creation status */ }; struct _MDThreadStack { @@ -237,6 +253,43 @@ struct _MDSegment { PRInt8 notused; }; +/* + * md-specific cpu structure field + */ +#define _PR_MD_MAX_OSFD FD_SETSIZE + +struct _MDCPU_Unix { + PRCList ioQ; + PRUint32 ioq_timeout; + PRInt32 ioq_max_osfd; + PRInt32 ioq_osfd_cnt; +#ifndef _PR_USE_POLL + fd_set fd_read_set, fd_write_set, fd_exception_set; + PRInt16 fd_read_cnt[_PR_MD_MAX_OSFD],fd_write_cnt[_PR_MD_MAX_OSFD], + fd_exception_cnt[_PR_MD_MAX_OSFD]; +#else + struct pollfd *ioq_pollfds; + int ioq_pollfds_size; +#endif /* _PR_USE_POLL */ +}; + +#define _PR_IOQ(_cpu) ((_cpu)->md.md_unix.ioQ) +#define _PR_ADD_TO_IOQ(_pq, _cpu) PR_APPEND_LINK(&_pq.links, &_PR_IOQ(_cpu)) +#define _PR_FD_READ_SET(_cpu) ((_cpu)->md.md_unix.fd_read_set) +#define _PR_FD_READ_CNT(_cpu) ((_cpu)->md.md_unix.fd_read_cnt) +#define _PR_FD_WRITE_SET(_cpu) ((_cpu)->md.md_unix.fd_write_set) +#define _PR_FD_WRITE_CNT(_cpu) ((_cpu)->md.md_unix.fd_write_cnt) +#define _PR_FD_EXCEPTION_SET(_cpu) ((_cpu)->md.md_unix.fd_exception_set) +#define _PR_FD_EXCEPTION_CNT(_cpu) ((_cpu)->md.md_unix.fd_exception_cnt) +#define _PR_IOQ_TIMEOUT(_cpu) ((_cpu)->md.md_unix.ioq_timeout) +#define _PR_IOQ_MAX_OSFD(_cpu) ((_cpu)->md.md_unix.ioq_max_osfd) +#define _PR_IOQ_OSFD_CNT(_cpu) ((_cpu)->md.md_unix.ioq_osfd_cnt) +#define _PR_IOQ_POLLFDS(_cpu) ((_cpu)->md.md_unix.ioq_pollfds) +#define _PR_IOQ_POLLFDS_SIZE(_cpu) ((_cpu)->md.md_unix.ioq_pollfds_size) + +#define _PR_IOQ_MIN_POLLFDS_SIZE(_cpu) 32 + + struct _MDCPU { PRInt32 id; PRInt32 suspending_id; @@ -290,9 +343,13 @@ struct _MDCPU { longjmp(jb, 1); \ PR_END_MACRO -PR_EXTERN(PRStatus) _MD_InitThread(struct PRThread *thread, PRBool wakeup_parent); +PR_EXTERN(PRStatus) _MD_InitThread(struct PRThread *thread, + PRBool wakeup_parent); +PR_EXTERN(PRStatus) _MD_InitAttachedThread(struct PRThread *thread, + PRBool wakeup_parent); #define _MD_INIT_THREAD(thread) _MD_InitThread(thread, PR_TRUE) -#define _MD_INIT_ATTACHED_THREAD(thread) _MD_InitThread(thread, PR_FALSE) +#define _MD_INIT_ATTACHED_THREAD(thread) \ + _MD_InitAttachedThread(thread, PR_FALSE) PR_EXTERN(void) _MD_ExitThread(struct PRThread *thread); #define _MD_EXIT_THREAD _MD_ExitThread @@ -329,6 +386,9 @@ PR_EXTERN(void) _MD_CleanThread(struct PRThread *thread); PR_EXTERN(PRStatus) _MD_wait(struct PRThread *, PRIntervalTime timeout); #define _MD_WAIT _MD_wait +PR_EXTERN(void) _PR_MD_primordial_cpu(); +PR_EXTERN(void) _PR_MD_WAKEUP_PRIMORDIAL_CPU(); + PR_EXTERN(PRStatus) _MD_WakeupWaiter(struct PRThread *); #define _MD_WAKEUP_WAITER _MD_WakeupWaiter @@ -353,6 +413,8 @@ PR_EXTERN(PRStatus) _MD_CreateThread( extern void _MD_CleanupBeforeExit(void); #define _MD_CLEANUP_BEFORE_EXIT _MD_CleanupBeforeExit +PR_EXTERN(void) _PR_MD_PRE_CLEANUP(PRThread *me); + /* The following defines the unwrapped versions of select() and poll(). */ extern int _select(int nfds, fd_set *readfds, fd_set *writefds, @@ -375,4 +437,6 @@ PR_EXTERN(void) _MD_InitRunningCPU(struct _PRCPU *cpu); #endif /* defined(_PR_PTHREADS) */ +#endif /* _LANGUAGE_ASSEMBLY */ + #endif /* nspr_irix_defs_h___ */ diff --git a/pr/include/md/_irix.cfg b/pr/include/md/_irix32.cfg index 2070760b..c5016880 100644 --- a/pr/include/md/_irix.cfg +++ b/pr/include/md/_irix32.cfg @@ -78,8 +78,7 @@ #define HAVE_ALIGNED_DOUBLES #define HAVE_ALIGNED_LONGLONGS -#define _PR_POLL_AVAILABLE -#define _PR_USE_POLL +#define _PR_POLL_BACKCOMPAT #ifndef NO_NSPR_10_SUPPORT diff --git a/pr/include/md/_irix64.cfg b/pr/include/md/_irix64.cfg new file mode 100644 index 00000000..7df5f997 --- /dev/null +++ b/pr/include/md/_irix64.cfg @@ -0,0 +1,127 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "NPL"); you may not use this file except in + * compliance with the NPL. You may obtain a copy of the NPL at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the NPL is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL + * for the specific language governing rights and limitations under the + * NPL. + * + * The Initial Developer of this code under the NPL is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All Rights + * Reserved. + */ + +#ifndef nspr_cpucfg___ +#define nspr_cpucfg___ + +#ifndef _SGI_MP_SOURCE +#define _SGI_MP_SOURCE +#endif + +#ifndef XP_UNIX +#define XP_UNIX +#endif + +#ifndef IRIX +#define IRIX +#endif + +#undef IS_LITTLE_ENDIAN +#define IS_BIG_ENDIAN 1 +#define IS_64 + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 8 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 8 +#define PR_BYTES_PER_DWORD 8 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 64 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 64 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 6 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 6 + +#define PR_BYTES_PER_WORD_LOG2 3 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 4 +#define PR_ALIGN_OF_INT64 8 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 8 +#define PR_ALIGN_OF_POINTER 4 +#define PR_ALIGN_OF_WORD 4 + +#define HAVE_LONG_LONG +#define HAVE_ALIGNED_DOUBLES +#define HAVE_ALIGNED_LONGLONGS + +#ifndef NO_NSPR_10_SUPPORT + +#define BYTES_PER_BYTE PR_BYTES_PER_BYTE +#define BYTES_PER_SHORT PR_BYTES_PER_SHORT +#define BYTES_PER_INT PR_BYTES_PER_INT +#define BYTES_PER_INT64 PR_BYTES_PER_INT64 +#define BYTES_PER_LONG PR_BYTES_PER_LONG +#define BYTES_PER_FLOAT PR_BYTES_PER_FLOAT +#define BYTES_PER_DOUBLE PR_BYTES_PER_DOUBLE +#define BYTES_PER_WORD PR_BYTES_PER_WORD +#define BYTES_PER_DWORD PR_BYTES_PER_DWORD + +#define BITS_PER_BYTE PR_BITS_PER_BYTE +#define BITS_PER_SHORT PR_BITS_PER_SHORT +#define BITS_PER_INT PR_BITS_PER_INT +#define BITS_PER_INT64 PR_BITS_PER_INT64 +#define BITS_PER_LONG PR_BITS_PER_LONG +#define BITS_PER_FLOAT PR_BITS_PER_FLOAT +#define BITS_PER_DOUBLE PR_BITS_PER_DOUBLE +#define BITS_PER_WORD PR_BITS_PER_WORD + +#define BITS_PER_BYTE_LOG2 PR_BITS_PER_BYTE_LOG2 +#define BITS_PER_SHORT_LOG2 PR_BITS_PER_SHORT_LOG2 +#define BITS_PER_INT_LOG2 PR_BITS_PER_INT_LOG2 +#define BITS_PER_INT64_LOG2 PR_BITS_PER_INT64_LOG2 +#define BITS_PER_LONG_LOG2 PR_BITS_PER_LONG_LOG2 +#define BITS_PER_FLOAT_LOG2 PR_BITS_PER_FLOAT_LOG2 +#define BITS_PER_DOUBLE_LOG2 PR_BITS_PER_DOUBLE_LOG2 +#define BITS_PER_WORD_LOG2 PR_BITS_PER_WORD_LOG2 + +#define ALIGN_OF_SHORT PR_ALIGN_OF_SHORT +#define ALIGN_OF_INT PR_ALIGN_OF_INT +#define ALIGN_OF_LONG PR_ALIGN_OF_LONG +#define ALIGN_OF_INT64 PR_ALIGN_OF_INT64 +#define ALIGN_OF_FLOAT PR_ALIGN_OF_FLOAT +#define ALIGN_OF_DOUBLE PR_ALIGN_OF_DOUBLE +#define ALIGN_OF_POINTER PR_ALIGN_OF_POINTER +#define ALIGN_OF_WORD PR_ALIGN_OF_WORD + +#define BYTES_PER_WORD_LOG2 PR_BYTES_PER_WORD_LOG2 +#define BYTES_PER_DWORD_LOG2 PR_BYTES_PER_DWORD_LOG2 +#define WORDS_PER_DWORD_LOG2 PR_WORDS_PER_DWORD_LOG2 + +#endif /* NO_NSPR_10_SUPPORT */ + +#endif /* nspr_cpucfg___ */ diff --git a/pr/include/md/_linux.h b/pr/include/md/_linux.h index 0c4a5f6a..c7c33ce8 100644 --- a/pr/include/md/_linux.h +++ b/pr/include/md/_linux.h @@ -64,6 +64,14 @@ #endif #define USE_SETJMP +#define _PR_POLL_AVAILABLE +#define _PR_USE_POLL +#define _PR_STAT_HAS_ONLY_ST_ATIME +#if defined(__alpha) +#define _PR_HAVE_LARGE_OFF_T +#else +#define _PR_NO_LARGE_FILES +#endif #ifdef _PR_PTHREADS @@ -282,6 +290,42 @@ struct _MDSegment { PRInt8 notused; }; +/* + * md-specific cpu structure field + */ +#define _PR_MD_MAX_OSFD FD_SETSIZE + +struct _MDCPU_Unix { + PRCList ioQ; + PRUint32 ioq_timeout; + PRInt32 ioq_max_osfd; + PRInt32 ioq_osfd_cnt; +#ifndef _PR_USE_POLL + fd_set fd_read_set, fd_write_set, fd_exception_set; + PRInt16 fd_read_cnt[_PR_MD_MAX_OSFD],fd_write_cnt[_PR_MD_MAX_OSFD], + fd_exception_cnt[_PR_MD_MAX_OSFD]; +#else + struct pollfd *ioq_pollfds; + int ioq_pollfds_size; +#endif /* _PR_USE_POLL */ +}; + +#define _PR_IOQ(_cpu) ((_cpu)->md.md_unix.ioQ) +#define _PR_ADD_TO_IOQ(_pq, _cpu) PR_APPEND_LINK(&_pq.links, &_PR_IOQ(_cpu)) +#define _PR_FD_READ_SET(_cpu) ((_cpu)->md.md_unix.fd_read_set) +#define _PR_FD_READ_CNT(_cpu) ((_cpu)->md.md_unix.fd_read_cnt) +#define _PR_FD_WRITE_SET(_cpu) ((_cpu)->md.md_unix.fd_write_set) +#define _PR_FD_WRITE_CNT(_cpu) ((_cpu)->md.md_unix.fd_write_cnt) +#define _PR_FD_EXCEPTION_SET(_cpu) ((_cpu)->md.md_unix.fd_exception_set) +#define _PR_FD_EXCEPTION_CNT(_cpu) ((_cpu)->md.md_unix.fd_exception_cnt) +#define _PR_IOQ_TIMEOUT(_cpu) ((_cpu)->md.md_unix.ioq_timeout) +#define _PR_IOQ_MAX_OSFD(_cpu) ((_cpu)->md.md_unix.ioq_max_osfd) +#define _PR_IOQ_OSFD_CNT(_cpu) ((_cpu)->md.md_unix.ioq_osfd_cnt) +#define _PR_IOQ_POLLFDS(_cpu) ((_cpu)->md.md_unix.ioq_pollfds) +#define _PR_IOQ_POLLFDS_SIZE(_cpu) ((_cpu)->md.md_unix.ioq_pollfds_size) + +#define _PR_IOQ_MIN_POLLFDS_SIZE(_cpu) 32 + struct _MDCPU { struct _MDCPU_Unix md_unix; }; @@ -334,7 +378,7 @@ extern PRIntervalTime _PR_UNIX_TicksPerSecond(void); #define _MD_SELECT __select #ifdef _PR_POLL_AVAILABLE -#include <poll.h> +#include <sys/poll.h> extern int __syscall_poll(struct pollfd *ufds, unsigned long int nfds, int timeout); #define _MD_POLL __syscall_poll diff --git a/pr/include/md/_macos.h b/pr/include/md/_macos.h index f1e2d5c6..ffeb1fa8 100644 --- a/pr/include/md/_macos.h +++ b/pr/include/md/_macos.h @@ -103,6 +103,7 @@ struct _MDFileDesc { #define _MD_BLOCK_CLOCK_INTERRUPTS() #define _MD_UNBLOCK_CLOCK_INTERRUPTS() #define _MD_DISABLE_CLOCK_INTERRUPTS() +#define _MD_ENABLE_CLOCK_INTERRUPTS() /* ** CPU Related definitions @@ -462,11 +463,13 @@ typedef short PROSFD; // Errors not found in the Mac StdCLib #define EACCES 13 // Permission denied #define ENOENT -43 // No such file or directory +#define EMFILE 24 // Too many open files #define _OS_INVALID_FD_VALUE -1 #define STDERR_FILENO 2 #if !defined(MAC_NSPR_STANDALONE) +#define MAC_PATH_SEPARATOR ':' #define PATH_SEPARATOR ':' #define PATH_SEPARATOR_STR ":" #define DIRECTORY_SEPARATOR '/' @@ -476,6 +479,10 @@ typedef short PROSFD; #define UNIX_THIS_DIRECTORY_STR "./" #define UNIX_PARENT_DIRECTORY_STR "../" +#define MAX_PATH 512 +#define MAX_MAC_FILENAME 31 +#define MAXPATHLEN MAX_PATH + // Alias a few names #define getenv PR_GetEnv @@ -527,6 +534,10 @@ extern void dprintf(const char *format, ...); extern PRUint8 CallCacheFlushers(size_t blockSize); #endif +enum { + kPrivateNSPREventType = 13 +}; + #if defined(MAC_NSPR_STANDALONE) extern void* reallocSmaller(void* block, size_t newSize); #endif @@ -535,7 +546,7 @@ extern void* reallocSmaller(void* block, size_t newSize); /* ** PR_GetSystemInfo related definitions */ -#define _PR_SI_SYSNAME "Mac OS" +#define _PR_SI_SYSNAME "MacOS" #define _PR_SI_ARCHITECTURE "PowerPC" /* diff --git a/pr/include/md/_ncr.cfg b/pr/include/md/_ncr.cfg index 337b933d..dde85210 100644 --- a/pr/include/md/_ncr.cfg +++ b/pr/include/md/_ncr.cfg @@ -71,8 +71,7 @@ #define PR_ALIGN_OF_DOUBLE 4 #define PR_ALIGN_OF_POINTER 4 -#define _PR_POLL_AVAILABLE -#define _PR_USE_POLL +#define _PR_POLL_BACKCOMPAT #ifndef NO_NSPR_10_SUPPORT diff --git a/pr/include/md/_ncr.h b/pr/include/md/_ncr.h index 75fa7ded..82a84e63 100644 --- a/pr/include/md/_ncr.h +++ b/pr/include/md/_ncr.h @@ -45,6 +45,9 @@ #define HAVE_WEAK_IO_SYMBOLS #endif +#define _PR_POLL_AVAILABLE +#define _PR_USE_POLL + #undef HAVE_STACK_GROWING_UP #define HAVE_NETCONFIG #define NEED_STRFTIME_LOCK @@ -124,6 +127,42 @@ struct _MDSegment { PRInt8 notused; }; +/* + * md-specific cpu structure field + */ +#define _PR_MD_MAX_OSFD FD_SETSIZE + +struct _MDCPU_Unix { + PRCList ioQ; + PRUint32 ioq_timeout; + PRInt32 ioq_max_osfd; + PRInt32 ioq_osfd_cnt; +#ifndef _PR_USE_POLL + fd_set fd_read_set, fd_write_set, fd_exception_set; + PRInt16 fd_read_cnt[_PR_MD_MAX_OSFD],fd_write_cnt[_PR_MD_MAX_OSFD], + fd_exception_cnt[_PR_MD_MAX_OSFD]; +#else + struct pollfd *ioq_pollfds; + int ioq_pollfds_size; +#endif /* _PR_USE_POLL */ +}; + +#define _PR_IOQ(_cpu) ((_cpu)->md.md_unix.ioQ) +#define _PR_ADD_TO_IOQ(_pq, _cpu) PR_APPEND_LINK(&_pq.links, &_PR_IOQ(_cpu)) +#define _PR_FD_READ_SET(_cpu) ((_cpu)->md.md_unix.fd_read_set) +#define _PR_FD_READ_CNT(_cpu) ((_cpu)->md.md_unix.fd_read_cnt) +#define _PR_FD_WRITE_SET(_cpu) ((_cpu)->md.md_unix.fd_write_set) +#define _PR_FD_WRITE_CNT(_cpu) ((_cpu)->md.md_unix.fd_write_cnt) +#define _PR_FD_EXCEPTION_SET(_cpu) ((_cpu)->md.md_unix.fd_exception_set) +#define _PR_FD_EXCEPTION_CNT(_cpu) ((_cpu)->md.md_unix.fd_exception_cnt) +#define _PR_IOQ_TIMEOUT(_cpu) ((_cpu)->md.md_unix.ioq_timeout) +#define _PR_IOQ_MAX_OSFD(_cpu) ((_cpu)->md.md_unix.ioq_max_osfd) +#define _PR_IOQ_OSFD_CNT(_cpu) ((_cpu)->md.md_unix.ioq_osfd_cnt) +#define _PR_IOQ_POLLFDS(_cpu) ((_cpu)->md.md_unix.ioq_pollfds) +#define _PR_IOQ_POLLFDS_SIZE(_cpu) ((_cpu)->md.md_unix.ioq_pollfds_size) + +#define _PR_IOQ_MIN_POLLFDS_SIZE(_cpu) 32 + struct _MDCPU { struct _MDCPU_Unix md_unix; }; diff --git a/pr/include/md/_nec.h b/pr/include/md/_nec.h index e949dd0c..8c5e5b5e 100644 --- a/pr/include/md/_nec.h +++ b/pr/include/md/_nec.h @@ -108,6 +108,42 @@ struct _MDSegment { PRInt8 notused; }; +/* + * md-specific cpu structure field + */ +#define _PR_MD_MAX_OSFD FD_SETSIZE + +struct _MDCPU_Unix { + PRCList ioQ; + PRUint32 ioq_timeout; + PRInt32 ioq_max_osfd; + PRInt32 ioq_osfd_cnt; +#ifndef _PR_USE_POLL + fd_set fd_read_set, fd_write_set, fd_exception_set; + PRInt16 fd_read_cnt[_PR_MD_MAX_OSFD],fd_write_cnt[_PR_MD_MAX_OSFD], + fd_exception_cnt[_PR_MD_MAX_OSFD]; +#else + struct pollfd *ioq_pollfds; + int ioq_pollfds_size; +#endif /* _PR_USE_POLL */ +}; + +#define _PR_IOQ(_cpu) ((_cpu)->md.md_unix.ioQ) +#define _PR_ADD_TO_IOQ(_pq, _cpu) PR_APPEND_LINK(&_pq.links, &_PR_IOQ(_cpu)) +#define _PR_FD_READ_SET(_cpu) ((_cpu)->md.md_unix.fd_read_set) +#define _PR_FD_READ_CNT(_cpu) ((_cpu)->md.md_unix.fd_read_cnt) +#define _PR_FD_WRITE_SET(_cpu) ((_cpu)->md.md_unix.fd_write_set) +#define _PR_FD_WRITE_CNT(_cpu) ((_cpu)->md.md_unix.fd_write_cnt) +#define _PR_FD_EXCEPTION_SET(_cpu) ((_cpu)->md.md_unix.fd_exception_set) +#define _PR_FD_EXCEPTION_CNT(_cpu) ((_cpu)->md.md_unix.fd_exception_cnt) +#define _PR_IOQ_TIMEOUT(_cpu) ((_cpu)->md.md_unix.ioq_timeout) +#define _PR_IOQ_MAX_OSFD(_cpu) ((_cpu)->md.md_unix.ioq_max_osfd) +#define _PR_IOQ_OSFD_CNT(_cpu) ((_cpu)->md.md_unix.ioq_osfd_cnt) +#define _PR_IOQ_POLLFDS(_cpu) ((_cpu)->md.md_unix.ioq_pollfds) +#define _PR_IOQ_POLLFDS_SIZE(_cpu) ((_cpu)->md.md_unix.ioq_pollfds_size) + +#define _PR_IOQ_MIN_POLLFDS_SIZE(_cpu) 32 + struct _MDCPU { struct _MDCPU_Unix md_unix; }; diff --git a/pr/include/md/_netbsd.h b/pr/include/md/_netbsd.h index 6065f370..497d658b 100644 --- a/pr/include/md/_netbsd.h +++ b/pr/include/md/_netbsd.h @@ -134,6 +134,42 @@ struct _MDSegment { PRInt8 notused; }; +/* + * md-specific cpu structure field + */ +#define _PR_MD_MAX_OSFD FD_SETSIZE + +struct _MDCPU_Unix { + PRCList ioQ; + PRUint32 ioq_timeout; + PRInt32 ioq_max_osfd; + PRInt32 ioq_osfd_cnt; +#ifndef _PR_USE_POLL + fd_set fd_read_set, fd_write_set, fd_exception_set; + PRInt16 fd_read_cnt[_PR_MD_MAX_OSFD],fd_write_cnt[_PR_MD_MAX_OSFD], + fd_exception_cnt[_PR_MD_MAX_OSFD]; +#else + struct pollfd *ioq_pollfds; + int ioq_pollfds_size; +#endif /* _PR_USE_POLL */ +}; + +#define _PR_IOQ(_cpu) ((_cpu)->md.md_unix.ioQ) +#define _PR_ADD_TO_IOQ(_pq, _cpu) PR_APPEND_LINK(&_pq.links, &_PR_IOQ(_cpu)) +#define _PR_FD_READ_SET(_cpu) ((_cpu)->md.md_unix.fd_read_set) +#define _PR_FD_READ_CNT(_cpu) ((_cpu)->md.md_unix.fd_read_cnt) +#define _PR_FD_WRITE_SET(_cpu) ((_cpu)->md.md_unix.fd_write_set) +#define _PR_FD_WRITE_CNT(_cpu) ((_cpu)->md.md_unix.fd_write_cnt) +#define _PR_FD_EXCEPTION_SET(_cpu) ((_cpu)->md.md_unix.fd_exception_set) +#define _PR_FD_EXCEPTION_CNT(_cpu) ((_cpu)->md.md_unix.fd_exception_cnt) +#define _PR_IOQ_TIMEOUT(_cpu) ((_cpu)->md.md_unix.ioq_timeout) +#define _PR_IOQ_MAX_OSFD(_cpu) ((_cpu)->md.md_unix.ioq_max_osfd) +#define _PR_IOQ_OSFD_CNT(_cpu) ((_cpu)->md.md_unix.ioq_osfd_cnt) +#define _PR_IOQ_POLLFDS(_cpu) ((_cpu)->md.md_unix.ioq_pollfds) +#define _PR_IOQ_POLLFDS_SIZE(_cpu) ((_cpu)->md.md_unix.ioq_pollfds_size) + +#define _PR_IOQ_MIN_POLLFDS_SIZE(_cpu) 32 + struct _MDCPU { struct _MDCPU_Unix md_unix; }; diff --git a/pr/include/md/_nspr_pthread.h b/pr/include/md/_nspr_pthread.h index 312c8def..1daeb61a 100644 --- a/pr/include/md/_nspr_pthread.h +++ b/pr/include/md/_nspr_pthread.h @@ -119,6 +119,42 @@ struct _MDSegment { PRInt8 notused; }; +/* + * md-specific cpu structure field + */ +#define _PR_MD_MAX_OSFD FD_SETSIZE + +struct _MDCPU_Unix { + PRCList ioQ; + PRUint32 ioq_timeout; + PRInt32 ioq_max_osfd; + PRInt32 ioq_osfd_cnt; +#ifndef _PR_USE_POLL + fd_set fd_read_set, fd_write_set, fd_exception_set; + PRInt16 fd_read_cnt[_PR_MD_MAX_OSFD],fd_write_cnt[_PR_MD_MAX_OSFD], + fd_exception_cnt[_PR_MD_MAX_OSFD]; +#else + struct pollfd *ioq_pollfds; + int ioq_pollfds_size; +#endif /* _PR_USE_POLL */ +}; + +#define _PR_IOQ(_cpu) ((_cpu)->md.md_unix.ioQ) +#define _PR_ADD_TO_IOQ(_pq, _cpu) PR_APPEND_LINK(&_pq.links, &_PR_IOQ(_cpu)) +#define _PR_FD_READ_SET(_cpu) ((_cpu)->md.md_unix.fd_read_set) +#define _PR_FD_READ_CNT(_cpu) ((_cpu)->md.md_unix.fd_read_cnt) +#define _PR_FD_WRITE_SET(_cpu) ((_cpu)->md.md_unix.fd_write_set) +#define _PR_FD_WRITE_CNT(_cpu) ((_cpu)->md.md_unix.fd_write_cnt) +#define _PR_FD_EXCEPTION_SET(_cpu) ((_cpu)->md.md_unix.fd_exception_set) +#define _PR_FD_EXCEPTION_CNT(_cpu) ((_cpu)->md.md_unix.fd_exception_cnt) +#define _PR_IOQ_TIMEOUT(_cpu) ((_cpu)->md.md_unix.ioq_timeout) +#define _PR_IOQ_MAX_OSFD(_cpu) ((_cpu)->md.md_unix.ioq_max_osfd) +#define _PR_IOQ_OSFD_CNT(_cpu) ((_cpu)->md.md_unix.ioq_osfd_cnt) +#define _PR_IOQ_POLLFDS(_cpu) ((_cpu)->md.md_unix.ioq_pollfds) +#define _PR_IOQ_POLLFDS_SIZE(_cpu) ((_cpu)->md.md_unix.ioq_pollfds_size) + +#define _PR_IOQ_MIN_POLLFDS_SIZE(_cpu) 32 + struct _MDCPU { jmp_buf jb; pthread_t pthread; diff --git a/pr/include/md/_openbsd.cfg b/pr/include/md/_openbsd.cfg new file mode 100644 index 00000000..967d36e5 --- /dev/null +++ b/pr/include/md/_openbsd.cfg @@ -0,0 +1,262 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "NPL"); you may not use this file except in + * compliance with the NPL. You may obtain a copy of the NPL at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the NPL is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL + * for the specific language governing rights and limitations under the + * NPL. + * + * The Initial Developer of this code under the NPL is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All Rights + * Reserved. + */ + +#ifndef nspr_cpucfg___ +#define nspr_cpucfg___ + +#ifndef XP_UNIX +#define XP_UNIX +#endif + +#ifndef OPENBSD +#define OPENBSD +#endif + +#if defined(__i386__) || defined(__arm32__) + +#define IS_LITTLE_ENDIAN 1 +#undef IS_BIG_ENDIAN +#define HAVE_LONG_LONG +#undef HAVE_ALIGNED_DOUBLES +#undef HAVE_ALIGNED_LONGLONGS + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 4 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 4 +#define PR_BYTES_PER_DWORD 8 +#define PR_BYTES_PER_WORD_LOG2 2 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 32 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 32 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 5 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 5 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 4 +#define PR_ALIGN_OF_INT64 4 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 4 +#define PR_ALIGN_OF_POINTER 4 + +#elif defined(__sparc__) + +#undef IS_LITTLE_ENDIAN 1 +#define IS_BIG_ENDIAN 1 +#define HAVE_LONG_LONG +#define HAVE_ALIGNED_DOUBLES +#define HAVE_ALIGNED_LONGLONGS + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 4 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 4 +#define PR_BYTES_PER_DWORD 8 +#define PR_BYTES_PER_WORD_LOG2 2 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 32 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 32 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 5 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 5 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 4 +#define PR_ALIGN_OF_INT64 8 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 8 +#define PR_ALIGN_OF_POINTER 4 + +#elif defined(__alpha__) +#define IS_LITTLE_ENDIAN 1 +#undef IS_BIG_ENDIAN +#define IS_64 + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 8 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 8 +#define PR_BYTES_PER_DWORD 8 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 64 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 64 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 6 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 6 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 8 +#define PR_ALIGN_OF_INT64 8 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 8 +#define PR_ALIGN_OF_POINTER 8 + +#define PR_BYTES_PER_WORD_LOG2 3 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#elif defined(__powerpc__) || defined(__m68k__) + +#undef IS_LITTLE_ENDIAN +#define IS_BIG_ENDIAN 1 + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 4 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 4 +#define PR_BYTES_PER_DWORD 8 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 32 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 32 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 5 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 5 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 4 +#define PR_ALIGN_OF_INT64 4 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 4 +#define PR_ALIGN_OF_POINTER 4 + +#define PR_BYTES_PER_WORD_LOG2 2 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#else + +#error Must define constants for type sizes here. + +#endif + + +#ifndef NO_NSPR_10_SUPPORT + +#define BYTES_PER_BYTE PR_BYTES_PER_BYTE +#define BYTES_PER_SHORT PR_BYTES_PER_SHORT +#define BYTES_PER_INT PR_BYTES_PER_INT +#define BYTES_PER_INT64 PR_BYTES_PER_INT64 +#define BYTES_PER_LONG PR_BYTES_PER_LONG +#define BYTES_PER_FLOAT PR_BYTES_PER_FLOAT +#define BYTES_PER_DOUBLE PR_BYTES_PER_DOUBLE +#define BYTES_PER_WORD PR_BYTES_PER_WORD +#define BYTES_PER_DWORD PR_BYTES_PER_DWORD + +#define BITS_PER_BYTE PR_BITS_PER_BYTE +#define BITS_PER_SHORT PR_BITS_PER_SHORT +#define BITS_PER_INT PR_BITS_PER_INT +#define BITS_PER_INT64 PR_BITS_PER_INT64 +#define BITS_PER_LONG PR_BITS_PER_LONG +#define BITS_PER_FLOAT PR_BITS_PER_FLOAT +#define BITS_PER_DOUBLE PR_BITS_PER_DOUBLE +#define BITS_PER_WORD PR_BITS_PER_WORD + +#define BITS_PER_BYTE_LOG2 PR_BITS_PER_BYTE_LOG2 +#define BITS_PER_SHORT_LOG2 PR_BITS_PER_SHORT_LOG2 +#define BITS_PER_INT_LOG2 PR_BITS_PER_INT_LOG2 +#define BITS_PER_INT64_LOG2 PR_BITS_PER_INT64_LOG2 +#define BITS_PER_LONG_LOG2 PR_BITS_PER_LONG_LOG2 +#define BITS_PER_FLOAT_LOG2 PR_BITS_PER_FLOAT_LOG2 +#define BITS_PER_DOUBLE_LOG2 PR_BITS_PER_DOUBLE_LOG2 +#define BITS_PER_WORD_LOG2 PR_BITS_PER_WORD_LOG2 + +#define ALIGN_OF_SHORT PR_ALIGN_OF_SHORT +#define ALIGN_OF_INT PR_ALIGN_OF_INT +#define ALIGN_OF_LONG PR_ALIGN_OF_LONG +#define ALIGN_OF_INT64 PR_ALIGN_OF_INT64 +#define ALIGN_OF_FLOAT PR_ALIGN_OF_FLOAT +#define ALIGN_OF_DOUBLE PR_ALIGN_OF_DOUBLE +#define ALIGN_OF_POINTER PR_ALIGN_OF_POINTER +#define ALIGN_OF_WORD PR_ALIGN_OF_WORD + +#define BYTES_PER_WORD_LOG2 PR_BYTES_PER_WORD_LOG2 +#define BYTES_PER_DWORD_LOG2 PR_BYTES_PER_DWORD_LOG2 +#define WORDS_PER_DWORD_LOG2 PR_WORDS_PER_DWORD_LOG2 + +#endif /* NO_NSPR_10_SUPPORT */ + +#endif /* nspr_cpucfg___ */ diff --git a/pr/include/md/_openbsd.h b/pr/include/md/_openbsd.h new file mode 100644 index 00000000..d34d5e58 --- /dev/null +++ b/pr/include/md/_openbsd.h @@ -0,0 +1,171 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "NPL"); you may not use this file except in + * compliance with the NPL. You may obtain a copy of the NPL at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the NPL is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL + * for the specific language governing rights and limitations under the + * NPL. + * + * The Initial Developer of this code under the NPL is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All Rights + * Reserved. + */ + +#ifndef nspr_openbsd_defs_h___ +#define nspr_openbsd_defs_h___ + +#include <sys/syscall.h> + +#define PR_LINKER_ARCH "openbsd" +#define _PR_SI_SYSNAME "OpenBSD" +#if defined(__i386__) +#define _PR_SI_ARCHITECTURE "x86" +#elif defined(__alpha__) +#define _PR_SI_ARCHITECTURE "alpha" +#elif defined(__m68k__) +#define _PR_SI_ARCHITECTURE "m68k" +#elif defined(__powerpc__) +#define _PR_SI_ARCHITECTURE "powerpc" +#elif defined(__sparc__) +#define _PR_SI_ARCHITECTURE "sparc" +#elif defined(__arm32__) +#define _PR_SI_ARCHITECTURE "arm32" +#endif + +#define PR_DLL_SUFFIX ".so.1.0" + +#define _PR_VMBASE 0x30000000 +#define _PR_STACK_VMBASE 0x50000000 +#define _MD_DEFAULT_STACK_SIZE 65536L +#define _MD_MMAP_FLAGS MAP_PRIVATE + +#undef HAVE_STACK_GROWING_UP +#define HAVE_DLL +#define USE_DLFCN +#define _PR_HAVE_SOCKADDR_LEN + +#define USE_SETJMP + +#ifndef _PR_PTHREADS +#include <setjmp.h> + +#define PR_CONTEXT_TYPE sigjmp_buf + +#define CONTEXT(_th) ((_th)->md.context) + +#if defined(__i386__) || defined(__sparc__) || defined(__m68k__) || defined(__powerpc__) +#define JB_SP_INDEX 2 +#elif defined(__alpha__) +#define JB_SP_INDEX 34 +#elif defined(__arm32__) +/* + * On the arm32, the jmpbuf regs underwent a namechange after NetBSD 1.3 + */ +#ifdef JMPBUF_REG_R13 +#define JB_SP_INDEX JMPBUF_REG_R13 +#else +#define JB_SP_INDEX _JB_REG_R13 +#endif +#else +#error "Need to define SP index in jmp_buf here" +#endif +#define _MD_GET_SP(_th) (_th)->md.context[JB_SP_INDEX] + +#define PR_NUM_GCREGS _JBLEN + +/* +** Initialize a thread context to run "_main()" when started +*/ +#define _MD_INIT_CONTEXT(_thread, _sp, _main, status) \ +{ \ + *status = PR_TRUE; \ + if (sigsetjmp(CONTEXT(_thread), 1)) { \ + _main(); \ + } \ + _MD_GET_SP(_thread) = (unsigned char*) ((_sp) - 64); \ +} + +#define _MD_SWITCH_CONTEXT(_thread) \ + if (!sigsetjmp(CONTEXT(_thread), 1)) { \ + (_thread)->md.errcode = errno; \ + _PR_Schedule(); \ + } + +/* +** Restore a thread context, saved by _MD_SWITCH_CONTEXT +*/ +#define _MD_RESTORE_CONTEXT(_thread) \ +{ \ + errno = (_thread)->md.errcode; \ + _MD_SET_CURRENT_THREAD(_thread); \ + siglongjmp(CONTEXT(_thread), 1); \ +} + +/* Machine-dependent (MD) data structures */ + +struct _MDThread { + PR_CONTEXT_TYPE context; + int id; + int errcode; +}; + +struct _MDThreadStack { + PRInt8 notused; +}; + +struct _MDLock { + PRInt8 notused; +}; + +struct _MDSemaphore { + PRInt8 notused; +}; + +struct _MDCVar { + PRInt8 notused; +}; + +struct _MDSegment { + PRInt8 notused; +}; + +struct _MDCPU { + struct _MDCPU_Unix md_unix; +}; + +#define _MD_INIT_LOCKS() +#define _MD_NEW_LOCK(lock) PR_SUCCESS +#define _MD_FREE_LOCK(lock) +#define _MD_LOCK(lock) +#define _MD_UNLOCK(lock) +#define _MD_INIT_IO() +#define _MD_IOQ_LOCK() +#define _MD_IOQ_UNLOCK() + +#define _MD_INIT_RUNNING_CPU(cpu) _MD_unix_init_running_cpu(cpu) +#define _MD_INIT_THREAD _MD_InitializeThread +#define _MD_EXIT_THREAD(thread) +#define _MD_SUSPEND_THREAD(thread) _MD_suspend_thread +#define _MD_RESUME_THREAD(thread) _MD_resume_thread +#define _MD_CLEAN_THREAD(_thread) + +#endif /* ! _PR_PTHREADS */ + +#define _MD_EARLY_INIT _MD_EarlyInit +#define _MD_FINAL_INIT _PR_UnixInit +#define _MD_GET_INTERVAL _PR_UNIX_GetInterval +#define _MD_INTERVAL_PER_SEC _PR_UNIX_TicksPerSecond + +/* + * We wrapped the select() call. _MD_SELECT refers to the built-in, + * unwrapped version. + */ +#define _MD_SELECT(nfds,r,w,e,tv) syscall(SYS_select,nfds,r,w,e,tv) +#define _MD_POLL(fds,nfds,timeout) syscall(SYS_poll,fds,nfds,timeout) + +#endif /* nspr_openbsd_defs_h___ */ diff --git a/pr/include/md/_os2.h b/pr/include/md/_os2.h index ab67224a..bd38535e 100644 --- a/pr/include/md/_os2.h +++ b/pr/include/md/_os2.h @@ -245,6 +245,7 @@ extern PRInt32 _MD_CloseSocket(PRInt32 osfd); #define _MD_INIT_ATOMIC _PR_MD_INIT_ATOMIC #define _MD_ATOMIC_INCREMENT(x) _PR_MD_ATOMIC_INCREMENT(x) +#define _MD_ATOMIC_ADD(x,y) _PR_MD_ATOMIC_ADD(x,y) #define _MD_ATOMIC_DECREMENT(x) _PR_MD_ATOMIC_DECREMENT(x) #define _MD_ATOMIC_SET(x,y) _PR_MD_ATOMIC_SET(x, y) @@ -340,6 +341,7 @@ extern PRInt32 _MD_Accept(PRFileDesc *fd, PRNetAddr *raddr, PRUint32 *rlen, #define _MD_START_INTERRUPTS() #define _MD_STOP_INTERRUPTS() #define _MD_DISABLE_CLOCK_INTERRUPTS() +#define _MD_ENABLE_CLOCK_INTERRUPTS() #define _MD_BLOCK_CLOCK_INTERRUPTS() #define _MD_UNBLOCK_CLOCK_INTERRUPTS() #define _MD_EARLY_INIT _PR_MD_EARLY_INIT diff --git a/pr/include/md/_osf1.cfg b/pr/include/md/_osf1.cfg index 16bc9ac9..27ef81ca 100644 --- a/pr/include/md/_osf1.cfg +++ b/pr/include/md/_osf1.cfg @@ -75,8 +75,7 @@ #define PR_ALIGN_OF_DOUBLE 8 #define PR_ALIGN_OF_POINTER 8 -#define _PR_POLL_AVAILABLE -#define _PR_USE_POLL +#define _PR_POLL_BACKCOMPAT #ifndef NO_NSPR_10_SUPPORT diff --git a/pr/include/md/_osf1.h b/pr/include/md/_osf1.h index 473dee28..ab2baadd 100644 --- a/pr/include/md/_osf1.h +++ b/pr/include/md/_osf1.h @@ -28,15 +28,10 @@ #define _PR_SI_ARCHITECTURE "alpha" #define PR_DLL_SUFFIX ".so" -#define _PR_VMBASE 0x30000000 -#define _PR_STACK_VMBASE 0x50000000 -#define _MD_DEFAULT_STACK_SIZE 131072L -/* - * OSF1 needs the MAP_FIXED flag to ensure that mmap returns a pointer - * with the upper 32 bits zero. This is because Java sticks a pointer - * into an int. - */ -#define _MD_MMAP_FLAGS MAP_PRIVATE|MAP_FIXED +#define _PR_VMBASE 0x30000000 +#define _PR_STACK_VMBASE 0x50000000 +#define _MD_DEFAULT_STACK_SIZE 131072L +#define _MD_MMAP_FLAGS MAP_PRIVATE #undef HAVE_STACK_GROWING_UP #undef HAVE_WEAK_IO_SYMBOLS @@ -47,6 +42,13 @@ #define NEED_TIME_R #define USE_DLFCN +#define _PR_HAVE_ATOMIC_OPS +#define _PR_HAVE_ATOMIC_CAS +#define _PR_POLL_AVAILABLE +#define _PR_USE_POLL +#define _PR_STAT_HAS_ONLY_ST_ATIME +#define _PR_HAVE_LARGE_OFF_T + #define USE_SETJMP #include <setjmp.h> @@ -116,6 +118,42 @@ struct _MDSegment { PRInt8 notused; }; +/* + * md-specific cpu structure field + */ +#define _PR_MD_MAX_OSFD FD_SETSIZE + +struct _MDCPU_Unix { + PRCList ioQ; + PRUint32 ioq_timeout; + PRInt32 ioq_max_osfd; + PRInt32 ioq_osfd_cnt; +#ifndef _PR_USE_POLL + fd_set fd_read_set, fd_write_set, fd_exception_set; + PRInt16 fd_read_cnt[_PR_MD_MAX_OSFD],fd_write_cnt[_PR_MD_MAX_OSFD], + fd_exception_cnt[_PR_MD_MAX_OSFD]; +#else + struct pollfd *ioq_pollfds; + int ioq_pollfds_size; +#endif /* _PR_USE_POLL */ +}; + +#define _PR_IOQ(_cpu) ((_cpu)->md.md_unix.ioQ) +#define _PR_ADD_TO_IOQ(_pq, _cpu) PR_APPEND_LINK(&_pq.links, &_PR_IOQ(_cpu)) +#define _PR_FD_READ_SET(_cpu) ((_cpu)->md.md_unix.fd_read_set) +#define _PR_FD_READ_CNT(_cpu) ((_cpu)->md.md_unix.fd_read_cnt) +#define _PR_FD_WRITE_SET(_cpu) ((_cpu)->md.md_unix.fd_write_set) +#define _PR_FD_WRITE_CNT(_cpu) ((_cpu)->md.md_unix.fd_write_cnt) +#define _PR_FD_EXCEPTION_SET(_cpu) ((_cpu)->md.md_unix.fd_exception_set) +#define _PR_FD_EXCEPTION_CNT(_cpu) ((_cpu)->md.md_unix.fd_exception_cnt) +#define _PR_IOQ_TIMEOUT(_cpu) ((_cpu)->md.md_unix.ioq_timeout) +#define _PR_IOQ_MAX_OSFD(_cpu) ((_cpu)->md.md_unix.ioq_max_osfd) +#define _PR_IOQ_OSFD_CNT(_cpu) ((_cpu)->md.md_unix.ioq_osfd_cnt) +#define _PR_IOQ_POLLFDS(_cpu) ((_cpu)->md.md_unix.ioq_pollfds) +#define _PR_IOQ_POLLFDS_SIZE(_cpu) ((_cpu)->md.md_unix.ioq_pollfds_size) + +#define _PR_IOQ_MIN_POLLFDS_SIZE(_cpu) 32 + struct _MDCPU { struct _MDCPU_Unix md_unix; }; @@ -159,15 +197,13 @@ extern int __poll(struct pollfd filedes[], unsigned int nfds, int timeout); /* * Atomic operations */ - -/* builtins.h is not available for OSF1 V3.2. */ -#ifndef OSF1V3 +#ifdef _PR_HAVE_ATOMIC_OPS #include <machine/builtins.h> -#define _PR_HAVE_ATOMIC_OPS #define _MD_INIT_ATOMIC() #define _MD_ATOMIC_INCREMENT(val) (__ATOMIC_INCREMENT_LONG(val) + 1) +#define _MD_ATOMIC_ADD(ptr, val) (__ATOMIC_ADD_LONG(ptr, val) + val) #define _MD_ATOMIC_DECREMENT(val) (__ATOMIC_DECREMENT_LONG(val) - 1) #define _MD_ATOMIC_SET(val, newval) __ATOMIC_EXCH_LONG(val, newval) -#endif /* OSF1V3 */ +#endif /* _PR_HAVE_ATOMIC_OPS */ #endif /* nspr_osf1_defs_h___ */ diff --git a/pr/include/md/_pth.h b/pr/include/md/_pth.h index 72ab48af..9ca91a74 100644 --- a/pr/include/md/_pth.h +++ b/pr/include/md/_pth.h @@ -25,6 +25,7 @@ #define _PR_MD_BLOCK_CLOCK_INTERRUPTS() #define _PR_MD_UNBLOCK_CLOCK_INTERRUPTS() #define _PR_MD_DISABLE_CLOCK_INTERRUPTS() +#define _PR_MD_ENABLE_CLOCK_INTERRUPTS() /* In good standards fashion, the DCE threads (based on posix-4) are not * quite the same as newer posix implementations. These are mostly name @@ -70,7 +71,7 @@ #define PTHREAD_COPY_THR_HANDLE(st, dt) (dt) = (st) #elif defined(IRIX) || defined(OSF1) || defined(AIX) || defined(SOLARIS) \ || defined(HPUX) || defined(LINUX) || defined(FREEBSD) \ - || defined(NETBSD) + || defined(NETBSD) || defined(OPENBSD) #define PTHREAD_ZERO_THR_HANDLE(t) (t) = 0 #define PTHREAD_THR_HANDLE_IS_ZERO(t) (t) == 0 #define PTHREAD_COPY_THR_HANDLE(st, dt) (dt) = (st) @@ -100,21 +101,6 @@ #error "Cannot determine pthread strategy" #endif -/* - * See if we have the privilege to set the scheduling policy and - * priority of threads. Returns 0 if privilege is available. - * Returns EPERM otherwise. - */ - -#ifdef AIX -#define PT_PRIVCHECK() privcheck(SET_PROC_RAC) -#elif defined(HPUX) && !defined(_PR_DCETHREADS) -PR_EXTERN(PRIntn) pt_hpux_privcheck(void); -#define PT_PRIVCHECK() pt_hpux_privcheck() -#else -#define PT_PRIVCHECK() 0 -#endif /* AIX */ - #if defined(_PR_DCETHREADS) #define PTHREAD_EXPLICIT_SCHED PTHREAD_DEFAULT_SCHED #endif @@ -136,7 +122,7 @@ PR_EXTERN(PRIntn) pt_hpux_privcheck(void); */ #if defined(_PR_DCETHREADS) || defined(FREEBSD) \ || (defined(LINUX) && defined(__alpha)) \ - || defined(NETBSD) + || defined(NETBSD) || defined(OPENBSD) #define PT_NO_ATFORK #endif @@ -144,7 +130,7 @@ PR_EXTERN(PRIntn) pt_hpux_privcheck(void); * These platforms don't have sigtimedwait() */ #if (defined(AIX) && !defined(AIX4_3)) || defined(LINUX) \ - || defined(FREEBSD) || defined(NETBSD) + || defined(FREEBSD) || defined(NETBSD) || defined(OPENBSD) #define PT_NO_SIGTIMEDWAIT #endif @@ -186,20 +172,26 @@ PR_EXTERN(PRIntn) pt_hpux_privcheck(void); */ #define PT_PRIO_MIN 1 #define PT_PRIO_MAX 127 -#elif defined(FREEBSD) || defined(NETBSD) /* XXX */ +#elif defined(FREEBSD) || defined(NETBSD) || defined(OPENBSD) /* XXX */ #define PT_PRIO_MIN 0 #define PT_PRIO_MAX 126 #else #error "pthreads is not supported for this architecture" #endif -/* Needed for garbage collection -- Look at PR_Suspend/PR_Resume implementation */ -#if defined(OSF1) -#define PTHREAD_YIELD() pthread_yield_np() -#elif defined(HPUX10_30) || defined(HPUX11) -#define PTHREAD_YIELD() sched_yield() -#elif defined(HPUX) +/* + * The PTHREAD_YIELD function is called from a signal handler. + * Needed for garbage collection -- Look at PR_Suspend/PR_Resume + * implementation. + */ +#if defined(_PR_DCETHREADS) #define PTHREAD_YIELD() pthread_yield() +#elif defined(OSF1) +/* + * sched_yield can't be called from a signal handler. Must use + * the _np version. + */ +#define PTHREAD_YIELD() pthread_yield_np() #elif defined(AIX) extern int (*_PT_aix_yield_fcn)(); #define PTHREAD_YIELD() (*_PT_aix_yield_fcn)() @@ -211,12 +203,9 @@ extern int (*_PT_aix_yield_fcn)(); onemillisec.tv_nsec = 1000000L; \ nanosleep(&onemillisec,NULL); \ PR_END_MACRO -#elif defined(SOLARIS) -#define PTHREAD_YIELD() sched_yield() -#elif defined(LINUX) +#elif defined(HPUX) || defined(LINUX) || defined(SOLARIS) \ + || defined(FREEBSD) || defined(NETBSD) || defined(OPENBSD) #define PTHREAD_YIELD() sched_yield() -#elif defined(FREEBSD) || defined(NETBSD) -#define PTHREAD_YIELD() pthread_yield() #else #error "Need to define PTHREAD_YIELD for this platform" #endif diff --git a/pr/include/md/_reliantunix.cfg b/pr/include/md/_reliantunix.cfg index 634acfe3..9cf253d8 100644 --- a/pr/include/md/_reliantunix.cfg +++ b/pr/include/md/_reliantunix.cfg @@ -76,8 +76,7 @@ #define PR_ALIGN_OF_DOUBLE 8 #define PR_ALIGN_OF_POINTER 4 -#define _PR_POLL_AVAILABLE -#define _PR_USE_POLL +#define _PR_POLL_BACKCOMPAT #ifndef NO_NSPR_10_SUPPORT diff --git a/pr/include/md/_reliantunix.h b/pr/include/md/_reliantunix.h index d7afb63d..a327b122 100644 --- a/pr/include/md/_reliantunix.h +++ b/pr/include/md/_reliantunix.h @@ -47,6 +47,8 @@ #define HAVE_WEAK_IO_SYMBOLS #define HAVE_WEAK_MALLOC_SYMBOLS #define _PR_RECV_BROKEN /* recv doesn't work on Unix Domain Sockets */ +#define _PR_POLL_AVAILABLE +#define _PR_USE_POLL /* * Mike Patnode indicated that it is possibly safe now to use context-switching @@ -109,6 +111,42 @@ struct _MDSegment { PRInt8 notused; }; +/* + * md-specific cpu structure field + */ +#define _PR_MD_MAX_OSFD FD_SETSIZE + +struct _MDCPU_Unix { + PRCList ioQ; + PRUint32 ioq_timeout; + PRInt32 ioq_max_osfd; + PRInt32 ioq_osfd_cnt; +#ifndef _PR_USE_POLL + fd_set fd_read_set, fd_write_set, fd_exception_set; + PRInt16 fd_read_cnt[_PR_MD_MAX_OSFD],fd_write_cnt[_PR_MD_MAX_OSFD], + fd_exception_cnt[_PR_MD_MAX_OSFD]; +#else + struct pollfd *ioq_pollfds; + int ioq_pollfds_size; +#endif /* _PR_USE_POLL */ +}; + +#define _PR_IOQ(_cpu) ((_cpu)->md.md_unix.ioQ) +#define _PR_ADD_TO_IOQ(_pq, _cpu) PR_APPEND_LINK(&_pq.links, &_PR_IOQ(_cpu)) +#define _PR_FD_READ_SET(_cpu) ((_cpu)->md.md_unix.fd_read_set) +#define _PR_FD_READ_CNT(_cpu) ((_cpu)->md.md_unix.fd_read_cnt) +#define _PR_FD_WRITE_SET(_cpu) ((_cpu)->md.md_unix.fd_write_set) +#define _PR_FD_WRITE_CNT(_cpu) ((_cpu)->md.md_unix.fd_write_cnt) +#define _PR_FD_EXCEPTION_SET(_cpu) ((_cpu)->md.md_unix.fd_exception_set) +#define _PR_FD_EXCEPTION_CNT(_cpu) ((_cpu)->md.md_unix.fd_exception_cnt) +#define _PR_IOQ_TIMEOUT(_cpu) ((_cpu)->md.md_unix.ioq_timeout) +#define _PR_IOQ_MAX_OSFD(_cpu) ((_cpu)->md.md_unix.ioq_max_osfd) +#define _PR_IOQ_OSFD_CNT(_cpu) ((_cpu)->md.md_unix.ioq_osfd_cnt) +#define _PR_IOQ_POLLFDS(_cpu) ((_cpu)->md.md_unix.ioq_pollfds) +#define _PR_IOQ_POLLFDS_SIZE(_cpu) ((_cpu)->md.md_unix.ioq_pollfds_size) + +#define _PR_IOQ_MIN_POLLFDS_SIZE(_cpu) 32 + struct _MDCPU { struct _MDCPU_Unix md_unix; }; diff --git a/pr/include/md/_rhapsody.cfg b/pr/include/md/_rhapsody.cfg index 73fc491c..a0787fc9 100644 --- a/pr/include/md/_rhapsody.cfg +++ b/pr/include/md/_rhapsody.cfg @@ -27,8 +27,14 @@ #define RHAPOSDY #endif +#if defined(i386) +#undef IS_BIG_ENDIAN +#define IS_LITTLE_ENDIAN 1 +#else #undef IS_LITTLE_ENDIAN #define IS_BIG_ENDIAN 1 +#endif + #define HAVE_LONG_LONG #undef HAVE_ALIGNED_DOUBLES #define HAVE_ALIGNED_LONGLONGS 1 @@ -53,6 +59,7 @@ #define PR_BITS_PER_FLOAT 32 #define PR_BITS_PER_DOUBLE 64 #define PR_BITS_PER_WORD 32 +#define PR_BITS_PER_DWORD 64 #define PR_BITS_PER_BYTE_LOG2 3 #define PR_BITS_PER_SHORT_LOG2 4 @@ -117,3 +124,4 @@ #endif /* NO_NSPR_10_SUPPORT */ #endif /* nspr_cpucfg___ */ + diff --git a/pr/include/md/_rhapsody.h b/pr/include/md/_rhapsody.h index 052da11f..476b8e38 100644 --- a/pr/include/md/_rhapsody.h +++ b/pr/include/md/_rhapsody.h @@ -38,24 +38,23 @@ #define _MD_MMAP_FLAGS MAP_PRIVATE #undef HAVE_STACK_GROWING_UP -#define HAVE_WEAK_MALLOC_SYMBOLS -/* do this until I figure out the rhapsody dll stuff. */ #define HAVE_DLL -#define USE_RLD -#define _PR_HAVE_SOCKADDR_LEN +#define _PR_HAVE_SOCKADDR_LEN +#define _PR_STAT_HAS_ST_ATIMESPEC +#define _PR_TIMESPEC_HAS_TS_SEC +#define _PR_NO_LARGE_FILES #define USE_SETJMP -#ifndef _PR_PTHREADS +#if !defined(_PR_PTHREADS) #include <setjmp.h> #define PR_CONTEXT_TYPE jmp_buf -#define CONTEXT(_th) ((_th)->md.context) - -#define _MD_GET_SP(_th) (_th)->md.context[0] -#define PR_NUM_GCREGS _JBLEN +#define CONTEXT(_th) ((_th)->md.context) +#define _MD_GET_SP(_th) (((struct sigcontext *) (_th)->md.context)->sc_onstack) +#define PR_NUM_GCREGS _JBLEN /* ** Initialize a thread context to run "_main()" when started @@ -66,7 +65,7 @@ if (setjmp(CONTEXT(_thread))) { \ _main(); \ } \ - _MD_GET_SP(_thread) = (int) ((_sp) - 64); \ + _MD_GET_SP(_thread) = (unsigned char*) ((_sp) - 64); \ } #define _MD_SWITCH_CONTEXT(_thread) \ @@ -113,6 +112,42 @@ struct _MDSegment { PRInt8 notused; }; +/* + * md-specific cpu structure field + */ +#define _PR_MD_MAX_OSFD FD_SETSIZE + +struct _MDCPU_Unix { + PRCList ioQ; + PRUint32 ioq_timeout; + PRInt32 ioq_max_osfd; + PRInt32 ioq_osfd_cnt; +#ifndef _PR_USE_POLL + fd_set fd_read_set, fd_write_set, fd_exception_set; + PRInt16 fd_read_cnt[_PR_MD_MAX_OSFD],fd_write_cnt[_PR_MD_MAX_OSFD], + fd_exception_cnt[_PR_MD_MAX_OSFD]; +#else + struct pollfd *ioq_pollfds; + int ioq_pollfds_size; +#endif /* _PR_USE_POLL */ +}; + +#define _PR_IOQ(_cpu) ((_cpu)->md.md_unix.ioQ) +#define _PR_ADD_TO_IOQ(_pq, _cpu) PR_APPEND_LINK(&_pq.links, &_PR_IOQ(_cpu)) +#define _PR_FD_READ_SET(_cpu) ((_cpu)->md.md_unix.fd_read_set) +#define _PR_FD_READ_CNT(_cpu) ((_cpu)->md.md_unix.fd_read_cnt) +#define _PR_FD_WRITE_SET(_cpu) ((_cpu)->md.md_unix.fd_write_set) +#define _PR_FD_WRITE_CNT(_cpu) ((_cpu)->md.md_unix.fd_write_cnt) +#define _PR_FD_EXCEPTION_SET(_cpu) ((_cpu)->md.md_unix.fd_exception_set) +#define _PR_FD_EXCEPTION_CNT(_cpu) ((_cpu)->md.md_unix.fd_exception_cnt) +#define _PR_IOQ_TIMEOUT(_cpu) ((_cpu)->md.md_unix.ioq_timeout) +#define _PR_IOQ_MAX_OSFD(_cpu) ((_cpu)->md.md_unix.ioq_max_osfd) +#define _PR_IOQ_OSFD_CNT(_cpu) ((_cpu)->md.md_unix.ioq_osfd_cnt) +#define _PR_IOQ_POLLFDS(_cpu) ((_cpu)->md.md_unix.ioq_pollfds) +#define _PR_IOQ_POLLFDS_SIZE(_cpu) ((_cpu)->md.md_unix.ioq_pollfds_size) + +#define _PR_IOQ_MIN_POLLFDS_SIZE(_cpu) 32 + struct _MDCPU { struct _MDCPU_Unix md_unix; }; @@ -149,14 +184,14 @@ extern void _MD_YIELD(void); #endif /* ! _PR_PTHREADS */ -extern void _MD_EarlyInit(void); -extern PRIntervalTime _PR_UNIX_GetInterval(void); -extern PRIntervalTime _PR_UNIX_TicksPerSecond(void); - -#define _MD_EARLY_INIT _MD_EarlyInit +#define _MD_EARLY_INIT _MD_EarlyInit #define _MD_FINAL_INIT _PR_UnixInit -#define _MD_GET_INTERVAL _PR_UNIX_GetInterval -#define _MD_INTERVAL_PER_SEC _PR_UNIX_TicksPerSecond +#define _MD_GET_INTERVAL _PR_UNIX_GetInterval +#define _MD_INTERVAL_PER_SEC _PR_UNIX_TicksPerSecond + +extern void _MD_EarlyInit(void); +extern PRIntervalTime _PR_UNIX_GetInterval(void); +extern PRIntervalTime _PR_UNIX_TicksPerSecond(void); /* * We wrapped the select() call. _MD_SELECT refers to the built-in, diff --git a/pr/include/md/_scoos.cfg b/pr/include/md/_scoos.cfg index 3f414650..6ef8fa90 100644 --- a/pr/include/md/_scoos.cfg +++ b/pr/include/md/_scoos.cfg @@ -71,8 +71,7 @@ #define PR_ALIGN_OF_DOUBLE 4 #define PR_ALIGN_OF_POINTER 4 -#define _PR_POLL_AVAILABLE -#define _PR_USE_POLL +#define _PR_POLL_BACKCOMPAT #ifndef NO_NSPR_10_SUPPORT diff --git a/pr/include/md/_scoos.h b/pr/include/md/_scoos.h index 45764f74..faa8e9ff 100644 --- a/pr/include/md/_scoos.h +++ b/pr/include/md/_scoos.h @@ -45,6 +45,9 @@ #define HAVE_WEAK_IO_SYMBOLS #endif +#define _PR_POLL_AVAILABLE +#define _PR_USE_POLL + #define NEED_STRFTIME_LOCK #define NEED_TIME_R #define _PR_RECV_BROKEN /* recv doesn't work on Unix Domain Sockets */ @@ -113,6 +116,42 @@ struct _MDSegment { PRInt8 notused; }; +/* + * md-specific cpu structure field + */ +#define _PR_MD_MAX_OSFD FD_SETSIZE + +struct _MDCPU_Unix { + PRCList ioQ; + PRUint32 ioq_timeout; + PRInt32 ioq_max_osfd; + PRInt32 ioq_osfd_cnt; +#ifndef _PR_USE_POLL + fd_set fd_read_set, fd_write_set, fd_exception_set; + PRInt16 fd_read_cnt[_PR_MD_MAX_OSFD],fd_write_cnt[_PR_MD_MAX_OSFD], + fd_exception_cnt[_PR_MD_MAX_OSFD]; +#else + struct pollfd *ioq_pollfds; + int ioq_pollfds_size; +#endif /* _PR_USE_POLL */ +}; + +#define _PR_IOQ(_cpu) ((_cpu)->md.md_unix.ioQ) +#define _PR_ADD_TO_IOQ(_pq, _cpu) PR_APPEND_LINK(&_pq.links, &_PR_IOQ(_cpu)) +#define _PR_FD_READ_SET(_cpu) ((_cpu)->md.md_unix.fd_read_set) +#define _PR_FD_READ_CNT(_cpu) ((_cpu)->md.md_unix.fd_read_cnt) +#define _PR_FD_WRITE_SET(_cpu) ((_cpu)->md.md_unix.fd_write_set) +#define _PR_FD_WRITE_CNT(_cpu) ((_cpu)->md.md_unix.fd_write_cnt) +#define _PR_FD_EXCEPTION_SET(_cpu) ((_cpu)->md.md_unix.fd_exception_set) +#define _PR_FD_EXCEPTION_CNT(_cpu) ((_cpu)->md.md_unix.fd_exception_cnt) +#define _PR_IOQ_TIMEOUT(_cpu) ((_cpu)->md.md_unix.ioq_timeout) +#define _PR_IOQ_MAX_OSFD(_cpu) ((_cpu)->md.md_unix.ioq_max_osfd) +#define _PR_IOQ_OSFD_CNT(_cpu) ((_cpu)->md.md_unix.ioq_osfd_cnt) +#define _PR_IOQ_POLLFDS(_cpu) ((_cpu)->md.md_unix.ioq_pollfds) +#define _PR_IOQ_POLLFDS_SIZE(_cpu) ((_cpu)->md.md_unix.ioq_pollfds_size) + +#define _PR_IOQ_MIN_POLLFDS_SIZE(_cpu) 32 + struct _MDCPU { struct _MDCPU_Unix md_unix; }; diff --git a/pr/include/md/_solaris.h b/pr/include/md/_solaris.h index 04d0aa91..aaa646c1 100644 --- a/pr/include/md/_solaris.h +++ b/pr/include/md/_solaris.h @@ -48,8 +48,14 @@ #undef _PR_HAVE_ATOMIC_OPS #else #define _PR_HAVE_ATOMIC_OPS +#define _PR_HAVE_ATOMIC_CAS #endif +#define _PR_POLL_AVAILABLE +#define _PR_USE_POLL +#define _PR_STAT_HAS_ST_ATIM + +#include "prinrval.h" PR_EXTERN(PRIntervalTime) _MD_Solaris_GetInterval(void); #define _MD_GET_INTERVAL _MD_Solaris_GetInterval PR_EXTERN(PRIntervalTime) _MD_Solaris_TicksPerSecond(void); @@ -64,6 +70,9 @@ PR_EXTERN(PRIntervalTime) _MD_Solaris_TicksPerSecond(void); PR_EXTERN(PRInt32) _MD_AtomicIncrement(PRInt32 *val); #define _MD_ATOMIC_INCREMENT _MD_AtomicIncrement +PR_EXTERN(PRInt32) _MD_AtomicAdd(PRInt32 *ptr, PRInt32 val); +#define _MD_ATOMIC_ADD _MD_AtomicAdd + PR_EXTERN(PRInt32) _MD_AtomicDecrement(PRInt32 *val); #define _MD_ATOMIC_DECREMENT _MD_AtomicDecrement @@ -285,6 +294,43 @@ struct _MDSegment { PRInt8 notused; }; +/* + * md-specific cpu structure field, common to all Unix platforms + */ +#define _PR_MD_MAX_OSFD FD_SETSIZE + +struct _MDCPU_Unix { + PRCList ioQ; + PRUint32 ioq_timeout; + PRInt32 ioq_max_osfd; + PRInt32 ioq_osfd_cnt; +#ifndef _PR_USE_POLL + fd_set fd_read_set, fd_write_set, fd_exception_set; + PRInt16 fd_read_cnt[_PR_MD_MAX_OSFD],fd_write_cnt[_PR_MD_MAX_OSFD], + fd_exception_cnt[_PR_MD_MAX_OSFD]; +#else + struct pollfd *ioq_pollfds; + int ioq_pollfds_size; +#endif /* _PR_USE_POLL */ +}; + +#define _PR_IOQ(_cpu) ((_cpu)->md.md_unix.ioQ) +#define _PR_ADD_TO_IOQ(_pq, _cpu) PR_APPEND_LINK(&_pq.links, &_PR_IOQ(_cpu)) +#define _PR_FD_READ_SET(_cpu) ((_cpu)->md.md_unix.fd_read_set) +#define _PR_FD_READ_CNT(_cpu) ((_cpu)->md.md_unix.fd_read_cnt) +#define _PR_FD_WRITE_SET(_cpu) ((_cpu)->md.md_unix.fd_write_set) +#define _PR_FD_WRITE_CNT(_cpu) ((_cpu)->md.md_unix.fd_write_cnt) +#define _PR_FD_EXCEPTION_SET(_cpu) ((_cpu)->md.md_unix.fd_exception_set) +#define _PR_FD_EXCEPTION_CNT(_cpu) ((_cpu)->md.md_unix.fd_exception_cnt) +#define _PR_IOQ_TIMEOUT(_cpu) ((_cpu)->md.md_unix.ioq_timeout) +#define _PR_IOQ_MAX_OSFD(_cpu) ((_cpu)->md.md_unix.ioq_max_osfd) +#define _PR_IOQ_OSFD_CNT(_cpu) ((_cpu)->md.md_unix.ioq_osfd_cnt) +#define _PR_IOQ_POLLFDS(_cpu) ((_cpu)->md.md_unix.ioq_pollfds) +#define _PR_IOQ_POLLFDS_SIZE(_cpu) ((_cpu)->md.md_unix.ioq_pollfds_size) + +#define _PR_IOQ_MIN_POLLFDS_SIZE(_cpu) 32 + + struct _MDCPU { struct _MDCPU_Unix md_unix; }; @@ -566,6 +612,42 @@ struct _MDSegment { PRInt8 notused; }; +/* + * md-specific cpu structure field + */ +#define _PR_MD_MAX_OSFD FD_SETSIZE + +struct _MDCPU_Unix { + PRCList ioQ; + PRUint32 ioq_timeout; + PRInt32 ioq_max_osfd; + PRInt32 ioq_osfd_cnt; +#ifndef _PR_USE_POLL + fd_set fd_read_set, fd_write_set, fd_exception_set; + PRInt16 fd_read_cnt[_PR_MD_MAX_OSFD],fd_write_cnt[_PR_MD_MAX_OSFD], + fd_exception_cnt[_PR_MD_MAX_OSFD]; +#else + struct pollfd *ioq_pollfds; + int ioq_pollfds_size; +#endif /* _PR_USE_POLL */ +}; + +#define _PR_IOQ(_cpu) ((_cpu)->md.md_unix.ioQ) +#define _PR_ADD_TO_IOQ(_pq, _cpu) PR_APPEND_LINK(&_pq.links, &_PR_IOQ(_cpu)) +#define _PR_FD_READ_SET(_cpu) ((_cpu)->md.md_unix.fd_read_set) +#define _PR_FD_READ_CNT(_cpu) ((_cpu)->md.md_unix.fd_read_cnt) +#define _PR_FD_WRITE_SET(_cpu) ((_cpu)->md.md_unix.fd_write_set) +#define _PR_FD_WRITE_CNT(_cpu) ((_cpu)->md.md_unix.fd_write_cnt) +#define _PR_FD_EXCEPTION_SET(_cpu) ((_cpu)->md.md_unix.fd_exception_set) +#define _PR_FD_EXCEPTION_CNT(_cpu) ((_cpu)->md.md_unix.fd_exception_cnt) +#define _PR_IOQ_TIMEOUT(_cpu) ((_cpu)->md.md_unix.ioq_timeout) +#define _PR_IOQ_MAX_OSFD(_cpu) ((_cpu)->md.md_unix.ioq_max_osfd) +#define _PR_IOQ_OSFD_CNT(_cpu) ((_cpu)->md.md_unix.ioq_osfd_cnt) +#define _PR_IOQ_POLLFDS(_cpu) ((_cpu)->md.md_unix.ioq_pollfds) +#define _PR_IOQ_POLLFDS_SIZE(_cpu) ((_cpu)->md.md_unix.ioq_pollfds_size) + +#define _PR_IOQ_MIN_POLLFDS_SIZE(_cpu) 32 + struct _MDCPU { struct _MDCPU_Unix md_unix; }; diff --git a/pr/include/md/_sony.h b/pr/include/md/_sony.h index f8846024..1ff68977 100644 --- a/pr/include/md/_sony.h +++ b/pr/include/md/_sony.h @@ -103,6 +103,42 @@ struct _MDSegment { PRInt8 notused; }; +/* + * md-specific cpu structure field + */ +#define _PR_MD_MAX_OSFD FD_SETSIZE + +struct _MDCPU_Unix { + PRCList ioQ; + PRUint32 ioq_timeout; + PRInt32 ioq_max_osfd; + PRInt32 ioq_osfd_cnt; +#ifndef _PR_USE_POLL + fd_set fd_read_set, fd_write_set, fd_exception_set; + PRInt16 fd_read_cnt[_PR_MD_MAX_OSFD],fd_write_cnt[_PR_MD_MAX_OSFD], + fd_exception_cnt[_PR_MD_MAX_OSFD]; +#else + struct pollfd *ioq_pollfds; + int ioq_pollfds_size; +#endif /* _PR_USE_POLL */ +}; + +#define _PR_IOQ(_cpu) ((_cpu)->md.md_unix.ioQ) +#define _PR_ADD_TO_IOQ(_pq, _cpu) PR_APPEND_LINK(&_pq.links, &_PR_IOQ(_cpu)) +#define _PR_FD_READ_SET(_cpu) ((_cpu)->md.md_unix.fd_read_set) +#define _PR_FD_READ_CNT(_cpu) ((_cpu)->md.md_unix.fd_read_cnt) +#define _PR_FD_WRITE_SET(_cpu) ((_cpu)->md.md_unix.fd_write_set) +#define _PR_FD_WRITE_CNT(_cpu) ((_cpu)->md.md_unix.fd_write_cnt) +#define _PR_FD_EXCEPTION_SET(_cpu) ((_cpu)->md.md_unix.fd_exception_set) +#define _PR_FD_EXCEPTION_CNT(_cpu) ((_cpu)->md.md_unix.fd_exception_cnt) +#define _PR_IOQ_TIMEOUT(_cpu) ((_cpu)->md.md_unix.ioq_timeout) +#define _PR_IOQ_MAX_OSFD(_cpu) ((_cpu)->md.md_unix.ioq_max_osfd) +#define _PR_IOQ_OSFD_CNT(_cpu) ((_cpu)->md.md_unix.ioq_osfd_cnt) +#define _PR_IOQ_POLLFDS(_cpu) ((_cpu)->md.md_unix.ioq_pollfds) +#define _PR_IOQ_POLLFDS_SIZE(_cpu) ((_cpu)->md.md_unix.ioq_pollfds_size) + +#define _PR_IOQ_MIN_POLLFDS_SIZE(_cpu) 32 + struct _MDCPU { struct _MDCPU_Unix md_unix; }; diff --git a/pr/include/md/_sunos4.h b/pr/include/md/_sunos4.h index 823d22fb..41d4258c 100644 --- a/pr/include/md/_sunos4.h +++ b/pr/include/md/_sunos4.h @@ -52,6 +52,8 @@ #define NEED_STRFTIME_LOCK #define NEED_TIME_R #define HAVE_BSD_FLOCK +#define _PR_NO_LARGE_FILES +#define _PR_STAT_HAS_ONLY_ST_ATIME #define _MD_GET_INTERVAL _PR_UNIX_GetInterval #define _MD_INTERVAL_PER_SEC _PR_UNIX_TicksPerSecond @@ -145,6 +147,42 @@ struct _MDSegment { PRInt8 notused; }; +/* + * md-specific cpu structure field + */ +#define _PR_MD_MAX_OSFD FD_SETSIZE + +struct _MDCPU_Unix { + PRCList ioQ; + PRUint32 ioq_timeout; + PRInt32 ioq_max_osfd; + PRInt32 ioq_osfd_cnt; +#ifndef _PR_USE_POLL + fd_set fd_read_set, fd_write_set, fd_exception_set; + PRInt16 fd_read_cnt[_PR_MD_MAX_OSFD],fd_write_cnt[_PR_MD_MAX_OSFD], + fd_exception_cnt[_PR_MD_MAX_OSFD]; +#else + struct pollfd *ioq_pollfds; + int ioq_pollfds_size; +#endif /* _PR_USE_POLL */ +}; + +#define _PR_IOQ(_cpu) ((_cpu)->md.md_unix.ioQ) +#define _PR_ADD_TO_IOQ(_pq, _cpu) PR_APPEND_LINK(&_pq.links, &_PR_IOQ(_cpu)) +#define _PR_FD_READ_SET(_cpu) ((_cpu)->md.md_unix.fd_read_set) +#define _PR_FD_READ_CNT(_cpu) ((_cpu)->md.md_unix.fd_read_cnt) +#define _PR_FD_WRITE_SET(_cpu) ((_cpu)->md.md_unix.fd_write_set) +#define _PR_FD_WRITE_CNT(_cpu) ((_cpu)->md.md_unix.fd_write_cnt) +#define _PR_FD_EXCEPTION_SET(_cpu) ((_cpu)->md.md_unix.fd_exception_set) +#define _PR_FD_EXCEPTION_CNT(_cpu) ((_cpu)->md.md_unix.fd_exception_cnt) +#define _PR_IOQ_TIMEOUT(_cpu) ((_cpu)->md.md_unix.ioq_timeout) +#define _PR_IOQ_MAX_OSFD(_cpu) ((_cpu)->md.md_unix.ioq_max_osfd) +#define _PR_IOQ_OSFD_CNT(_cpu) ((_cpu)->md.md_unix.ioq_osfd_cnt) +#define _PR_IOQ_POLLFDS(_cpu) ((_cpu)->md.md_unix.ioq_pollfds) +#define _PR_IOQ_POLLFDS_SIZE(_cpu) ((_cpu)->md.md_unix.ioq_pollfds_size) + +#define _PR_IOQ_MIN_POLLFDS_SIZE(_cpu) 32 + struct _MDCPU { struct _MDCPU_Unix md_unix; }; diff --git a/pr/include/md/_unix_errors.h b/pr/include/md/_unix_errors.h index b022462c..03ca7a02 100644 --- a/pr/include/md/_unix_errors.h +++ b/pr/include/md/_unix_errors.h @@ -138,6 +138,9 @@ PR_EXTERN(void) _MD_unix_map_select_error(int err); PR_EXTERN(void) _MD_unix_map_poll_error(int err); #define _PR_MD_MAP_POLL_ERROR _MD_unix_map_poll_error +PR_EXTERN(void) _MD_unix_map_poll_revents_error(int err); +#define _PR_MD_MAP_POLL_REVENTS_ERROR _MD_unix_map_poll_revents_error + PR_EXTERN(void) _MD_unix_map_flock_error(int err); #define _PR_MD_MAP_FLOCK_ERROR _MD_unix_map_flock_error diff --git a/pr/include/md/_unixos.h b/pr/include/md/_unixos.h index 4555a948..a801553f 100644 --- a/pr/include/md/_unixos.h +++ b/pr/include/md/_unixos.h @@ -37,26 +37,27 @@ #include <stddef.h> #include <sys/stat.h> #include <dirent.h> +#include <errno.h> #include "prio.h" #include "prmem.h" #include "prclist.h" -/* To pick up fd_set */ -#if defined(HPUX) -#include <sys/time.h> -#elif defined(OSF1) || defined(AIX) || defined(SOLARIS) || defined(IRIX) \ - || defined(UNIXWARE) || defined(NCR) || defined(SNI) || defined(NEC) \ - || defined(BSDI) || defined(SONY) -#include <sys/select.h> -#elif defined(SUNOS4) || defined(SCO) || defined(FREEBSD) \ - || defined(NETBSD) || defined(RHAPSODY) || defined(DGUX) -#include <sys/types.h> -#elif defined(LINUX) +/* + * For select(), fd_set, and struct timeval. + * + * In The Single UNIX(R) Specification, Version 2, + * the header file for select() is <sys/time.h>. + * + * fd_set is defined in <sys/types.h>. Usually + * <sys/time.h> includes <sys/types.h>, but on some + * older systems <sys/time.h> does not include + * <sys/types.h>, so we include it explicitly. + */ #include <sys/time.h> #include <sys/types.h> -#else -#error Find out what include file defines fd_set on this platform +#if defined(AIX) /* Only pre-4.2 AIX needs it, but for simplicity... */ +#include <sys/select.h> #endif #define PR_DIRECTORY_SEPARATOR '/' @@ -64,7 +65,6 @@ #define PR_PATH_SEPARATOR ':' #define PR_PATH_SEPARATOR_STR ":" #define GCPTR - typedef int (*FARPROC)(); /* @@ -73,6 +73,26 @@ typedef int (*FARPROC)(); #define _PR_INTERRUPT_CHECK_INTERVAL_SECS 5 extern PRIntervalTime intr_timeout_ticks; +/* + * The bit flags for the in_flags and out_flags fields + * of _PR_UnixPollDesc + */ +#ifdef _PR_USE_POLL +#define _PR_UNIX_POLL_READ POLLIN +#define _PR_UNIX_POLL_WRITE POLLOUT +#define _PR_UNIX_POLL_EXCEPT POLLPRI +#define _PR_UNIX_POLL_ERR POLLERR +#define _PR_UNIX_POLL_NVAL POLLNVAL +#define _PR_UNIX_POLL_HUP POLLHUP +#else /* _PR_USE_POLL */ +#define _PR_UNIX_POLL_READ 0x1 +#define _PR_UNIX_POLL_WRITE 0x2 +#define _PR_UNIX_POLL_EXCEPT 0x4 +#define _PR_UNIX_POLL_ERR 0x8 +#define _PR_UNIX_POLL_NVAL 0x10 +#define _PR_UNIX_POLL_HUP 0x20 +#endif /* _PR_USE_POLL */ + typedef struct _PRUnixPollDesc { PRInt32 osfd; PRInt16 in_flags; @@ -92,8 +112,10 @@ typedef struct PRPollQueue { ((PRPollQueue*) ((char*) (_qp) - offsetof(PRPollQueue,links))) -extern PRInt32 _PR_WaitForFD(PRInt32 osfd, PRUintn how, - PRIntervalTime timeout); +extern PRInt32 _PR_WaitForMultipleFDs( + _PRUnixPollDesc *unixpds, + PRInt32 pdcnt, + PRIntervalTime timeout); extern void _PR_Unblock_IO_Wait(struct PRThread *thr); #if defined(_PR_LOCAL_THREADS_ONLY) || defined(_PR_GLOBAL_THREADS_ONLY) @@ -113,45 +135,9 @@ struct _MDDir { DIR *d; }; -/* - * md-specific cpu structure field, common to all Unix platforms - */ -#define _PR_MD_MAX_OSFD FD_SETSIZE - -struct _MDCPU_Unix { - PRCList ioQ; - PRUint32 ioq_timeout; - PRInt32 ioq_max_osfd; - PRInt32 ioq_osfd_cnt; -#ifndef _PR_USE_POLL - fd_set fd_read_set, fd_write_set, fd_exception_set; - PRInt16 fd_read_cnt[_PR_MD_MAX_OSFD],fd_write_cnt[_PR_MD_MAX_OSFD], - fd_exception_cnt[_PR_MD_MAX_OSFD]; -#else - struct pollfd *ioq_pollfds; - int ioq_pollfds_size; -#endif /* _PR_USE_POLL */ -}; struct _PRCPU; extern void _MD_unix_init_running_cpu(struct _PRCPU *cpu); -#define _PR_IOQ(_cpu) ((_cpu)->md.md_unix.ioQ) -#define _PR_ADD_TO_IOQ(_pq, _cpu) PR_APPEND_LINK(&_pq.links, &_PR_IOQ(_cpu)) -#define _PR_FD_READ_SET(_cpu) ((_cpu)->md.md_unix.fd_read_set) -#define _PR_FD_READ_CNT(_cpu) ((_cpu)->md.md_unix.fd_read_cnt) -#define _PR_FD_WRITE_SET(_cpu) ((_cpu)->md.md_unix.fd_write_set) -#define _PR_FD_WRITE_CNT(_cpu) ((_cpu)->md.md_unix.fd_write_cnt) -#define _PR_FD_EXCEPTION_SET(_cpu) ((_cpu)->md.md_unix.fd_exception_set) -#define _PR_FD_EXCEPTION_CNT(_cpu) ((_cpu)->md.md_unix.fd_exception_cnt) -#define _PR_IOQ_TIMEOUT(_cpu) ((_cpu)->md.md_unix.ioq_timeout) -#define _PR_IOQ_MAX_OSFD(_cpu) ((_cpu)->md.md_unix.ioq_max_osfd) -#define _PR_IOQ_OSFD_CNT(_cpu) ((_cpu)->md.md_unix.ioq_osfd_cnt) -#define _PR_IOQ_POLLFDS(_cpu) ((_cpu)->md.md_unix.ioq_pollfds) -#define _PR_IOQ_POLLFDS_SIZE(_cpu) ((_cpu)->md.md_unix.ioq_pollfds_size) - -#define _PR_IOQ_MIN_POLLFDS_SIZE(_cpu) 32 - - /* ** Make a redzone at both ends of the stack segment. Disallow access ** to those pages of memory. It's ok if the mprotect call's don't @@ -248,6 +234,7 @@ extern PRStatus _MD_KillUnixProcess(struct PRProcess *process); #define _MD_START_INTERRUPTS _MD_StartInterrupts #define _MD_STOP_INTERRUPTS _MD_StopInterrupts #define _MD_DISABLE_CLOCK_INTERRUPTS _MD_DisableClockInterrupts +#define _MD_ENABLE_CLOCK_INTERRUPTS _MD_EnableClockInterrupts #define _MD_BLOCK_CLOCK_INTERRUPTS _MD_BlockClockInterrupts #define _MD_UNBLOCK_CLOCK_INTERRUPTS _MD_UnblockClockInterrupts @@ -291,7 +278,9 @@ extern void _MD_FreeSegment(PRSegment *seg); /************************************************************************/ +#if !defined(HPUX_LW_TIMER) #define _MD_INTERVAL_INIT() +#endif #define _MD_INTERVAL_PER_MILLISEC() (_PR_MD_INTERVAL_PER_SEC() / 1000) #define _MD_INTERVAL_PER_MICROSEC() (_PR_MD_INTERVAL_PER_SEC() / 1000000) @@ -304,11 +293,6 @@ extern void _MD_FreeSegment(PRSegment *seg); extern PRInt32 _MD_AvailableSocket(PRInt32 osfd); -#include <errno.h> -#include <sys/types.h> -#include <sys/time.h> -#include <sys/stat.h> - extern void _MD_InitSegs(void); extern void _MD_StartInterrupts(void); extern void _MD_StopInterrupts(void); @@ -327,7 +311,7 @@ extern PRInt32 _MD_getfileinfo64(const char *fn, PRFileInfo64 *info); extern PRInt32 _MD_getopenfileinfo(const PRFileDesc *fd, PRFileInfo *info); extern PRInt32 _MD_getopenfileinfo64(const PRFileDesc *fd, PRFileInfo64 *info); extern PRInt32 _MD_rename(const char *from, const char *to); -extern PRInt32 _MD_access(const char *name, PRIntn how); +extern PRInt32 _MD_access(const char *name, PRAccessHow how); extern PRInt32 _MD_mkdir(const char *name, PRIntn mode); extern PRInt32 _MD_rmdir(const char *name); extern PRInt32 _MD_accept_read(PRInt32 sock, PRInt32 *newSock, @@ -516,4 +500,72 @@ extern int poll(struct pollfd *, unsigned long, int); #endif /* _PR_NEED_FAKE_POLL */ +/* +** A vector of the UNIX I/O calls we use. These are here to smooth over +** the rough edges needed for large files. All of NSPR's implmentaions +** go through this vector using syntax of the form +** result = _md_iovector.xxx64(args); +*/ + +#if defined(SOLARIS2_5) +/* +** Special case: Solaris 2.5.1 +** Solaris starts to have 64-bit file I/O in 2.6. We build on Solaris +** 2.5.1 so that we can use the same binaries on both Solaris 2.5.1 and +** 2.6. At run time, we detect whether 64-bit file I/O is available by +** looking up the 64-bit file function symbols in libc. At build time, +** we need to define the 64-bit file I/O datatypes that are compatible +** with their definitions on Solaris 2.6. +*/ +typedef PRInt64 off64_t; +typedef PRUint64 ino64_t; +typedef PRUint64 blkcnt64_t; +struct stat64 { + dev_t st_dev; + long st_pad1[3]; + ino64_t st_ino; + mode_t st_mode; + nlink_t st_nlink; + uid_t st_uid; + gid_t st_gid; + dev_t st_rdev; + long t_pad2[2]; + off64_t st_size; + timestruc_t st_atim; + timestruc_t st_mtim; + timestruc_t st_ctim; + long st_blksize; + blkcnt64_t st_blocks; + char st_fstype[_ST_FSTYPSZ]; + long st_pad4[8]; +}; +typedef struct stat64 _MDStat64; + +#elif defined(_PR_HAVE_OFF64_T) +typedef struct stat64 _MDStat64; +#elif defined(_PR_HAVE_LARGE_OFF_T) || defined(_PR_NO_LARGE_FILES) +typedef struct stat _MDStat64; +#else +#error "I don't know yet" +#endif + +typedef PRIntn (*_MD_Fstat64)(PRIntn osfd, _MDStat64 *buf); +typedef PRIntn (*_MD_Open64)(const char *path, int oflag, ...); +typedef PRIntn (*_MD_Stat64)(const char *path, _MDStat64 *buf); +typedef PRInt64 (*_MD_Lseek64)(PRIntn osfd, PRInt64, PRIntn whence); +typedef PRIntn (*_MD_Lockf64)(PRIntn osfd, PRIntn function, PRInt64 size); +typedef void* (*_MD_Mmap64)( + void *addr, PRSize len, PRIntn prot, PRIntn flags, + PRIntn fildes, PRInt64 offset); +struct _MD_IOVector +{ + _MD_Open64 _open64; + _MD_Mmap64 _mmap64; + _MD_Stat64 _stat64; + _MD_Fstat64 _fstat64; + _MD_Lockf64 _lockf64; + _MD_Lseek64 _lseek64; +}; +extern struct _MD_IOVector _md_iovector; + #endif /* prunixos_h___ */ diff --git a/pr/include/md/_unixware.cfg b/pr/include/md/_unixware.cfg index d8261908..fd96a083 100644 --- a/pr/include/md/_unixware.cfg +++ b/pr/include/md/_unixware.cfg @@ -71,8 +71,7 @@ #define PR_ALIGN_OF_DOUBLE 4 #define PR_ALIGN_OF_POINTER 4 -#define _PR_USE_POLL -#define _PR_POLL_AVAILABLE +#define _PR_POLL_BACKCOMPAT #ifndef NO_NSPR_10_SUPPORT diff --git a/pr/include/md/_unixware.h b/pr/include/md/_unixware.h index 9a0afda3..b1ce660a 100644 --- a/pr/include/md/_unixware.h +++ b/pr/include/md/_unixware.h @@ -36,6 +36,8 @@ #ifndef HAVE_WEAK_IO_SYMBOLS #define HAVE_WEAK_IO_SYMBOLS #endif +#define _PR_POLL_AVAILABLE +#define _PR_USE_POLL #undef HAVE_STACK_GROWING_UP #define HAVE_NETCONFIG @@ -114,6 +116,42 @@ struct _MDSegment { PRInt8 notused; }; +/* + * md-specific cpu structure field + */ +#define _PR_MD_MAX_OSFD FD_SETSIZE + +struct _MDCPU_Unix { + PRCList ioQ; + PRUint32 ioq_timeout; + PRInt32 ioq_max_osfd; + PRInt32 ioq_osfd_cnt; +#ifndef _PR_USE_POLL + fd_set fd_read_set, fd_write_set, fd_exception_set; + PRInt16 fd_read_cnt[_PR_MD_MAX_OSFD],fd_write_cnt[_PR_MD_MAX_OSFD], + fd_exception_cnt[_PR_MD_MAX_OSFD]; +#else + struct pollfd *ioq_pollfds; + int ioq_pollfds_size; +#endif /* _PR_USE_POLL */ +}; + +#define _PR_IOQ(_cpu) ((_cpu)->md.md_unix.ioQ) +#define _PR_ADD_TO_IOQ(_pq, _cpu) PR_APPEND_LINK(&_pq.links, &_PR_IOQ(_cpu)) +#define _PR_FD_READ_SET(_cpu) ((_cpu)->md.md_unix.fd_read_set) +#define _PR_FD_READ_CNT(_cpu) ((_cpu)->md.md_unix.fd_read_cnt) +#define _PR_FD_WRITE_SET(_cpu) ((_cpu)->md.md_unix.fd_write_set) +#define _PR_FD_WRITE_CNT(_cpu) ((_cpu)->md.md_unix.fd_write_cnt) +#define _PR_FD_EXCEPTION_SET(_cpu) ((_cpu)->md.md_unix.fd_exception_set) +#define _PR_FD_EXCEPTION_CNT(_cpu) ((_cpu)->md.md_unix.fd_exception_cnt) +#define _PR_IOQ_TIMEOUT(_cpu) ((_cpu)->md.md_unix.ioq_timeout) +#define _PR_IOQ_MAX_OSFD(_cpu) ((_cpu)->md.md_unix.ioq_max_osfd) +#define _PR_IOQ_OSFD_CNT(_cpu) ((_cpu)->md.md_unix.ioq_osfd_cnt) +#define _PR_IOQ_POLLFDS(_cpu) ((_cpu)->md.md_unix.ioq_pollfds) +#define _PR_IOQ_POLLFDS_SIZE(_cpu) ((_cpu)->md.md_unix.ioq_pollfds_size) + +#define _PR_IOQ_MIN_POLLFDS_SIZE(_cpu) 32 + struct _MDCPU { struct _MDCPU_Unix md_unix; }; diff --git a/pr/include/md/_win16.h b/pr/include/md/_win16.h index bb8ba5a3..399b7c6d 100644 --- a/pr/include/md/_win16.h +++ b/pr/include/md/_win16.h @@ -296,6 +296,7 @@ extern PRStatus _PR_KillWindowsProcess(struct PRProcess *process); #define _MD_INIT_ATOMIC() #define _MD_ATOMIC_INCREMENT(x) (*x++) +#define _MD_ATOMIC_ADD(ptr, val) ((*x) += val) #define _MD_ATOMIC_DECREMENT(x) (*x--) #define _MD_ATOMIC_SET(x,y) (*x, y) @@ -388,6 +389,7 @@ PR_EXTERN(void) _MD_INIT_RUNNING_CPU(struct _PRCPU *cpu ); #define _MD_START_INTERRUPTS() #define _MD_STOP_INTERRUPTS() #define _MD_DISABLE_CLOCK_INTERRUPTS() +#define _MD_ENABLE_CLOCK_INTERRUPTS() #define _MD_BLOCK_CLOCK_INTERRUPTS() #define _MD_UNBLOCK_CLOCK_INTERRUPTS() #define _MD_EARLY_INIT _PR_MD_EARLY_INIT diff --git a/pr/include/md/_win95.h b/pr/include/md/_win95.h index 9cfbc1b4..a4710b7f 100644 --- a/pr/include/md/_win95.h +++ b/pr/include/md/_win95.h @@ -222,13 +222,17 @@ extern PRInt32 _MD_CloseSocket(PRInt32 osfd); #define _MD_SETSOCKOPT _PR_MD_SETSOCKOPT #define _MD_SELECT select #define _MD_FSYNC _PR_MD_FSYNC +#define READ_FD 1 +#define WRITE_FD 2 #define _MD_INIT_ATOMIC() #if defined(_M_IX86) || defined(_X86_) #define _MD_ATOMIC_INCREMENT _PR_MD_ATOMIC_INCREMENT +#define _MD_ATOMIC_ADD _PR_MD_ATOMIC_ADD #define _MD_ATOMIC_DECREMENT _PR_MD_ATOMIC_DECREMENT #else /* non-x86 processors */ #define _MD_ATOMIC_INCREMENT(x) InterlockedIncrement((PLONG)x) +#define _MD_ATOMIC_ADD(ptr,val) (InterlockedExchangeAdd((PLONG)ptr, (LONG)val) + val) #define _MD_ATOMIC_DECREMENT(x) InterlockedDecrement((PLONG)x) #endif /* x86 */ #define _MD_ATOMIC_SET(x,y) InterlockedExchange((PLONG)x, (LONG)y) @@ -325,6 +329,7 @@ extern PRInt32 _MD_Accept(PRFileDesc *fd, PRNetAddr *raddr, PRUint32 *rlen, #define _MD_START_INTERRUPTS() #define _MD_STOP_INTERRUPTS() #define _MD_DISABLE_CLOCK_INTERRUPTS() +#define _MD_ENABLE_CLOCK_INTERRUPTS() #define _MD_BLOCK_CLOCK_INTERRUPTS() #define _MD_UNBLOCK_CLOCK_INTERRUPTS() #define _MD_EARLY_INIT _PR_MD_EARLY_INIT @@ -368,9 +373,11 @@ extern PRStatus _PR_KillWindowsProcess(struct PRProcess *process); /* --- Native-Thread Specific Definitions ------------------------------- */ +extern struct PRThread * _MD_CURRENT_THREAD(void); + #ifdef _PR_USE_STATIC_TLS extern __declspec(thread) struct PRThread *_pr_currentThread; -#define _MD_CURRENT_THREAD() _pr_currentThread +#define _MD_GET_ATTACHED_THREAD() _pr_currentThread #define _MD_SET_CURRENT_THREAD(_thread) (_pr_currentThread = (_thread)) extern __declspec(thread) struct PRThread *_pr_thread_last_run; @@ -382,7 +389,7 @@ extern __declspec(thread) struct _PRCPU *_pr_currentCPU; #define _MD_SET_CURRENT_CPU(_cpu) (_pr_currentCPU = 0) #else /* _PR_USE_STATIC_TLS */ extern DWORD _pr_currentThreadIndex; -#define _MD_CURRENT_THREAD() ((PRThread *) TlsGetValue(_pr_currentThreadIndex)) +#define _MD_GET_ATTACHED_THREAD() ((PRThread *) TlsGetValue(_pr_currentThreadIndex)) #define _MD_SET_CURRENT_THREAD(_thread) TlsSetValue(_pr_currentThreadIndex, (_thread)) extern DWORD _pr_lastThreadIndex; diff --git a/pr/include/md/_winnt.h b/pr/include/md/_winnt.h index 7695e5f6..9de2cf05 100644 --- a/pr/include/md/_winnt.h +++ b/pr/include/md/_winnt.h @@ -34,6 +34,7 @@ #include <errno.h> #include "prio.h" +#include "prclist.h" /* * Internal configuration macros @@ -49,6 +50,7 @@ #define HAVE_SOCKET_REUSEADDR #define HAVE_SOCKET_KEEPALIVE #define _PR_HAVE_ATOMIC_OPS +#define _PR_HAVE_ATOMIC_CAS /* --- Common User-Thread/Native-Thread Definitions --------------------- */ @@ -72,9 +74,39 @@ struct _MDCPU { int unused; }; +enum _MDIOModel { + _MD_BlockingIO = 0x38, + _MD_MultiWaitIO = 0x49 +}; + +typedef struct _MDOverlapped { + OVERLAPPED overlapped; /* Used for async I/O */ + + enum _MDIOModel ioModel; /* The I/O model to implement + * using overlapped I/O. + */ + + union { + struct _MDThread *mdThread; /* For blocking I/O, this structure + * is embedded in the _MDThread + * structure. + */ + struct { + PRCList links; /* for group->io_ready list */ + struct PRRecvWait *desc; /* For multiwait I/O, this structure + * is associated with a PRRecvWait + * structure. + */ + struct PRWaitGroup *group; + struct TimerEvent *timer; + DWORD error; + } mw; + } data; +} _MDOverlapped; + struct _MDThread { /* The overlapped structure must be first! */ - OVERLAPPED overlapped; /* Used for async IO for this thread */ + struct _MDOverlapped overlapped; /* Used for async IO for this thread */ void *acceptex_buf; /* Used for AcceptEx() */ TRANSMIT_FILE_BUFFERS *xmit_bufs; /* Used for TransmitFile() */ HANDLE blocked_sema; /* Threads block on this when waiting @@ -168,6 +200,7 @@ struct _MDProcess { /* --- IO stuff --- */ +extern PRInt32 _md_Associate(HANDLE); extern PRInt32 _PR_MD_CLOSE(PRInt32 osfd, PRBool socket); #define _MD_OPEN _PR_MD_OPEN @@ -213,9 +246,11 @@ extern PRInt32 _PR_MD_CLOSE(PRInt32 osfd, PRBool socket); #define _MD_INIT_ATOMIC() #if defined(_M_IX86) || defined(_X86_) #define _MD_ATOMIC_INCREMENT _PR_MD_ATOMIC_INCREMENT +#define _MD_ATOMIC_ADD _PR_MD_ATOMIC_ADD #define _MD_ATOMIC_DECREMENT _PR_MD_ATOMIC_DECREMENT #else /* non-x86 processors */ #define _MD_ATOMIC_INCREMENT(x) InterlockedIncrement((PLONG)x) +#define _MD_ATOMIC_ADD(ptr,val) (InterlockedExchangeAdd((PLONG)ptr, (LONG)val) + val) #define _MD_ATOMIC_DECREMENT(x) InterlockedDecrement((PLONG)x) #endif /* x86 */ #define _MD_ATOMIC_SET(x,y) InterlockedExchange((PLONG)x, (LONG)y) @@ -321,6 +356,7 @@ extern struct _MDLock _pr_ioq_lock; #define _MD_START_INTERRUPTS() #define _MD_STOP_INTERRUPTS() #define _MD_DISABLE_CLOCK_INTERRUPTS() +#define _MD_ENABLE_CLOCK_INTERRUPTS() #define _MD_BLOCK_CLOCK_INTERRUPTS() #define _MD_UNBLOCK_CLOCK_INTERRUPTS() #define _MD_EARLY_INIT _PR_MD_EARLY_INIT @@ -370,43 +406,73 @@ extern PRStatus _PR_KillWindowsProcess(struct PRProcess *process); /* --- Native-Thread Specific Definitions ------------------------------- */ -#ifdef _PR_USE_STATIC_TLS +extern BOOL _pr_use_static_tls; extern __declspec(thread) struct PRThread *_pr_current_fiber; -#define _MD_CURRENT_THREAD() _pr_current_fiber -#define _MD_SET_CURRENT_THREAD(_thread) (_pr_current_fiber = (_thread)) +extern DWORD _pr_currentFiberIndex; -extern __declspec(thread) struct PRThread *_pr_fiber_last_run; -#define _MD_LAST_THREAD() _pr_fiber_last_run -#define _MD_SET_LAST_THREAD(_thread) (_pr_fiber_last_run = (_thread)) +#define _MD_GET_ATTACHED_THREAD() \ + (_pr_use_static_tls ? _pr_current_fiber \ + : (PRThread *) TlsGetValue(_pr_currentFiberIndex)) -extern __declspec(thread) struct _PRCPU *_pr_current_cpu; -#define _MD_CURRENT_CPU() _pr_current_cpu -#define _MD_SET_CURRENT_CPU(_cpu) (_pr_current_cpu = (_cpu)) +extern struct PRThread * _MD_CURRENT_THREAD(void); -extern __declspec(thread) PRUintn _pr_ints_off; -#define _MD_SET_INTSOFF(_val) (_pr_ints_off = (_val)) -#define _MD_GET_INTSOFF() _pr_ints_off +#define _MD_SET_CURRENT_THREAD(_thread) \ + PR_BEGIN_MACRO \ + if (_pr_use_static_tls) { \ + _pr_current_fiber = (_thread); \ + } else { \ + TlsSetValue(_pr_currentFiberIndex, (_thread)); \ + } \ + PR_END_MACRO -#else /* _PR_USE_STATIC_TLS */ +extern __declspec(thread) struct PRThread *_pr_fiber_last_run; +extern DWORD _pr_lastFiberIndex; -extern DWORD _pr_currentFiberIndex; -#define _MD_CURRENT_THREAD() ((PRThread *) TlsGetValue(_pr_currentFiberIndex)) -#define _MD_SET_CURRENT_THREAD(_thread) TlsSetValue(_pr_currentFiberIndex, (_thread)) +#define _MD_LAST_THREAD() \ + (_pr_use_static_tls ? _pr_fiber_last_run \ + : (PRThread *) TlsGetValue(_pr_lastFiberIndex)) -extern DWORD _pr_lastFiberIndex; -#define _MD_LAST_THREAD() ((PRThread *) TlsGetValue(_pr_lastFiberIndex)) -#define _MD_SET_LAST_THREAD(_thread) TlsSetValue(_pr_lastFiberIndex, (_thread)) +#define _MD_SET_LAST_THREAD(_thread) \ + PR_BEGIN_MACRO \ + if (_pr_use_static_tls) { \ + _pr_fiber_last_run = (_thread); \ + } else { \ + TlsSetValue(_pr_lastFiberIndex, (_thread)); \ + } \ + PR_END_MACRO +extern __declspec(thread) struct _PRCPU *_pr_current_cpu; extern DWORD _pr_currentCPUIndex; -#define _MD_CURRENT_CPU() ((struct _PRCPU *) TlsGetValue(_pr_currentCPUIndex)) -#define _MD_SET_CURRENT_CPU(_cpu) TlsSetValue(_pr_currentCPUIndex, (_cpu)) +#define _MD_CURRENT_CPU() \ + (_pr_use_static_tls ? _pr_current_cpu \ + : (struct _PRCPU *) TlsGetValue(_pr_currentCPUIndex)) + +#define _MD_SET_CURRENT_CPU(_cpu) \ + PR_BEGIN_MACRO \ + if (_pr_use_static_tls) { \ + _pr_current_cpu = (_cpu); \ + } else { \ + TlsSetValue(_pr_currentCPUIndex, (_cpu)); \ + } \ + PR_END_MACRO + +extern __declspec(thread) PRUintn _pr_ints_off; extern DWORD _pr_intsOffIndex; -#define _MD_SET_INTSOFF(_val) TlsSetValue(_pr_intsOffIndex, (LPVOID) (_val)) -#define _MD_GET_INTSOFF() ((PRUintn) TlsGetValue(_pr_intsOffIndex)) -#endif /* _PR_USE_STATIC_TLS */ +#define _MD_GET_INTSOFF() \ + (_pr_use_static_tls ? _pr_ints_off \ + : (PRUintn) TlsGetValue(_pr_intsOffIndex)) + +#define _MD_SET_INTSOFF(_val) \ + PR_BEGIN_MACRO \ + if (_pr_use_static_tls) { \ + _pr_ints_off = (_val); \ + } else { \ + TlsSetValue(_pr_intsOffIndex, (LPVOID) (_val)); \ + } \ + PR_END_MACRO /* --- Initialization stuff --- */ #define _MD_INIT_LOCKS() diff --git a/pr/include/md/prosdep.h b/pr/include/md/prosdep.h index bd8e6a19..98002558 100644 --- a/pr/include/md/prosdep.h +++ b/pr/include/md/prosdep.h @@ -50,9 +50,6 @@ PR_BEGIN_EXTERN_C #elif defined(XP_UNIX) -#include "md/_unixos.h" -#include "md/_unix_errors.h" - #if defined(AIX) #include "md/_aix.h" @@ -62,6 +59,9 @@ PR_BEGIN_EXTERN_C #elif defined(NETBSD) #include "md/_netbsd.h" +#elif defined(OPENBSD) +#include "md/_openbsd.h" + #elif defined(BSDI) #include "md/_bsdi.h" @@ -112,6 +112,9 @@ PR_BEGIN_EXTERN_C #endif +#include "md/_unixos.h" +#include "md/_unix_errors.h" + #else #error "The platform is not Unix, Windows, or Mac" diff --git a/pr/include/nspr.h b/pr/include/nspr.h index 4539af58..a2800df2 100644 --- a/pr/include/nspr.h +++ b/pr/include/nspr.h @@ -37,6 +37,7 @@ #include "prlong.h" #include "prmem.h" #include "prmon.h" +#include "prmwait.h" #include "prnetdb.h" #include "prprf.h" #include "prproces.h" diff --git a/pr/include/obsolete/pralarm.h b/pr/include/obsolete/pralarm.h index 5afb65a5..422a7b6a 100644 --- a/pr/include/obsolete/pralarm.h +++ b/pr/include/obsolete/pralarm.h @@ -46,6 +46,7 @@ #include "prtypes.h" #include "prinrval.h" + PR_BEGIN_EXTERN_C /**********************************************************************/ diff --git a/pr/include/obsolete/protypes.h b/pr/include/obsolete/protypes.h index e9fba9dc..e70b03b4 100644 --- a/pr/include/obsolete/protypes.h +++ b/pr/include/obsolete/protypes.h @@ -26,6 +26,7 @@ #if !defined(PROTYPES_H) #define PROTYPES_H + /* SVR4 typedef of uint is commonly found on UNIX machines. */ #ifdef XP_UNIX #include <sys/types.h> diff --git a/pr/include/pratom.h b/pr/include/pratom.h index 48d162a9..d8ad0a8e 100644 --- a/pr/include/pratom.h +++ b/pr/include/pratom.h @@ -25,6 +25,7 @@ #define pratom_h___ #include "prtypes.h" +#include "prlock.h" PR_BEGIN_EXTERN_C @@ -35,7 +36,7 @@ PR_BEGIN_EXTERN_C ** INPUTS: ** val: a pointer to the value to increment ** RETURN: -** the returned value has the same sign as the result +** the returned value is the result of the increment */ PR_EXTERN(PRInt32) PR_AtomicIncrement(PRInt32 *val); @@ -46,7 +47,7 @@ PR_EXTERN(PRInt32) PR_AtomicIncrement(PRInt32 *val); ** INPUTS: ** val: a pointer to the value to decrement ** RETURN: -** the returned value has the same sign as the result +** the returned value is the result of the decrement */ PR_EXTERN(PRInt32) PR_AtomicDecrement(PRInt32 *val); @@ -55,13 +56,96 @@ PR_EXTERN(PRInt32) PR_AtomicDecrement(PRInt32 *val); ** DESCRIPTION: ** Atomically set a 32 bit value. ** INPUTS: -** val: A pointer to a 32 bit value to bet set +** val: A pointer to a 32 bit value to be set ** newval: The newvalue to assign to val ** RETURN: ** Returns the prior value */ PR_EXTERN(PRInt32) PR_AtomicSet(PRInt32 *val, PRInt32 newval); +/* +** FUNCTION: PR_AtomicAdd +** DESCRIPTION: +** Atomically add a 32 bit value. +** INPUTS: +** ptr: a pointer to the value to increment +** val: value to be added +** RETURN: +** the returned value is the result of the addition +*/ +PR_EXTERN(PRInt32) PR_AtomicAdd(PRInt32 *ptr, PRInt32 val); + +/* +** LIFO linked-list (stack) +*/ +typedef struct PRStackElemStr PRStackElem; + +struct PRStackElemStr { + PRStackElem *prstk_elem_next; /* next pointer MUST be at offset 0; + assembly language code relies on this */ +}; + +typedef struct PRStackStr PRStack; + +struct PRStackStr { + PRStackElem prstk_head; /* head MUST be at offset 0; assembly + language code relies on this + */ + PRLock *prstk_lock; + char *prstk_name; +}; + + +/* +** FUNCTION: PR_CreateStack +** DESCRIPTION: +** Create a stack, a LIFO linked list +** INPUTS: +** stack_name: a pointer to string containing the name of the stack +** RETURN: +** A pointer to the created stack, if successful, else NULL. +*/ +PR_EXTERN(PRStack *) PR_CreateStack(const char *stack_name); + +/* +** FUNCTION: PR_StackPush +** DESCRIPTION: +** Push an element on the top of the stack +** INPUTS: +** stack: pointer to the stack +** stack_elem: pointer to the stack element +** RETURN: +** None +*/ +PR_EXTERN(void) PR_StackPush(PRStack *stack, PRStackElem *stack_elem); + +/* +** FUNCTION: PR_StackPop +** DESCRIPTION: +** Remove the element on the top of the stack +** INPUTS: +** stack: pointer to the stack +** RETURN: +** A pointer to the stack element removed from the top of the stack, +** if non-empty, +** else NULL +*/ +PR_EXTERN(PRStackElem *) PR_StackPop(PRStack *stack); + +/* +** FUNCTION: PR_DestroyStack +** DESCRIPTION: +** Destroy the stack +** INPUTS: +** stack: pointer to the stack +** RETURN: +** PR_SUCCESS - if successfully deleted +** PR_FAILURE - if the stack is not empty +** PR_GetError will return +** PR_INVALID_STATE_ERROR - stack is not empty +*/ +PR_EXTERN(PRStatus) PR_DestroyStack(PRStack *stack); + PR_END_EXTERN_C #endif /* pratom_h___ */ diff --git a/pr/include/prbit.h b/pr/include/prbit.h index 57853384..72beb243 100644 --- a/pr/include/prbit.h +++ b/pr/include/prbit.h @@ -20,6 +20,7 @@ #define prbit_h___ #include "prtypes.h" +PR_BEGIN_EXTERN_C /* ** A prbitmap_t is a long integer that can be used for bitmaps @@ -87,4 +88,5 @@ PR_EXTERN(PRIntn) PR_FloorLog2(PRUint32 i); (_log2) += 1; \ PR_END_MACRO +PR_END_EXTERN_C #endif /* prbit_h___ */ diff --git a/pr/include/prcountr.h b/pr/include/prcountr.h new file mode 100644 index 00000000..44d5fb43 --- /dev/null +++ b/pr/include/prcountr.h @@ -0,0 +1,512 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "NPL"); you may not use this file except in + * compliance with the NPL. You may obtain a copy of the NPL at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the NPL is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL + * for the specific language governing rights and limitations under the + * NPL. + * + * The Initial Developer of this code under the NPL is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All Rights + * Reserved. + */ + +#ifndef prcountr_h___ +#define prcountr_h___ + +/*---------------------------------------------------------------------------- +** prcountr.h -- NSPR Instrumentation counters +** +** The NSPR Counter Feature provides a means to "count +** something." Counters can be dynamically defined, incremented, +** decremented, set, and deleted under application program +** control. +** +** The Counter Feature is intended to be used as instrumentation, +** not as operational data. If you need a counter for operational +** data, use native integral types. +** +** Counters are 32bit unsigned intergers. On overflow, a counter +** will wrap. No exception is recognized or reported. +** +** A counter can be dynamically created using a two level naming +** convention. A "handle" is returned when the counter is +** created. The counter can subsequently be addressed by its +** handle. An API is provided to get an existing counter's handle +** given the names with which it was originally created. +** Similarly, a counter's name can be retrieved given its handle. +** +** The counter naming convention is a two-level hierarchy. The +** QName is the higher level of the hierarchy; RName is the +** lower level. RNames can be thought of as existing within a +** QName. The same RName can exist within multiple QNames. QNames +** are unique. The NSPR Counter is not a near-zero overhead +** feature. Application designers should be aware of +** serialization issues when using the Counter API. Creating a +** counter locks a large asset, potentially causing a stall. This +** suggest that applications should create counters at component +** initialization, for example, and not create and destroy them +** willy-nilly. ... You have been warned. +** +** Incrementing and Adding to counters uses atomic operations. +** The performance of these operations will vary from platform +** to platform. On platforms where atomic operations are not +** supported the overhead may be substantial. +** +** When traversing the counter database with FindNext functions, +** the instantaneous values of any given counter is that at the +** moment of extraction. The state of the entire counter database +** may not be viewed as atomic. +** +** The counter interface may be disabled (No-Op'd) at compile +** time. When DEBUG is defined at compile time, the Counter +** Feature is compiled into NSPR and applications invoking it. +** When DEBUG is not defined, the counter macros compile to +** nothing. To force the Counter Feature to be compiled into an +** optimized build, define FORCE_NSPR_COUNTERS at compile time +** for both NSPR and the application intending to use it. +** +** Application designers should use the macro form of the Counter +** Feature methods to minimize performance impact in optimized +** builds. The macros normally compile to nothing on optimized +** builds. +** +** Application designers should be aware of the effects of +** debug and optimized build differences when using result of the +** Counter Feature macros in expressions. +** +** The Counter Feature is thread-safe and SMP safe. +** +** /lth. 09-Jun-1998. +*/ + +#include "prtypes.h" + +PR_BEGIN_EXTERN_C + +/* +** Opaque counter handle type. +** ... don't even think of looking in here. +** +*/ +typedef void * PRCounterHandle; + +#define PRCOUNTER_NAME_MAX 31 +#define PRCOUNTER_DESC_MAX 255 + + +#if defined(DEBUG) || defined(FORCE_NSPR_COUNTERS) + +/* ----------------------------------------------------------------------- +** FUNCTION: PR_DEFINE_COUNTER() -- Define a PRCounterHandle +** +** DESCRIPTION: PR_DEFINE_COUNTER() is used to define a counter +** handle. +** +*/ +#define PR_DEFINE_COUNTER(name) PRCounterHandle name + +/* ----------------------------------------------------------------------- +** FUNCTION: PR_INIT_COUNTER_HANDLE() -- Set the value of a PRCounterHandle +** +** DESCRIPTION: +** PR_INIT_COUNTER_HANDLE() sets the value of a PRCounterHandle +** to value. +** +*/ +#define PR_INIT_COUNTER_HANDLE(handle,value)\ + (handle) = (PRCounterHandle)(value) + +/* ----------------------------------------------------------------------- +** FUNCTION: PR_CreateCounter() -- Create a counter +** +** DESCRIPTION: PR_CreateCounter() creates a counter object and +** initializes it to zero. +** +** The macro form takes as its first argument the name of the +** PRCounterHandle to receive the handle returned from +** PR_CreateCounter(). +** +** INPUTS: +** qName: The QName for the counter object. The maximum length +** of qName is defined by PRCOUNTER_NAME_MAX +** +** rName: The RName for the counter object. The maximum length +** of qName is defined by PRCOUNTER_NAME_MAX +** +** descrioption: The description of the counter object. The +** maximum length of description is defined by +** PRCOUNTER_DESC_MAX. +** +** OUTPUTS: +** +** RETURNS: +** PRCounterHandle. +** +** RESTRICTIONS: +** +*/ +#define PR_CREATE_COUNTER(handle,qName,rName,description)\ + (handle) = PR_CreateCounter((qName),(rName),(description)) + +PR_EXTERN(PRCounterHandle) + PR_CreateCounter( + const char *qName, + const char *rName, + const char *description +); + +/* ----------------------------------------------------------------------- +** FUNCTION: PR_DestroyCounter() -- Destroy a counter object. +** +** DESCRIPTION: PR_DestroyCounter() removes a counter and +** unregisters its handle from the counter database. +** +** INPUTS: +** handle: the PRCounterHandle of the counter to be destroyed. +** +** OUTPUTS: +** The counter is destroyed. +** +** RETURNS: void +** +** RESTRICTIONS: +** +*/ +#define PR_DESTROY_COUNTER(handle) PR_DestroyCounter((handle)) + +PR_EXTERN(void) + PR_DestroyCounter( + PRCounterHandle handle +); + + +/* ----------------------------------------------------------------------- +** FUNCTION: PR_GetCounterHandleFromName() -- Retreive a +** counter's handle give its name. +** +** DESCRIPTION: PR_GetCounterHandleFromName() retreives a +** counter's handle from the counter database, given the name +** the counter was originally created with. +** +** INPUTS: +** qName: Counter's original QName. +** rName: Counter's original RName. +** +** OUTPUTS: +** +** RETURNS: +** PRCounterHandle or PRCounterError. +** +** RESTRICTIONS: +** +*/ +#define PR_GET_COUNTER_HANDLE_FROM_NAME(handle,qName,rName)\ + (handle) = PR_GetCounterHandleFromName((qName),(rName)) + +PR_EXTERN(PRCounterHandle) + PR_GetCounterHandleFromName( + const char *qName, + const char *rName +); + +/* ----------------------------------------------------------------------- +** FUNCTION: PR_GetCounterNameFromHandle() -- Retreive a +** counter's name, given its handle. +** +** DESCRIPTION: PR_GetCounterNameFromHandle() retreives a +** counter's name given its handle. +** +** INPUTS: +** qName: Where to store a pointer to qName. +** rName: Where to store a pointer to rName. +** description: Where to store a pointer to description. +** +** OUTPUTS: Pointers to the Counter Feature's copies of the names +** used when the counters were created. +** +** RETURNS: void +** +** RESTRICTIONS: +** +*/ +#define PR_GET_COUNTER_NAME_FROM_HANDLE(handle,qName,rName,description)\ + PR_GetCounterNameFromHandle((handle),(qName),(rName),(description)) + +PR_EXTERN(void) + PR_GetCounterNameFromHandle( + PRCounterHandle handle, + const char **qName, + const char **rName, + const char **description +); + + +/* ----------------------------------------------------------------------- +** FUNCTION: PR_IncrementCounter() -- Add one to the referenced +** counter. +** +** DESCRIPTION: Add one to the referenced counter. +** +** INPUTS: +** handle: The PRCounterHandle of the counter to be incremented +** +** OUTPUTS: The counter is incrementd. +** +** RETURNS: void +** +** RESTRICTIONS: +** +*/ +#define PR_INCREMENT_COUNTER(handle) PR_IncrementCounter(handle) + +PR_EXTERN(void) + PR_IncrementCounter( + PRCounterHandle handle +); + + +/* ----------------------------------------------------------------------- +** FUNCTION: PR_DecrementCounter() -- Subtract one from the +** referenced counter +** +** DESCRIPTION: Subtract one from the referenced counter. +** +** INPUTS: +** handle: The PRCounterHandle of the coutner to be +** decremented. +** +** OUTPUTS: the counter is decremented. +** +** RETURNS: void +** +** RESTRICTIONS: +** +*/ +#define PR_DECREMENT_COUNTER(handle) PR_DecrementCounter(handle) + +PR_EXTERN(void) + PR_DecrementCounter( + PRCounterHandle handle +); + +/* ----------------------------------------------------------------------- +** FUNCTION: PR_AddToCounter() -- Add a value to a counter. +** +** DESCRIPTION: Add value to the counter referenced by handle. +** +** INPUTS: +** handle: the PRCounterHandle of the counter to be added to. +** +** value: the value to be added to the counter. +** +** OUTPUTS: new value for counter. +** +** RETURNS: void +** +** RESTRICTIONS: +** +*/ +#define PR_ADD_TO_COUNTER(handle,value)\ + PR_AddToCounter((handle),(value)) + +PR_EXTERN(void) + PR_AddToCounter( + PRCounterHandle handle, + PRUint32 value +); + + +/* ----------------------------------------------------------------------- +** FUNCTION: PR_SubtractFromCounter() -- A value is subtracted +** from a counter. +** +** DESCRIPTION: +** Subtract a value from a counter. +** +** INPUTS: +** handle: the PRCounterHandle of the counter to be subtracted +** from. +** +** value: the value to be subtracted from the counter. +** +** OUTPUTS: new value for counter +** +** RETURNS: void +** +** RESTRICTIONS: +** +*/ +#define PR_SUBTRACT_FROM_COUNTER(handle,value)\ + PR_SubtractFromCounter((handle),(value)) + +PR_EXTERN(void) + PR_SubtractFromCounter( + PRCounterHandle handle, + PRUint32 value +); + + +/* ----------------------------------------------------------------------- +** FUNCTION: PR_GetCounter() -- Retreive the value of a counter +** +** DESCRIPTION: +** Retreive the value of a counter. +** +** INPUTS: +** handle: the PR_CounterHandle of the counter to be retreived +** +** OUTPUTS: +** +** RETURNS: The value of the referenced counter +** +** RESTRICTIONS: +** +*/ +#define PR_GET_COUNTER(counter,handle)\ + (counter) = PR_GetCounter((handle)) + +PR_EXTERN(PRUint32) + PR_GetCounter( + PRCounterHandle handle +); + +/* ----------------------------------------------------------------------- +** FUNCTION: PR_SetCounter() -- Replace the content of counter +** with value. +** +** DESCRIPTION: The contents of the referenced counter are +** replaced by value. +** +** INPUTS: +** handle: the PRCounterHandle of the counter whose contents +** are to be replaced. +** +** value: the new value of the counter. +** +** OUTPUTS: +** +** RETURNS: void +** +** RESTRICTIONS: +** +*/ +#define PR_SET_COUNTER(handle,value) PR_SetCounter((handle),(value)) + +PR_EXTERN(void) + PR_SetCounter( + PRCounterHandle handle, + PRUint32 value +); + + +/* ----------------------------------------------------------------------- +** FUNCTION: PR_FindNextCounterQname() -- Retreive the next QName counter +** handle iterator +** +** DESCRIPTION: +** PR_FindNextCounterQname() retreives the first or next Qname +** the counter data base, depending on the value of handle. When +** handle is NULL, the function attempts to retreive the first +** QName handle in the database. When handle is a handle previosly +** retreived QName handle, then the function attempts to retreive +** the next QName handle. +** +** INPUTS: +** handle: PRCounterHandle or NULL. +** +** OUTPUTS: returned +** +** RETURNS: PRCounterHandle or NULL when no more QName counter +** handles are present. +** +** RESTRICTIONS: +** A concurrent PR_CreateCounter() or PR_DestroyCounter() may +** cause unpredictable results. +** +** A PRCounterHandle returned from this function may only be used +** in another PR_FindNextCounterQname() function call; other +** operations may cause unpredictable results. +** +*/ +#define PR_FIND_NEXT_COUNTER_QNAME(next,handle)\ + (next) = PR_FindNextCounterQname((handle)) + +PR_EXTERN(PRCounterHandle) + PR_FindNextCounterQname( + PRCounterHandle handle +); + +/* ----------------------------------------------------------------------- +** FUNCTION: PR_FindNextCounterRname() -- Retreive the next RName counter +** handle iterator +** +** DESCRIPTION: +** PR_FindNextCounterRname() retreives the first or next RNname +** handle from the counter data base, depending on the +** value of handle. When handle is NULL, the function attempts to +** retreive the first RName handle in the database. When handle is +** a handle previosly retreived RName handle, then the function +** attempts to retreive the next RName handle. +** +** INPUTS: +** handle: PRCounterHandle or NULL. +** qhandle: PRCounterHandle of a previously aquired via +** PR_FIND_NEXT_QNAME_HANDLE() +** +** OUTPUTS: returned +** +** RETURNS: PRCounterHandle or NULL when no more RName counter +** handles are present. +** +** RESTRICTIONS: +** A concurrent PR_CreateCounter() or PR_DestroyCounter() may +** cause unpredictable results. +** +** A PRCounterHandle returned from this function may only be used +** in another PR_FindNextCounterRname() function call; other +** operations may cause unpredictable results. +** +*/ +#define PR_FIND_NEXT_COUNTER_RNAME(next,rhandle,qhandle)\ + (next) = PR_FindNextCounterRname((rhandle),(qhandle)) + +PR_EXTERN(PRCounterHandle) + PR_FindNextCounterRname( + PRCounterHandle rhandle, + PRCounterHandle qhandle +); + + +#else /* ( !(defined(DEBUG) || defined(FORCE_NSPR_COUNTERS)) */ +/* +** When counters are not compiled in, provide macros that +** evaluate to No-Ops. +** +*/ + +#define PR_DEFINE_COUNTER(name) PRCounterHandle name +#define PR_INIT_COUNTER_HANDLE(handle,value) +#define PR_CREATE_COUNTER(handle,qName,rName,description) +#define PR_DESTROY_COUNTER(handle) +#define PR_GET_COUNTER_HANDLE_FROM_NAME(handle,qName,rName) +#define PR_GET_COUNTER_NAME_FROM_HANDLE(handle,qName,rName,description ) +#define PR_INCREMENT_COUNTER(handle) +#define PR_DECREMENT_COUNTER(handle) +#define PR_ADD_TO_COUNTER(handle,value) +#define PR_SUBTRACT_FROM_COUNTER(handle,value) +#define PR_GET_COUNTER(counter,handle) 0 +#define PR_SET_COUNTER(handle,value) +#define PR_FIND_NEXT_COUNTER_QNAME(next,handle) NULL +#define PR_FIND_NEXT_COUNTER_RNAME(next,rhandle,qhandle) + +#endif /* ( !(defined(DEBUG) || defined(FORCE_NSPR_COUNTERS)) */ + +PR_END_EXTERN_C + +#endif /* prcountr_h___ */ diff --git a/pr/include/prdtoa.h b/pr/include/prdtoa.h index fec81a59..22cfc58c 100644 --- a/pr/include/prdtoa.h +++ b/pr/include/prdtoa.h @@ -21,12 +21,6 @@ #include "prtypes.h" -/*******************************************************************************/ -/*******************************************************************************/ -/****************** THESE FUNCTIONS MAY NOT BE THREAD SAFE *********************/ -/*******************************************************************************/ -/*******************************************************************************/ - PR_BEGIN_EXTERN_C /* diff --git a/pr/include/prerror.h b/pr/include/prerror.h index 0f56f106..dbb7256b 100644 --- a/pr/include/prerror.h +++ b/pr/include/prerror.h @@ -25,7 +25,7 @@ PR_BEGIN_EXTERN_C typedef PRInt32 PRErrorCode; -#define PR_NSPR_ERROR_BASE -2600 +#define PR_NSPR_ERROR_BASE -6000 #define PR_OUT_OF_MEMORY_ERROR PR_NSPR_ERROR_BASE + 0 /* Insufficient memory to perform request */ @@ -147,7 +147,11 @@ typedef PRInt32 PRErrorCode; #define PR_ALREADY_INITIATED_ERROR PR_NSPR_ERROR_BASE + 67 #define PR_GROUP_EMPTY_ERROR PR_NSPR_ERROR_BASE + 68 #define PR_INVALID_STATE_ERROR PR_NSPR_ERROR_BASE + 69 -#define PR_MAX_ERROR PR_NSPR_ERROR_BASE + 70 +#define PR_NETWORK_DOWN_ERROR PR_NSPR_ERROR_BASE + 70 +#define PR_SOCKET_SHUTDOWN_ERROR PR_NSPR_ERROR_BASE + 71 +#define PR_CONNECT_ABORTED_ERROR PR_NSPR_ERROR_BASE + 72 +#define PR_HOST_UNREACHABLE_ERROR PR_NSPR_ERROR_BASE + 73 +#define PR_MAX_ERROR PR_NSPR_ERROR_BASE + 74 /* Place holder for the end of the list */ /* diff --git a/pr/include/prinit.h b/pr/include/prinit.h index cf1d5fa2..7ba12fea 100644 --- a/pr/include/prinit.h +++ b/pr/include/prinit.h @@ -44,7 +44,11 @@ PR_BEGIN_EXTERN_C ** The format of the version string is ** "<major version>.<minor version> <build date>" */ -#define PR_VERSION "2.1 yyyymmdd" +#define PR_VERSION "3.0 yyyymmdd" +#define PR_VMAJOR 3 +#define PR_VMINOR 0 +#define PR_VPATCH 0 +#define PR_BETA PR_TRUE /* ** PRVersionCheck @@ -81,8 +85,7 @@ PR_EXTERN(PRBool) PR_VersionCheck(const char *importedVersion); /* ** Initialize the runtime. Attach a thread object to the currently -** executing native thread of type "type" (as if PR_AttachThread were -** called). +** executing native thread of type "type". ** ** The specificaiton of 'maxPTDs' is ignored. */ @@ -142,6 +145,12 @@ PR_EXTERN(PRStatus) PR_Cleanup(void); PR_EXTERN(void) PR_DisableClockInterrupts(void); /* +** Enables Interrupts +** Enables timer signals used for pre-emptive scheduling. +*/ +PR_EXTERN(void) PR_EnableClockInterrupts(void); + +/* ** Block Interrupts ** Blocks the timer signal used for pre-emptive scheduling */ @@ -159,6 +168,13 @@ PR_EXTERN(void) PR_UnblockClockInterrupts(void); PR_EXTERN(void) PR_SetConcurrency(PRUintn numCPUs); /* +** Control the method and size of the file descriptor (PRFileDesc*) +** cache used by the runtime. Setting 'high' to zero is for performance, +** any other value probably for debugging (see memo on FD caching). +*/ +PR_EXTERN(PRStatus) PR_SetFDCacheSize(PRIntn low, PRIntn high); + +/* * Cause an immediate, nongraceful, forced termination of the process. * It takes a PRIntn argument, which is the exit status code of the * process. diff --git a/pr/include/prio.h b/pr/include/prio.h index 1cc6719e..89ffb871 100644 --- a/pr/include/prio.h +++ b/pr/include/prio.h @@ -1408,8 +1408,7 @@ PR_EXTERN(PRInt32) PR_TransmitFile( ** void *buf ** A pointer to a buffer to receive data sent by the client. This ** buffer must be large enough to receive <amount> bytes of data -** and two PRNetAddr structures (thus allowing the runtime to align -** the addresses as needed). +** and two PRNetAddr structures, plus an extra 32 bytes. ** PRInt32 amount ** The number of bytes of client data to receive. Does not include ** the size of the PRNetAddr structures. If 0, no data will be read @@ -1425,7 +1424,8 @@ PR_EXTERN(PRInt32) PR_TransmitFile( ** will only be valid if the function return does not indicate failure. ** PRNetAddr **peerAddr, ** The address of the remote socket. This parameter will only be -** valid if the function return does not indicate failure. +** valid if the function return does not indicate failure. The +** returned address is not guaranteed to be properly aligned. ** ** RETURNS: ** The number of bytes read from the client or -1 on failure. The reason @@ -1570,12 +1570,9 @@ struct PRPollDesc { /* ** Bit values for PRPollDesc.in_flags or PRPollDesc.out_flags. Binary-or ** these together to produce the desired poll request. -** -** On Unix platforms where the poll() system call is available, -** the various PR_POLL_XXX flags are mapped to the native poll flags. */ -#if defined(XP_UNIX) && defined(_PR_POLL_AVAILABLE) +#if defined(_PR_POLL_BACKCOMPAT) #include <poll.h> #define PR_POLL_READ POLLIN @@ -1583,16 +1580,18 @@ struct PRPollDesc { #define PR_POLL_EXCEPT POLLPRI #define PR_POLL_ERR POLLERR /* only in out_flags */ #define PR_POLL_NVAL POLLNVAL /* only in out_flags when fd is bad */ +#define PR_POLL_HUP POLLHUP /* only in out_flags */ -#else /* XP_UNIX, _PR_POLL_AVAILABLE */ +#else /* _PR_POLL_BACKCOMPAT */ #define PR_POLL_READ 0x1 #define PR_POLL_WRITE 0x2 #define PR_POLL_EXCEPT 0x4 #define PR_POLL_ERR 0x8 /* only in out_flags */ #define PR_POLL_NVAL 0x10 /* only in out_flags when fd is bad */ +#define PR_POLL_HUP 0x20 /* only in out_flags */ -#endif /* XP_UNIX, _PR_POLL_AVAILABLE */ +#endif /* _PR_POLL_BACKCOMPAT */ /* ************************************************************************* @@ -1632,6 +1631,55 @@ struct PRPollDesc { PR_EXTERN(PRInt32) PR_Poll( PRPollDesc *pds, PRIntn npds, PRIntervalTime timeout); +/* +************************************************************************** +** +** Pollable events +** +** A pollable event is a special kind of file descriptor. +** The only I/O operation you can perform on a pollable event +** is to poll it with the PR_POLL_READ flag. You can't +** read from or write to a pollable event. +** +** The purpose of a pollable event is to combine event waiting +** with I/O waiting in a single PR_Poll call. Pollable events +** are implemented using a pipe or a pair of TCP sockets +** connected via the loopback address, therefore setting and +** waiting for pollable events are expensive operating system +** calls. Do not use pollable events for general thread +** synchronization. Use condition variables instead. +** +** A pollable event has two states: set and unset. Events +** are not queued, so there is no notion of an event count. +** A pollable event is either set or unset. +** +** A new pollable event is created by a PR_NewPollableEvent +** call and is initially in the unset state. +** +** PR_WaitForPollableEvent blocks the calling thread until +** the pollable event is set, and then it atomically unsets +** the pollable event before it returns. +** +** To set a pollable event, call PR_SetPollableEvent. +** +** One can call PR_Poll with the PR_POLL_READ flag on a pollable +** event. When the pollable event is set, PR_Poll returns with +** the PR_POLL_READ flag set in the out_flags. +** +** To close a pollable event, call PR_DestroyPollableEvent +** (not PR_Close). +** +************************************************************************** +*/ + +PR_EXTERN(PRFileDesc *) PR_NewPollableEvent(void); + +PR_EXTERN(PRStatus) PR_DestroyPollableEvent(PRFileDesc *event); + +PR_EXTERN(PRStatus) PR_SetPollableEvent(PRFileDesc *event); + +PR_EXTERN(PRStatus) PR_WaitForPollableEvent(PRFileDesc *event); + PR_END_EXTERN_C #endif /* prio_h___ */ diff --git a/pr/include/private/Makefile b/pr/include/private/Makefile index c2e38c41..3a8b1e9f 100644 --- a/pr/include/private/Makefile +++ b/pr/include/private/Makefile @@ -24,7 +24,7 @@ include $(MOD_DEPTH)/config/config.mk RELEASE_HEADERS = pprio.h pprthred.h prpriv.h RELEASE_HEADERS_DEST = $(RELEASE_INCLUDE_DIR)/private -HEADERS = $(RELEASE_HEADERS) primpl.h +HEADERS = $(RELEASE_HEADERS) pprmwait.h primpl.h include $(MOD_DEPTH)/config/rules.mk diff --git a/pr/include/private/pprio.h b/pr/include/private/pprio.h index c9d6eec1..7e73b31e 100644 --- a/pr/include/private/pprio.h +++ b/pr/include/private/pprio.h @@ -28,8 +28,19 @@ #include "prtypes.h" #include "prio.h" -NSPR_BEGIN_EXTERN_C +PR_BEGIN_EXTERN_C +/* +** File descriptors of the NSPR layer can be in one of the +** following states (stored in the 'state' field of struct +** PRFilePrivate): +** - _PR_FILEDESC_OPEN: The OS fd is open. +** - _PR_FILEDESC_CLOSED: The OS fd is closed. The PRFileDesc +** is still open but is unusable. The only operation allowed +** on the PRFileDesc is PR_Close(). +** - _PR_FILEDESC_FREED: The OS fd is closed and the PRFileDesc +** structure is freed. +*/ #define _PR_FILEDESC_OPEN 0xaaaaaaaa /* 1010101... */ #define _PR_FILEDESC_CLOSED 0x55555555 /* 0101010... */ @@ -186,6 +197,6 @@ PR_EXTERN(void) PR_NT_UseNonblock(); #endif /* WIN32 */ -NSPR_END_EXTERN_C +PR_END_EXTERN_C #endif /* pprio_h___ */ diff --git a/pr/src/io/pprmwait.h b/pr/include/private/pprmwait.h index adfce668..edad3420 100644 --- a/pr/src/io/pprmwait.h +++ b/pr/include/private/pprmwait.h @@ -31,8 +31,8 @@ #define MAX_POLLING_INTERVAL 100 #define _PR_DEFAULT_HASH_LENGTH 59 -#define _MW_REHASH(a, i, m) _MW_HASH((PRUword)(a) + (i) + _PR_HASH_OFFSET, m) -#define _MW_HASH(a, m) ((((PRUword)(a) >> 4) ^ ((PRUword)(a) >> 10)) % (m)) +#define _MW_REHASH(a, i, m) _MW_HASH((PRUptrdiff)(a) + (i) + _PR_HASH_OFFSET, m) +#define _MW_HASH(a, m) ((((PRUptrdiff)(a) >> 4) ^ ((PRUptrdiff)(a) >> 10)) % (m)) #define _MW_ABORTED(_rv) \ ((PR_FAILURE == (_rv)) && (PR_PENDING_INTERRUPT_ERROR == PR_GetError())) @@ -61,17 +61,52 @@ struct PRWaitGroup PRThread* poller; /* thread that's actually doing the poll() */ PRUint16 waiting_threads; /* number of threads waiting for recv */ PRUint16 polling_count; /* number of elements in the polling list */ + PRUint32 p_timestamp; /* pseudo-time group had element removed */ PRPollDesc *polling_list; /* list poller builds for polling */ PRIntervalTime last_poll; /* last time we polled */ _PRWaiterHash *waiter; /* pointer to hash table of wait receive objects */ + +#ifdef WINNT + /* + * On NT, idle threads are responsible for getting completed i/o. + * They need to add completed i/o to the io_ready list. Since + * idle threads cannot use nspr locks, we have to use an md lock + * to protect the io_ready list. + */ + _MDLock mdlock; /* protect io_ready, waiter, and wait_list */ + PRCList wait_list; /* used in place of io_complete. reuse + * waitQLinks in the PRThread structure. */ +#endif /* WINNT */ }; +/********************************************************************** +*********************************************************************** +******************** Wait group enumerations ************************** +*********************************************************************** +**********************************************************************/ typedef struct _PRGlobalState { PRCList group_list; /* master of the group list */ PRWaitGroup *group; /* the default (NULL) group */ } _PRGlobalState; +#ifdef WINNT +extern PRStatus NT_HashRemoveInternal(PRWaitGroup *group, PRFileDesc *fd); +#endif + +typedef enum {_PR_ENUM_UNSEALED=0, _PR_ENUM_SEALED=0x0eadface} _PREnumSeal; + +struct PRMWaitEnumerator +{ + PRWaitGroup *group; /* group this enumerator is bound to */ + PRThread *thread; /* thread in midst of an enumeration */ + _PREnumSeal seal; /* trying to detect deleted objects */ + PRUint32 p_timestamp; /* when enumeration was (re)started */ + PRRecvWait **waiter; /* pointer into hash table */ + PRUintn index; /* position in hash table */ + void *pad[4]; /* some room to grow */ +}; + #endif /* defined(_PPRMWAIT_H) */ /* pprmwait.h */ diff --git a/pr/include/private/primpl.h b/pr/include/private/primpl.h index 0d4bd69d..f4c32230 100644 --- a/pr/include/private/primpl.h +++ b/pr/include/private/primpl.h @@ -46,6 +46,8 @@ #include "nspr.h" #include "prpriv.h" +typedef struct PRSegment PRSegment; + #ifdef XP_MAC #include "prosdep.h" #include "probslet.h" @@ -128,18 +130,6 @@ typedef struct _MDFileMap _MDFileMap; ** stuff, this is a pretty small set. */ -struct _PT_Bookeeping -{ - PRLock *ml; /* a lock to protect ourselves */ - PRCondVar *cv; /* used to signal global things */ - PRUint16 system, user; /* a count of the two different types */ - PRUintn this_many; /* number of threads allowed for exit */ - pthread_key_t key; /* private private data key */ - pthread_key_t highwater; /* ordinal value of next key to be allocated */ - PRThread *first, *last; /* list of threads we know about */ - PRInt32 minPrio, maxPrio; /* range of scheduling priorities */ -}; - #define PT_CV_NOTIFIED_LENGTH 6 typedef struct _PT_Notified _PT_Notified; struct _PT_Notified @@ -162,7 +152,8 @@ struct _PT_Notified #define PT_THREAD_PRIMORD 0x08 /* this is the primordial thread */ #define PT_THREAD_ABORTED 0x10 /* thread has been interrupted */ #define PT_THREAD_GCABLE 0x20 /* thread is garbage collectible */ -#define PT_THREAD_SUSPENDED 0x40 /* thread has been suspended */ +#define PT_THREAD_SUSPENDED 0x40 /* thread has been suspended */ +#define PT_THREAD_FOREIGN 0x80 /* thread is not one of ours */ /* ** Possible values for thread's suspend field @@ -189,13 +180,23 @@ typedef struct PTDebug PRUintn cvars_notified, delayed_cv_deletes; } PTDebug; -PR_EXTERN(PTDebug) PT_GetStats(void); +PR_EXTERN(void) PT_GetStats(PTDebug* here); PR_EXTERN(void) PT_FPrintStats(PRFileDesc *fd, const char *msg); +#else + +typedef PRUintn PTDebug; +#define PT_GetStats(_p) +#define PT_FPrintStats(_fd, _msg) + #endif /* defined(DEBUG) */ #else /* defined(_PR_PTHREADS) */ +typedef PRUintn PTDebug; +#define PT_GetStats(_p) +#define PT_FPrintStats(_fd, _msg) + /* ** This section is contains those parts needed to implement NSPR on ** platforms in general. One would assume that the pthreads implementation @@ -273,7 +274,7 @@ typedef struct _PRInterruptTable { #define _PR_CPU_PTR(_qp) \ ((_PRCPU*) ((char*) (_qp) - offsetof(_PRCPU,links))) -#if !defined(IRIX) +#if !defined(IRIX) && !defined(WIN32) #define _MD_GET_ATTACHED_THREAD() (_PR_MD_CURRENT_THREAD()) #endif @@ -305,8 +306,6 @@ PR_EXTERN(PRInt32) _pr_intsOff; #define _MD_GET_INTSOFF() 0 #define _MD_SET_INTSOFF(_val) -#define _PR_SET_INTSOFF(_is) -#define _PR_GET_INTSOFF(_is) #define _PR_INTSOFF(_is) #define _PR_FAST_INTSON(_is) #define _PR_INTSON(_is) @@ -337,11 +336,6 @@ PR_EXTERN(PRInt32) _pr_intsOff; #else -#define _PR_SET_INTSOFF(_val) \ - PR_BEGIN_MACRO \ - _PR_MD_SET_INTSOFF(_val); \ - PR_END_MACRO - #define _PR_INTSOFF(_is) \ PR_BEGIN_MACRO \ (_is) = _PR_MD_GET_INTSOFF(); \ @@ -556,14 +550,6 @@ typedef struct _PRPerThreadExit { void *arg; } _PRPerThreadExit; -/* - * Thread private data destructor array - * There is a destructor (or NULL) associated with each key and - * applied to all threads known to the system. - * Storage allocated in prtpd.c. - */ -extern PRThreadPrivateDTOR *_pr_tpd_destructors; - /* PRThread.flags */ #define _PR_SYSTEM 0x01 #define _PR_INTERRUPT 0x02 @@ -575,7 +561,7 @@ extern PRThreadPrivateDTOR *_pr_tpd_destructors; #define _PR_GLOBAL_SCOPE 0x80 /* thread is global scope */ #define _PR_IDLE_THREAD 0x200 /* this is an idle thread */ #define _PR_GCABLE_THREAD 0x400 /* this is a collectable thread */ -#define _PR_BOUND_THREAD 0x800 /* a bound thread (only on solaris) */ +#define _PR_BOUND_THREAD 0x800 /* a bound thread */ /* PRThread.state */ #define _PR_UNBORN 0 @@ -667,9 +653,9 @@ extern PRUint32 _pr_utid; extern struct _PRCPU *_pr_primordialCPU; extern PRLock *_pr_activeLock; /* lock for userActive and systemActive */ -extern PRUintn _pr_userActive; /* number of active user threads */ -extern PRUintn _pr_systemActive; /* number of active system threads */ -extern PRUintn _pr_primordialExitCount; /* number of user threads left +extern PRInt32 _pr_userActive; /* number of active user threads */ +extern PRInt32 _pr_systemActive; /* number of active system threads */ +extern PRInt32 _pr_primordialExitCount; /* number of user threads left * before the primordial thread * can exit. */ extern PRCondVar *_pr_primordialExitCVar; /* the condition variable for @@ -718,10 +704,13 @@ PR_EXTERN(PRThread*) _PR_CreateThread(PRThreadType type, extern void _PR_NativeDestroyThread(PRThread *thread); extern void _PR_UserDestroyThread(PRThread *thread); -PR_EXTERN(PRThread*) _PRI_AttachThread( +extern PRThread* _PRI_AttachThread( PRThreadType type, PRThreadPriority priority, PRThreadStack *stack, PRUint32 flags); +extern void _PRI_DetachThread(void); + + #define _PR_IO_PENDING(_thread) ((_thread)->io_pending) PR_EXTERN(void) _PR_MD_INIT_CPUS(); @@ -735,6 +724,9 @@ PR_EXTERN(void) _PR_MD_WAKEUP_CPUS(); PR_EXTERN(void) _PR_MD_STOP_INTERRUPTS(void); #define _PR_MD_STOP_INTERRUPTS _MD_STOP_INTERRUPTS +PR_EXTERN(void) _PR_MD_ENABLE_CLOCK_INTERRUPTS(void); +#define _PR_MD_ENABLE_CLOCK_INTERRUPTS _MD_ENABLE_CLOCK_INTERRUPTS + PR_EXTERN(void) _PR_MD_DISABLE_CLOCK_INTERRUPTS(void); #define _PR_MD_DISABLE_CLOCK_INTERRUPTS _MD_DISABLE_CLOCK_INTERRUPTS @@ -995,34 +987,16 @@ extern PRInt32 _PR_MD_WRITEV( PRInt32 iov_size, PRIntervalTime timeout); #define _PR_MD_WRITEV _MD_WRITEV -extern PRInt32 _PR_MD_LSEEK(PRFileDesc *fd, PRInt32 offset, int whence); -#define _PR_MD_LSEEK _MD_LSEEK - -extern PRInt64 _PR_MD_LSEEK64(PRFileDesc *fd, PRInt64 offset, int whence); -#define _PR_MD_LSEEK64 _MD_LSEEK64 - extern PRInt32 _PR_MD_FSYNC(PRFileDesc *fd); #define _PR_MD_FSYNC _MD_FSYNC extern PRInt32 _PR_MD_DELETE(const char *name); #define _PR_MD_DELETE _MD_DELETE -extern PRInt32 _PR_MD_GETFILEINFO(const char *fn, PRFileInfo *info); -#define _PR_MD_GETFILEINFO _MD_GETFILEINFO - -extern PRInt32 _PR_MD_GETFILEINFO64(const char *fn, PRFileInfo64 *info); -#define _PR_MD_GETFILEINFO64 _MD_GETFILEINFO64 - -extern PRInt32 _PR_MD_GETOPENFILEINFO(const PRFileDesc *fd, PRFileInfo *info); -#define _PR_MD_GETOPENFILEINFO _MD_GETOPENFILEINFO - -extern PRInt32 _PR_MD_GETOPENFILEINFO64(const PRFileDesc *fd, PRFileInfo64 *info); -#define _PR_MD_GETOPENFILEINFO64 _MD_GETOPENFILEINFO64 - extern PRInt32 _PR_MD_RENAME(const char *from, const char *to); #define _PR_MD_RENAME _MD_RENAME -extern PRInt32 _PR_MD_ACCESS(const char *name, PRIntn how); +extern PRInt32 _PR_MD_ACCESS(const char *name, PRAccessHow how); #define _PR_MD_ACCESS _MD_ACCESS extern PRInt32 _PR_MD_STAT(const char *name, struct stat *buf); @@ -1174,16 +1148,63 @@ PR_EXTERN(void *) _PR_MD_GET_SP(PRThread *thread); *************************************************************************/ /************************************************************************/ +extern PRInt32 _PR_MD_LSEEK(PRFileDesc *fd, PRInt32 offset, PRSeekWhence whence); +#define _PR_MD_LSEEK _MD_LSEEK + +extern PRInt64 _PR_MD_LSEEK64(PRFileDesc *fd, PRInt64 offset, PRSeekWhence whence); +#define _PR_MD_LSEEK64 _MD_LSEEK64 + +extern PRInt32 _PR_MD_GETFILEINFO(const char *fn, PRFileInfo *info); +#define _PR_MD_GETFILEINFO _MD_GETFILEINFO + +extern PRInt32 _PR_MD_GETFILEINFO64(const char *fn, PRFileInfo64 *info); +#define _PR_MD_GETFILEINFO64 _MD_GETFILEINFO64 + +extern PRInt32 _PR_MD_GETOPENFILEINFO(const PRFileDesc *fd, PRFileInfo *info); +#define _PR_MD_GETOPENFILEINFO _MD_GETOPENFILEINFO + +extern PRInt32 _PR_MD_GETOPENFILEINFO64(const PRFileDesc *fd, PRFileInfo64 *info); +#define _PR_MD_GETOPENFILEINFO64 _MD_GETOPENFILEINFO64 + + +/*****************************************************************************/ +/************************** File descriptor caching **************************/ +/*****************************************************************************/ +extern void _PR_InitFdCache(void); +extern void _PR_CleanupFdCache(void); +extern PRFileDesc *_PR_Getfd(void); +extern void _PR_Putfd(PRFileDesc *fd); + +/* + * These flags are used by NSPR temporarily in the poll + * descriptor's out_flags field to record the mapping of + * NSPR's poll flags to the system poll flags. + * + * If _PR_POLL_READ_SYS_WRITE bit is set, it means the + * PR_POLL_READ flag specified by the topmost layer is + * mapped to the WRITE flag at the system layer. Similarly + * for the other three _PR_POLL_XXX_SYS_YYY flags. It is + * assumed that the PR_POLL_EXCEPT flag doesn't get mapped + * to other flags. + */ +#define _PR_POLL_READ_SYS_READ 0x1 +#define _PR_POLL_READ_SYS_WRITE 0x2 +#define _PR_POLL_WRITE_SYS_READ 0x4 +#define _PR_POLL_WRITE_SYS_WRITE 0x8 + /* ** These methods are coerced into file descriptor methods table ** when the intended service is inappropriate for the particular ** type of file descriptor. */ extern PRIntn _PR_InvalidInt(void); +extern PRInt16 _PR_InvalidInt16(void); extern PRInt64 _PR_InvalidInt64(void); extern PRStatus _PR_InvalidStatus(void); extern PRFileDesc *_PR_InvalidDesc(void); +extern PRIOMethods _pr_faulty_methods; + extern PRStatus _PR_MapOptionName( PRSockOption optname, PRInt32 *level, PRInt32 *name); extern void _PR_InitThreads( @@ -1229,9 +1250,9 @@ struct PRCondVar { struct PRMonitor { const char* name; /* monitor name for debugging */ #if defined(_PR_PTHREADS) - PRLock lock; /* the lock struture structure */ + PRLock lock; /* the lock struture structure */ pthread_t owner; /* the owner of the lock or zero */ - PRCondVar cvar; /* condition variable queue */ + PRCondVar *cvar; /* condition variable queue */ #else /* defined(_PR_PTHREADS) */ PRCondVar *cvar; /* associated lock and condition variable queue */ #endif /* defined(_PR_PTHREADS) */ @@ -1274,19 +1295,23 @@ struct PRThreadStack { #endif /* defined(_PR_PTHREADS) */ }; +/* + * Thread private data destructor array + * There is a destructor (or NULL) associated with each key and + * applied to all threads known to the system. + * Storage allocated in prtpd.c. + */ +extern PRThreadPrivateDTOR *_pr_tpd_destructors; +extern void _PR_DestroyThreadPrivate(PRThread*); +typedef void (PR_CALLBACK *_PRStartFn)(void *); struct PRThread { PRUint32 state; /* thread's creation state */ PRThreadPriority priority; /* apparent priority, loosly defined */ - PRInt32 errorStringSize; /* byte length of current error string | zero */ - PRErrorCode errorCode; /* current NSPR error code | zero */ - PRInt32 osErrorCode; /* mapping of errorCode | zero */ - - char *errorString; /* current error string | NULL */ void *arg; /* argument to the client's entry point */ - void (PR_CALLBACK *startFunc)(void *arg); /* the root of the client's thread */ + _PRStartFn startFunc; /* the root of the client's thread */ PRThreadStack *stack; /* info about thread's stack (for GC) */ void *environment; /* pointer to execution environment */ @@ -1294,6 +1319,16 @@ struct PRThread { PRThreadDumpProc dump; /* dump thread info out */ void *dumpArg; /* argument for the dump function */ + /* + ** Per thread private data + */ + PRUint32 tpdLength; /* thread's current vector length */ + void **privateData; /* private data vector or NULL */ + PRInt32 errorStringSize; /* byte length of current error string | zero */ + PRErrorCode errorCode; /* current NSPR error code | zero */ + PRInt32 osErrorCode; /* mapping of errorCode | zero */ + char *errorString; /* current error string | NULL */ + #if defined(_PR_PTHREADS) pthread_t id; /* pthread identifier for the thread */ PRBool okToDelete; /* ok to delete the PRThread struct? */ @@ -1308,13 +1343,13 @@ struct PRThread { #endif #else /* defined(_PR_PTHREADS) */ _MDLock threadLock; /* Lock to protect thread state variables. - * Protects the following fields: - * state - * priority - * links - * wait - * cpu - */ + * Protects the following fields: + * state + * priority + * links + * wait + * cpu + */ PRUint32 queueCount; PRUint32 waitCount; @@ -1330,17 +1365,24 @@ struct PRThread { PRUint32 id; PRUint32 flags; - PRUint32 no_sched; + PRUint32 no_sched; /* Don't schedule the thread to run. + * This flag has relevance only when + * multiple NSPR CPUs are created. + * When a thread is de-scheduled, there + * is a narrow window of time in which + * the thread is put on the run queue + * but the scheduler is actually using + * the stack of this thread. It is safe + * to run this thread on a different CPU + * only when its stack is not in use on + * any other CPU. The no_sched flag is + * set during this interval to prevent + * the thread from being scheduled on a + * different CPU. + */ PRUint32 numExits; _PRPerThreadExit *ptes; - - /* - ** Per thread private data - */ - PRUint32 tpdLength; /* thread's current vector length */ - void **privateData; /* private data vector or NULL */ - /* thread termination condition variable for join */ PRCondVar *term; @@ -1413,6 +1455,7 @@ extern void _PR_InitLinker(void); extern void _PR_InitAtomic(void); extern void _PR_InitCPUs(void); extern void _PR_InitDtoa(void); +extern void _PR_InitMW(void); extern void _PR_NotifyCondVar(PRCondVar *cvar, PRThread *me); extern void _PR_CleanupThread(PRThread *thread); extern void _PR_CleanupTPD(void); @@ -1427,7 +1470,6 @@ extern PRBool _PR_Obsolete(const char *obsolete, const char *preferred); /************************************************************************/ struct PRSegment { - PRSegmentAccess access; void *vaddr; PRUint32 size; PRUintn flags; @@ -1440,6 +1482,32 @@ struct PRSegment { /* PRSegment.flags */ #define _PR_SEG_VM 0x1 +/*********************************************************************** +** FUNCTION: _PR_NewSegment() +** DESCRIPTION: +** Allocate a memory segment. The "size" value is rounded up to the +** native system page size and a page aligned portion of memory is +** returned. This memory is not part of the malloc heap. If "vaddr" is +** not NULL then PR tries to allocate the segment at the desired virtual +** address. +** INPUTS: size: size of the desired memory segment +** vaddr: address at which the newly aquired segment is to be +** mapped into memory. +** OUTPUTS: a memory segment is allocated, a PRSegment is allocated +** RETURN: pointer to PRSegment +***********************************************************************/ +extern PRSegment* _PR_NewSegment(PRUint32 size, void *vaddr); + +/*********************************************************************** +** FUNCTION: _PR_DestroySegment() +** DESCRIPTION: +** The memory segment and the PRSegment are freed +** INPUTS: seg: pointer to PRSegment to be freed +** OUTPUTS: the the PRSegment and its associated memory segment are freed +** RETURN: void +***********************************************************************/ +extern void _PR_DestroySegment(PRSegment *seg); + /************************************************************************/ extern PRInt32 _pr_pageSize; @@ -1465,14 +1533,9 @@ extern PRBool _pr_ipv6_enabled; /* defined in prnetdb.c */ /* Overriding malloc, free, etc. */ #if !defined(_PR_NO_PREEMPT) && defined(XP_UNIX) \ - && (!defined(SOLARIS) || !defined(_PR_GLOBAL_THREADS_ONLY)) \ - && (!defined(AIX) || !defined(_PR_PTHREADS)) \ - && (!defined(OSF1) || !defined(_PR_PTHREADS)) \ - && (!defined(HPUX) || !defined(_PR_PTHREADS)) \ - && (!defined(IRIX) || !defined(_PR_PTHREADS)) \ - && (!defined(LINUX) || !defined(_PR_PTHREADS)) \ - && (!defined(RHAPSODY)) \ + && !defined(_PR_PTHREADS) && !defined(_PR_GLOBAL_THREADS_ONLY) \ && !defined(PURIFY) \ + && !defined(RHAPSODY) \ && !(defined (UNIXWARE) && defined (USE_SVR4_THREADS)) #define _PR_OVERRIDE_MALLOC #endif @@ -1531,6 +1594,9 @@ extern void _PR_MD_INIT_ATOMIC(void); extern PRInt32 _PR_MD_ATOMIC_INCREMENT(PRInt32 *); #define _PR_MD_ATOMIC_INCREMENT _MD_ATOMIC_INCREMENT +extern PRInt32 _PR_MD_ATOMIC_ADD(PRInt32 *, PRInt32); +#define _PR_MD_ATOMIC_ADD _MD_ATOMIC_ADD + extern PRInt32 _PR_MD_ATOMIC_DECREMENT(PRInt32 *); #define _PR_MD_ATOMIC_DECREMENT _MD_ATOMIC_DECREMENT diff --git a/pr/include/prlog.h b/pr/include/prlog.h index 9be6c13f..8369c64c 100644 --- a/pr/include/prlog.h +++ b/pr/include/prlog.h @@ -74,7 +74,12 @@ PR_BEGIN_EXTERN_C ** log buffer to <size>. ** ** The environment variable NSPR_LOG_FILE specifies the log file to use -** unless the default of "stderr" is acceptable. +** unless the default of "stderr" is acceptable. For MS Windows +** systems, NSPR_LOG_FILE can be set to a special value: "WinDebug" +** (case sensitive). This value causes PR_LOG() output to be written +** using the Windows API OutputDebugString(). OutputDebugString() +** writes to the debugger window; some people find this helpful. +** ** ** To put log messages in your programs, use the PR_LOG macro: ** @@ -141,11 +146,6 @@ typedef struct PRLogModuleInfo { PR_EXTERN(PRLogModuleInfo*) PR_NewLogModule(const char *name); /* -** Destroys a log module. -*/ -PR_EXTERN(void) PR_DestroyLogModule(PRLogModuleInfo* logModule); - -/* ** Set the file to use for logging. Returns PR_FALSE if the file cannot ** be created */ diff --git a/pr/include/prmem.h b/pr/include/prmem.h index dc88f755..2a6c766a 100644 --- a/pr/include/prmem.h +++ b/pr/include/prmem.h @@ -135,109 +135,6 @@ PR_EXTERN(void) PR_Free(void *ptr); ***********************************************************************/ #define PR_FREEIF(_ptr) if (_ptr) PR_DELETE(_ptr) -/*********************************************************************** -** Typedef ENUM: PRSegmentAccess -** DESCRIPTION: -** Defines a number of segment accessor types for PR_Seg* functions -** -***********************************************************************/ -typedef struct PRSegment PRSegment; -typedef enum { - PR_SEGMENT_NONE, - PR_SEGMENT_RDONLY, - PR_SEGMENT_RDWR -} PRSegmentAccess; - -/*********************************************************************** -** FUNCTION: PR_NewSegment() -** DESCRIPTION: -** Allocate a memory segment. The "size" value is rounded up to the -** native system page size and a page aligned portion of memory is -** returned. This memory is not part of the malloc heap. If "vaddr" is -** not NULL then PR tries to allocate the segment at the desired virtual -** address. Segments are mapped PR_SEGMENT_RDWR when created. -** INPUTS: size: size of the desired memory segment -** vaddr: address at which the newly aquired segment is to be -** mapped into memory. -** OUTPUTS: a memory segment is allocated, a PRSegment is allocated -** RETURN: pointer to PRSegment -***********************************************************************/ -PR_EXTERN(PRSegment*) PR_NewSegment(PRUint32 size, void *vaddr); - -/*********************************************************************** -** FUNCTION: PR_DestroySegment() -** DESCRIPTION: -** The memory segment and the PRSegment are freed -** INPUTS: seg: pointer to PRSegment to be freed -** OUTPUTS: the the PRSegment and its associated memory segment are freed -** RETURN: void -***********************************************************************/ -PR_EXTERN(void) PR_DestroySegment(PRSegment *seg); - -/*********************************************************************** -** FUNCTION: PR_GrowSegment() -** DESCRIPTION: -** Attempt to grow/shrink a memory segment. If deltaBytes is positive, -** the segment is grown. If deltaBytes is negative, the segment is -** shrunk. This returns the number of bytes added to the segment if -** successful, zero otherwise. -** INPUTS: seg: pointer to a PRSegment -** OUTPUTS: -** RETURN: PRUint32: number of bytes added to the memory segment or zero -***********************************************************************/ -PR_EXTERN(PRUint32) PR_GrowSegment(PRSegment *seg, PRInt32 deltaBytes); - -/*********************************************************************** -** FUNCTION: PR_GetSegmentVaddr() -** DESCRIPTION: -** PR_Segment member accessor function. -** Return the virtual address of the memory segment -** -** INPUTS: seg: pointer to a PRSegment -** OUTPUTS: none -** RETURN: void*: Address where the memory segment is mapped. -***********************************************************************/ -PR_EXTERN(void*) PR_GetSegmentVaddr(PRSegment *seg); - -/*********************************************************************** -** FUNCTION: PR_GetSegmentSize() -** DESCRIPTION: -** PR_Segment member accessor function. -** Return the size of the associated memory segment -** INPUTS: seg: pointer to a PRSegment -** OUTPUTS: none -** RETURN: size_t: size of the associated memory segment -***********************************************************************/ -PR_EXTERN(size_t) PR_GetSegmentSize(PRSegment *seg); - -/*********************************************************************** -** FUNCTION: PR_MapSegment() -** DESCRIPTION: -** Change the mapping on a segment. -** "how" == PR_SEGMENT_NONE: the segment becomes unmapped -** "how" == PR_SEGMENT_RDONLY: the segment becomes mapped and readable -** "how" == PR_SEGMENT_RDWR: the segment becomes mapped read/write -** -** Note: If a segment can be read then it is also possible to execute -** code in it. -** INPUTS: seg: pointer to a PRSegment -** how: one of PRSegmentAccess enumerated values -** OUTPUTS: the access for the associated memory segment is changed -** RETURN: void -***********************************************************************/ -PR_EXTERN(void) PR_MapSegment(PRSegment *seg, PRSegmentAccess how); - -/*********************************************************************** -** FUNCTION: PR_GetSegmentAccess() -** DESCRIPTION: -** PR_Segment member accessor function. -** Return a memory segment's current access rights -** INPUTS: seg: pointer to a PRSegment -** OUTPUTS: -** RETURN: PRSegmentAccess: current access rights -***********************************************************************/ -PR_EXTERN(PRSegmentAccess) PR_GetSegmentAccess(PRSegment *seg); - PR_END_EXTERN_C #endif /* prmem_h___ */ diff --git a/pr/include/prmwait.h b/pr/include/prmwait.h index c63398bd..91f44393 100644 --- a/pr/include/prmwait.h +++ b/pr/include/prmwait.h @@ -53,7 +53,7 @@ typedef struct PRWaitGroup PRWaitGroup; ** ENUMERATION: PRMWStatus ** DESCRIPTION: ** This enumeration is used to indicate the completion status of -** a recieve wait object. Generally stated, a positive value indicates +** a receive wait object. Generally stated, a positive value indicates ** that the operation is not yet complete. A zero value indicates ** success (similar to PR_SUCCESS) and any negative value is an ** indication of failure. The reason for the failure can be retrieved @@ -94,6 +94,15 @@ typedef struct PRMemoryDescriptor } PRMemoryDescriptor; /* +** STRUCTURE: PRMWaitClientData +** DESCRIPTION: +** An opague stucture for which a client MAY give provide a concrete +** definition and associate with a receive descriptor. The NSPR runtime +** does not manage this field. It is completely up to the client. +*/ +typedef struct PRMWaitClientData PRMWaitClientData; + +/* ** STRUCTURE: PRRecvWait ** DESCRIPTION: ** A receive wait object contains the file descriptor that is subject @@ -117,10 +126,22 @@ typedef struct PRRecvWait PRMWStatus outcome; /* outcome of the current/last operation */ PRIntervalTime timeout; /* time allowed for entire operation */ - PRInt32 bytesRecv; /* number of bytes transferred into buffer */ + PRInt32 bytesRecv; /* number of bytes transferred into buffer */ PRMemoryDescriptor buffer; /* where to store first segment of input data */ + PRMWaitClientData *client; /* pointer to arbitrary client defined data */ } PRRecvWait; +/* +** STRUCTURE: PRMWaitEnumerator +** DESCRIPTION: +** An enumeration object is used to store the state of an existing +** enumeration over a wait group. The opaque object must be allocated +** by the client and the reference presented on each call to the +** pseudo-stateless enumerator. The enumeration objects are sharable +** only in serial fashion. +*/ +typedef struct PRMWaitEnumerator PRMWaitEnumerator; + /* ** FUNCTION: PR_AddWaitFileDesc @@ -139,7 +160,7 @@ typedef struct PRRecvWait ** to semantically group various file descriptors by the ** client's application. ** desc A reference to a valid PRRecvWait. The object of the -** reference must be preserved and treated as read-only +** reference must be preserved and not be modified ** until its ownership is returned to the client. ** RETURN ** PRStatus An indication of success. If equal to PR_FAILUE details @@ -295,12 +316,76 @@ PR_EXTERN(PRWaitGroup*) PR_CreateWaitGroup(PRInt32 size); ** ** ERRORS ** PR_INVALID_ARGUMENT_ERROR - The 'group' argument does not reference a known object. +** The 'group' argument does not reference a known object. ** PR_INVALID_STATE_ERROR ** The group still contains receive wait objects. */ PR_EXTERN(PRStatus) PR_DestroyWaitGroup(PRWaitGroup *group); +/* +** FUNCTION: PR_CreateMWaitEnumerator +** DESCRIPTION: +** The PR_CreateMWaitEnumerator() function returns a reference to an +** opaque PRMWaitEnumerator object. The enumerator object is required +** as an argument for each successive call in the stateless enumeration +** of the indicated wait group. +** +** group The wait group that the enumeration is intended to +** process. It may be be the default wait group (NULL). +** RETURN +** PRMWaitEnumerator* group +** A reference to an object that will be used to store +** intermediate state of enumerations. +** ERRORS +** Errors are indicated by the function returning a NULL. +** PR_INVALID_ARGUMENT_ERROR +** The 'group' argument does not reference a known object. +** PR_OUT_OF_MEMORY_ERROR +*/ +PR_EXTERN(PRMWaitEnumerator*) PR_CreateMWaitEnumerator(PRWaitGroup *group); + +/* +** FUNCTION: PR_DestroyMWaitEnumerator +** DESCRIPTION: +** Destroys the object created by PR_CreateMWaitEnumerator(). The reference +** used as an argument becomes invalid. +** +** INPUT +** PRMWaitEnumerator* enumerator +** The PRMWaitEnumerator object to destroy. +** RETURN +** PRStatus +** PR_SUCCESS if successful, PR_FAILURE otherwise. +** ERRORS +** PR_INVALID_ARGUMENT_ERROR +** The enumerator is invalid. +*/ +PR_EXTERN(PRStatus) PR_DestroyMWaitEnumerator(PRMWaitEnumerator* enumerator); + +/* +** FUNCTION: PR_EnumerateWaitGroup +** DESCRIPTION: +** PR_EnumerateWaitGroup is a thread safe enumerator over a wait group. +** Each call to the enumerator must present a valid PRMWaitEnumerator +** rererence and a pointer to the "previous" element returned from the +** enumeration process or a NULL. +** +** An enumeration is started by passing a NULL as the "previous" value. +** Subsequent calls to the enumerator must pass in the result of the +** previous call. The enumeration end is signaled by the runtime returning +** a NULL as the result. +** +** Modifications to the content of the wait group are allowed during +** an enumeration. The effect is that the enumeration may have to be +** "reset" and that may result in duplicates being returned from the +** enumeration. +** +** An enumeration may be abandoned at any time. The runtime is not +** keeping any state, so there are no issues in that regard. +*/ +PR_EXTERN(PRRecvWait*) PR_EnumerateWaitGroup( + PRMWaitEnumerator *enumerator, const PRRecvWait *previous); + PR_END_EXTERN_C #endif /* defined(_PRMWAIT_H) */ diff --git a/pr/include/prolock.h b/pr/include/prolock.h new file mode 100644 index 00000000..b9dcd9f9 --- /dev/null +++ b/pr/include/prolock.h @@ -0,0 +1,196 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "NPL"); you may not use this file except in + * compliance with the NPL. You may obtain a copy of the NPL at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the NPL is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL + * for the specific language governing rights and limitations under the + * NPL. + * + * The Initial Developer of this code under the NPL is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All Rights + * Reserved. + */ + +#ifndef prolock_h___ +#define prolock_h___ + +#include "prtypes.h" + +PR_BEGIN_EXTERN_C + +#if defined(DEBUG) || defined(FORCE_NSPR_ORDERED_LOCKS) + +/* +** A locking mechanism, built on the existing PRLock definiion, +** is provided that will permit applications to define a Lock +** Hierarchy (or Lock Ordering) schema. An application designed +** using the Ordered Lock functions will terminate with a +** diagnostic message when a lock inversion condition is +** detected. +** +** The lock ordering detection is complile-time enabled only. in +** optimized builds of NSPR, the Ordered Lock functions map +** directly to PRLock functions, providing no lock order +** detection. +** +** The Ordered Lock Facility is compiled in when DEBUG is defined at +** compile time. Ordered Lock can be forced on in optimized builds by +** defining FORCE_NSPR_ORDERED_LOCK at compile time. Both the +** application using Ordered Lock and NSPR must be compiled with the +** facility enabled to achieve the desired results. +** +** Application designers should use the macro interfaces to the Ordered +** Lock facility to ensure that it is compiled out in optimized builds. +** +** Application designers are responsible for defining their own +** lock hierarchy. +** +** Ordered Lock is thread-safe and SMP safe. +** +** See Also: prlock.h +** +** /lth. 10-Jun-1998. +** +*/ + +/* +** Opaque type for ordered lock. +** ... Don't even think of looking in here. +** +*/ + +typedef void * PROrderedLock; + +/* ----------------------------------------------------------------------- +** FUNCTION: PR_CreateOrderedLock() -- Create an Ordered Lock +** +** DESCRIPTION: PR_CreateOrderedLock() creates an ordered lock. +** +** INPUTS: +** order: user defined order of this lock. +** name: name of the lock. For debugging purposes. +** +** OUTPUTS: returned +** +** RETURNS: PR_OrderedLock pointer +** +** RESTRICTIONS: +** +*/ +#define PR_CREATE_ORDERED_LOCK(order,name)\ + PR_CreateOrderedLock((order),(name)) + +PR_EXTERN(PROrderedLock *) + PR_CreateOrderedLock( + PRInt32 order, + const char *name +); + +/* ----------------------------------------------------------------------- +** FUNCTION: PR_DestroyOrderedLock() -- Destroy an Ordered Lock +** +** DESCRIPTION: PR_DestroyOrderedLock() destroys the ordered lock +** referenced by lock. +** +** INPUTS: lock: pointer to a PROrderedLock +** +** OUTPUTS: the lock is destroyed +** +** RETURNS: void +** +** RESTRICTIONS: +** +*/ +#define PR_DESTROY_ORDERED_LOCK(lock) PR_DestroyOrderedLock((lock)) + +PR_EXTERN(void) + PR_DestroyOrderedLock( + PROrderedLock *lock +); + +/* ----------------------------------------------------------------------- +** FUNCTION: PR_LockOrderedLock() -- Lock an ordered lock +** +** DESCRIPTION: PR_LockOrderedLock() locks the ordered lock +** referenced by lock. If the order of lock is less than or equal +** to the order of the highest lock held by the locking thread, +** the function asserts. +** +** INPUTS: lock: a pointer to a PROrderedLock +** +** OUTPUTS: The lock is held or the fucntion asserts. +** +** RETURNS: void +** +** RESTRICTIONS: +** +*/ +#define PR_LOCK_ORDERED_LOCK(lock) PR_LockOrderedLock((lock)) + +PR_EXTERN(void) + PR_LockOrderedLock( + PROrderedLock *lock +); + +/* ----------------------------------------------------------------------- +** FUNCTION: PR_UnlockOrderedLock() -- unlock and Ordered Lock +** +** DESCRIPTION: PR_UnlockOrderedLock() unlocks the lock referenced +** by lock. +** +** INPUTS: lock: a pointer to a PROrderedLock +** +** OUTPUTS: the lock is unlocked +** +** RETURNS: +** PR_SUCCESS +** PR_FAILURE +** +** RESTRICTIONS: +** +*/ +#define PR_UNLOCK_ORDERED_LOCK(lock) PR_UnlockOrderedLock((lock)) + +PR_EXTERN(PRStatus) + PR_UnlockOrderedLock( + PROrderedLock *lock +); + +#else /* !(defined(DEBUG) || defined(FORCE_NSPR_ORDERED_LOCKS)) */ +/* +** Map PROrderedLock and methods onto PRLock when ordered locking +** is not compiled in. +** +*/ +#include <prlock.h> + +typedef PRLock PROrderedLock; + +#define PR_CREATE_ORDERED_LOCK(order) PR_NewLock() +#define PR_DESTROY_ORDERED_LOCK(lock) PR_DestroyLock((lock)) +#define PR_LOCK_ORDERED_LOCK(lock) PR_Lock((lock)) +#define PR_UNLOCK_ORDERED_LOCK(lock) PR_Unlock((lock)) + +#endif /* !(defined(DEBUG) || defined(FORCE_NSPR_ORDERED_LOCKS)) */ + +PR_END_EXTERN_C + +#endif /* prolock_h___ */ + + + + + + + + + + + + + diff --git a/pr/include/prpdce.h b/pr/include/prpdce.h index 32a5cf58..b0bc7853 100644 --- a/pr/include/prpdce.h +++ b/pr/include/prpdce.h @@ -31,6 +31,8 @@ #include "prtypes.h" #include "prinrval.h" +PR_BEGIN_EXTERN_C + #define _PR_NAKED_CV_LOCK (PRLock*)0xdce1dce1 /* @@ -92,4 +94,6 @@ PR_EXTERN(PRStatus) PRP_NakedNotify(PRCondVar *cvar); */ PR_EXTERN(PRStatus) PRP_NakedBroadcast(PRCondVar *cvar); +PR_END_EXTERN_C + #endif /* PRPDCE_H */ diff --git a/pr/include/prtrace.h b/pr/include/prtrace.h new file mode 100644 index 00000000..807d4e45 --- /dev/null +++ b/pr/include/prtrace.h @@ -0,0 +1,635 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "NPL"); you may not use this file except in + * compliance with the NPL. You may obtain a copy of the NPL at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the NPL is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL + * for the specific language governing rights and limitations under the + * NPL. + * + * The Initial Developer of this code under the NPL is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All Rights + * Reserved. + */ + +#ifndef prtrace_h___ +#define prtrace_h___ +/* +** prtrace.h -- NSPR's Trace Facility. +** +** The Trace Facility provides a means to trace application +** program events within a process. When implementing an +** application program an engineer may insert a "Trace" function +** call, passing arguments to be traced. The "Trace" function +** combines the user trace data with identifying data and +** writes this data in time ordered sequence into a circular +** in-memory buffer; when the buffer fills, it wraps. +** +** Functions are provided to set and/or re-configure the size of +** the trace buffer, control what events are recorded in the +** buffer, enable and disable tracing based on specific user +** supplied data and other control functions. Methods are provided +** to record the trace entries in the in-memory trace buffer to +** a file. +** +** Tracing may cause a performance degredation to the application +** depending on the number and placement of calls to the tracing +** facility. When tracing is compiled in and all tracing is +** disabled via the runtime controls, the overhead should be +** minimal. ... Famous last words, eh? +** +** When DEBUG is defined at compile time, the Trace Facility is +** compiled as part of NSPR and any application using NSPR's +** header files will have tracing compiled in. When DEBUG is not +** defined, the Trace Facility is not compiled into NSPR nor +** exported in its header files. If the Trace Facility is +** desired in a non-debug build, then FORCE_NSPR_TRACE may be +** defined at compile time for both the optimized build of NSPR +** and the application. NSPR and any application using NSPR's +** Trace Facility must be compiled with the same level of trace +** conditioning or unresolved references may be realized at link +** time. +** +** For any of the Trace Facility methods that requires a trace +** handle as an input argument, the caller must ensure that the +** trace handle argument is valid. An invalid trace handle +** argument may cause unpredictable results. +** +** Trace Facility methods are thread-safe and SMP safe. +** +** Users of the Trace Facility should use the defined macros to +** invoke trace methods, not the function calls directly. e.g. +** PR_TRACE( h1,0,1,2, ...); not PR_Trace(h1,0,1,2, ...); +** +** Application designers should be aware of the effects of +** debug and optimized build differences when using result of the +** Trace Facility macros in expressions. +** +** See Also: prcountr.h +** +** /lth. 08-Jun-1998. +*/ + +#include "prtypes.h" +#include "prthread.h" +#include "prtime.h" + +PR_BEGIN_EXTERN_C + +/* +** Opaque type for the trace handle +** ... Don't even think about looking in here. +** +*/ +typedef void * PRTraceHandle; + +#if defined (DEBUG) || defined (FORCE_NSPR_TRACE) +/* +** PRTraceEntry -- A trace entry in the in-memory trace buffer +** looks like this. +** +*/ +typedef struct PRTraceEntry +{ + PRThread *thread; /* The thread creating the trace entry */ + PRTraceHandle handle; /* PRTraceHandle creating the trace entry */ + PRTime time; /* Value of PR_Now() at time of trace entry */ + PRUint32 userData[8]; /* user supplied trace data */ +} PRTraceEntry; + +/* +** PRTraceOption -- command operands to +** PR_[Set|Get]TraceOption(). See descriptive meanings there. +** +*/ +typedef enum PRTraceOption +{ + PRTraceBufSize, + PRTraceEnable, + PRTraceDisable, + PRTraceSuspend, + PRTraceResume, + PRTraceSuspendRecording, + PRTraceResumeRecording, + PRTraceLockHandles, + PRTraceUnLockHandles, + PRTraceStopRecording +} PRTraceOption; + +/* ----------------------------------------------------------------------- +** FUNCTION: PR_DEFINE_TRACE() -- Define a PRTraceHandle +** +** DESCRIPTION: PR_DEFINE_TRACE() is used to define a trace +** handle. +** +*/ +#define PR_DEFINE_TRACE(name) PRTraceHandle name + +/* ----------------------------------------------------------------------- +** FUNCTION: PR_INIT_TRACE_HANDLE() -- Set the value of a PRTraceHandle +** +** DESCRIPTION: +** PR_INIT_TRACE_HANDLE() sets the value of a PRTraceHandle +** to value. e.g. PR_INIT_TRACE_HANDLE( myHandle, NULL ); +** +*/ +#define PR_INIT_TRACE_HANDLE(handle,value)\ + (handle) = (PRCounterHandle)(value) + + +/* ----------------------------------------------------------------------- +** FUNCTION: PR_CreateTrace() -- Create a trace handle +** +** DESCRIPTION: +** PR_CreateTrace() creates a new trace handle. Tracing is +** enabled for this handle when it is created. The trace handle +** is intended for use in other Trace Facility calls. +** +** PR_CreateTrace() registers the QName, RName and description +** data so that this data can be retrieved later. +** +** INPUTS: +** qName: pointer to string. QName for this trace handle. +** +** rName: pointer to string. RName for this trace handle. +** +** description: pointer to string. Descriptive data about this +** trace handle. +** +** OUTPUTS: +** Creates the trace handle. +** Registers the QName and RName with the trace facility. +** +** RETURNS: +** PRTraceHandle +** +** RESTRICTIONS: +** qName is limited to 31 characters. +** rName is limited to 31 characters. +** description is limited to 255 characters. +** +*/ +#define PRTRACE_NAME_MAX 31 +#define PRTRACE_DESC_MAX 255 + +#define PR_CREATE_TRACE(handle,qName,rName,description)\ + (handle) = PR_CreateTrace((qName),(rName),(description)) + +PR_EXTERN(PRTraceHandle) + PR_CreateTrace( + const char *qName, /* QName for this trace handle */ + const char *rName, /* RName for this trace handle */ + const char *description /* description for this trace handle */ +); + + +/* ----------------------------------------------------------------------- +** FUNCTION: PR_DestroyTrace() -- Destroy a trace handle +** +** DESCRIPTION: +** PR_DestroyTrace() removes the referenced trace handle and +** associated QName, RName and description data from the Trace +** Facility. +** +** INPUTS: handle. A PRTraceHandle +** +** OUTPUTS: +** The trace handle is unregistered. +** The QName, RName and description are removed. +** +** RETURNS: void +** +** RESTRICTIONS: +** +*/ +#define PR_DESTROY_TRACE(handle)\ + PR_DestroyTrace((handle)) + +PR_EXTERN(void) + PR_DestroyTrace( + PRTraceHandle handle /* Handle to be destroyed */ +); + + +/* ----------------------------------------------------------------------- +** FUNCTION: PR_Trace() -- Make a trace entry in the in-memory trace +** +** DESCRIPTION: +** PR_Trace() makes an entry in the in-memory trace buffer for +** the referenced trace handle. The next logically available +** PRTraceEntry is used; when the next trace entry would overflow +** the trace table, the table wraps. +** +** PR_Trace() for a specific trace handle may be disabled by +** calling PR_SetTraceOption() specifying PRTraceDisable for the +** trace handle to be disabled. +** +** INPUTS: +** handle: PRTraceHandle. The trace handle for this trace. +** +** userData[0..7]: unsigned 32bit integers. user supplied data +** that is copied into the PRTraceEntry +** +** OUTPUTS: +** A PRTraceEntry is (conditionally) formatted in the in-memory +** trace buffer. +** +** RETURNS: void. +** +** RESTRICTIONS: +** +*/ +#define PR_TRACE(handle,ud0,ud1,ud2,ud3,ud4,ud5,ud6,ud7)\ + PR_Trace((handle),(ud0),(ud1),(ud2),(ud3),(ud4),(ud5),(ud6),(ud7)) + +PR_EXTERN(void) + PR_Trace( + PRTraceHandle handle, /* use this trace handle */ + PRUint32 userData0, /* User supplied data word 0 */ + PRUint32 userData1, /* User supplied data word 1 */ + PRUint32 userData2, /* User supplied data word 2 */ + PRUint32 userData3, /* User supplied data word 3 */ + PRUint32 userData4, /* User supplied data word 4 */ + PRUint32 userData5, /* User supplied data word 5 */ + PRUint32 userData6, /* User supplied data word 6 */ + PRUint32 userData7 /* User supplied data word 7 */ +); + +/* ----------------------------------------------------------------------- +** FUNCTION: PR_SetTraceOption() -- Control the Trace Facility +** +** DESCRIPTION: +** PR_SetTraceOption() controls the Trace Facility. Depending on +** command and value, attributes of the Trace Facility may be +** changed. +** +** INPUTS: +** command: An enumerated value in the set of PRTraceOption. +** value: pointer to the data to be set. Type of the data is +** dependent on command; for each value of command, the type +** and meaning of dereferenced value is shown. +** +** PRTraceBufSize: unsigned long: the size of the trace buffer, +** in bytes. +** +** PRTraceEnable: PRTraceHandle. The trace handle to be +** enabled. +** +** PRTraceDisable: PRTraceHandle. The trace handle to be +** disabled. +** +** PRTraceSuspend: void. value must be NULL. All tracing is +** suspended. +** +** PRTraceResume: void. value must be NULL. Tracing for all +** previously enabled, prior to a PRTraceSuspend, is resumed. +** +** PRTraceStopRecording: void. value must be NULL. If recording +** (see: ** PR_RecordTraceEntries()) is being done, +** PRTraceStopRecording causes PR_RecordTraceEntries() to return +** to its caller. If recording is not being done, this function +** has no effect. +** +** PRTraceSuspendRecording: void. Must be NULL. If recording is +** being done, PRTraceSuspendRecording causes further writes to +** the trace file to be suspended. Data in the in-memory +** trace buffer that would ordinarily be written to the +** trace file will not be written. Trace entries will continue +** to be entered in the in-memory buffer. If the Trace Facility +** recording is already in a suspended state, the call has no +** effect. +** +** PRTraceResumeRecording: void. value must be NULL. If +** recording for the Trace Facility has been previously been +** suspended, this causes recording to resume. Recording resumes +** with the next in-memory buffer segment that would be written +** if trace recording had not been suspended. If recording is +** not currently suspended, the call has no effect. +** +** PRTraceLockHandles: void. value must be NULL. Locks the +** trace handle lock. While the trace handle lock is held, +** calls to PR_CreateTrace() will block until the lock is +** released. +** +** PRTraceUnlockHandles: void. value must be NULL. Unlocks the +** trace handle lock. +** +** OUTPUTS: +** The operation of the Trace Facility may be changed. +** +** RETURNS: void +** +** RESTRICTIONS: +** +*/ +#define PR_SET_TRACE_OPTION(command,value)\ + PR_SetTraceOption((command),(value)) + +PR_EXTERN(void) + PR_SetTraceOption( + PRTraceOption command, /* One of the enumerated values */ + void *value /* command value or NULL */ +); + + +/* ----------------------------------------------------------------------- +** FUNCTION: PR_GetTraceOption() -- Retrieve settings from the Trace Facility +** +** DESCRIPTION: +** PR_GetTraceOption() retrieves the current setting of the +** Trace Facility control depending on command. +** +** +** PRTraceBufSize: unsigned long: the size of the trace buffer, +** in bytes. +** +** +** INPUTS: +** command: one of the enumerated values in PRTraceOptions +** valid for PR_GetTraceOption(). +** +** OUTPUTS: +** dependent on command. +** +** RETURNS: void +** +** RESTRICTIONS: +** +*/ +#define PR_GET_TRACE_OPTION(command,value)\ + PR_GetTraceOption((command),(value)) + +PR_EXTERN(void) + PR_GetTraceOption( + PRTraceOption command, /* One of the enumerated values */ + void *value /* command value or NULL */ +); + +/* ----------------------------------------------------------------------- +** FUNCTION: PR_GetTraceHandleFromName() -- Retrieve an existing +** handle by name. +** +** DESCRIPTION: +** PR_GetTraceHandleFromName() retreives an existing tracehandle +** using the name specified by qName and rName. +** +** INPUTS: +** qName: pointer to string. QName for this trace handle. +** +** rName: pointer to string. RName for this trace handle. +** +** +** OUTPUTS: returned. +** +** RETURNS: +** PRTraceHandle associated with qName and rName or NULL when +** there is no match. +** +** RESTRICTIONS: +** +*/ +#define PR_GET_TRACE_HANDLE_FROM_NAME(handle,qName,rName)\ + (handle) = PR_GetTraceHandleFromName((qName),(rName)) + +PR_EXTERN(PRTraceHandle) + PR_GetTraceHandleFromName( + const char *qName, /* QName search argument */ + const char *rName /* RName search argument */ +); + +/* ----------------------------------------------------------------------- +** FUNCTION: PR_GetTraceNameFromHandle() -- Retreive trace name +** by bandle. +** +** DESCRIPTION: +** PR_GetTraceNameFromHandle() retreives the existing qName, +** rName, and description for the referenced trace handle. +** +** INPUTS: handle: PRTraceHandle. +** +** OUTPUTS: pointers to the Trace Facility's copy of qName, +** rName and description. ... Don't mess with these values. +** They're mine. +** +** RETURNS: void +** +** RESTRICTIONS: +** +*/ +#define PR_GET_TRACE_NAME_FROM_HANDLE(handle,qName,rName,description)\ + PR_GetTraceNameFromHandle((handle),(qName),(rName),(description)) + +PR_EXTERN(void) + PR_GetTraceNameFromHandle( + PRTraceHandle handle, /* handle as search argument */ + const char **qName, /* pointer to associated QName */ + const char **rName, /* pointer to associated RName */ + const char **description /* pointer to associated description */ +); + +/* ----------------------------------------------------------------------- +** FUNCTION: PR_FindNextTraceQname() -- Retrieive a QName handle +** iterator. +** +** DESCRIPTION: +** PR_FindNextTraceQname() retreives the first or next trace +** QName handle, depending on the value of handle, from the trace +** database. The PRTraceHandle returned can be used as an +** iterator to traverse the QName handles in the Trace database. +** +** INPUTS: +** handle: When NULL, PR_FindNextQname() returns the first QName +** handle. When a handle is a valid PRTraceHandle previously +** retreived using PR_FindNextQname() the next QName handle is +** retreived. +** +** OUTPUTS: returned. +** +** RETURNS: +** PRTraceHandle or NULL when there are no trace handles. +** +** RESTRICTIONS: +** Iterating thru the trace handles via FindFirst/FindNext +** should be done under protection of the trace handle lock. +** See: PR_SetTraceOption( PRLockTraceHandles ). +** +*/ +#define PR_FIND_NEXT_TRACE_QNAME(next,handle)\ + (next) = PR_FindNextTraceQname((handle)) + +PR_EXTERN(PRTraceHandle) + PR_FindNextTraceQname( + PRTraceHandle handle +); + + +/* ----------------------------------------------------------------------- +** FUNCTION: PR_FindNextTraceRname() -- Retrieive an RName handle +** iterator. +** +** DESCRIPTION: +** PR_FindNextTraceRname() retreives the first or next trace +** RName handle, depending on the value of handle, from the trace +** database. The PRTraceHandle returned can be used as an +** iterator to traverse the RName handles in the Trace database. +** +** INPUTS: +** rhandle: When NULL, PR_FindNextRname() returns the first +** RName handle. When a handle is a valid PRTraceHandle +** previously retreived using PR_FindNextRname() the next RName +** handle is retreived. +** qhandle: A valid PRTraceHandle retruned from a previous call +** to PR_FIND_NEXT_TRACE_QNAME(). +** +** OUTPUTS: returned. +** +** RETURNS: +** PRTraceHandle or NULL when there are no trace handles. +** +** RESTRICTIONS: +** Iterating thru the trace handles via FindNext should be done +** under protection of the trace handle lock. See: ( +** PR_SetTraceOption( PRLockTraceHandles ). +** +*/ +#define PR_FIND_NEXT_TRACE_RNAME(next,rhandle,qhandle)\ + (next) = PR_FindNextTraceRname((rhandle),(qhandle)) + +PR_EXTERN(PRTraceHandle) + PR_FindNextTraceRname( + PRTraceHandle rhandle, + PRTraceHandle qhandle +); + +/* ----------------------------------------------------------------------- +** FUNCTION: PR_RecordTraceEntries() -- Write trace entries to external media +** +** DESCRIPTION: +** PR_RecordTraceEntries() causes entries in the in-memory trace +** buffer to be written to external media. +** +** When PR_RecordTraceEntries() is called from an application +** thread, the function appears to block until another thread +** calls PR_SetTraceOption() with the PRTraceStopRecording +** option. This suggests that PR_RecordTraceEntries() should be +** called from a user supplied thread whose only job is to +** record trace entries. +** +** The environment variable NSPR_TRACE_LOG controls the operation +** of this function. When NSPR_TRACE_LOG is not defined in the +** environment, no recording of trace entries occurs. When +** NSPR_TRACE_LOG is defined, the value of its definition must be +** the filename of the file to receive the trace entry buffer. +** +** PR_RecordTraceEntries() attempts to record the in-memory +** buffer to a file, subject to the setting of the environment +** variable NSPR_TRACE_LOG. It is possible because of system +** load, the thread priority of the recording thread, number of +** active trace records being written over time, and other +** variables that some trace records can be lost. ... In other +** words: don't bet the farm on getting everything. +** +** INPUTS: none +** +** OUTPUTS: none +** +** RETURNS: PR_STATUS +** PR_SUCCESS no errors were found. +** PR_FAILURE errors were found. +** +** RESTRICTIONS: +** Only one thread can call PR_RecordTraceEntries() within a +** process. +** +** On error, PR_RecordTraceEntries() may return prematurely. +** +*/ +#define PR_RECORD_TRACE_ENTRIES()\ + PR_RecordTraceEntries() + +PR_EXTERN(void) + PR_RecordTraceEntries( + void +); + +/* ----------------------------------------------------------------------- +** FUNCTION: PR_GetTraceEntries() -- Retreive trace entries from +** the Trace Facility +** +** DESCRIPTION: +** PR_GetTraceEntries() retreives trace entries from the Trace +** Facility. Up to count trace entries are copied from the Trace +** Facility into buffer. Only those trace entries that have not +** been copied via a previous call to PR_GetTraceEntries() are +** copied. The actual number copied is placed in the PRInt32 +** variable pointed to by found. +** +** If more than count trace entries have entered the Trace +** Facility since the last call to PR_GetTraceEntries() +** a lost data condition is returned. In this case, the most +** recent count trace entries are copied into buffer and found is +** set to count. +** +** INPUTS: +** count. The number of trace entries to be copied into buffer. +** +** +** OUTPUTS: +** buffer. An array of PRTraceEntries. The buffer is supplied +** by the caller. +** +** found: 32bit signed integer. The number of PRTraceEntries +** actually copied. found is always less than or equal to count. +** +** RETURNS: +** zero when there is no lost data. +** non-zero when some PRTraceEntries have been lost. +** +** RESTRICTIONS: +** This is a real performance pig. The copy out operation is bad +** enough, but depending on then frequency of calls to the +** function, serious performance impact to the operating +** application may be realized. ... YMMV. +** +*/ +#define PR_GET_TRACE_ENTRIES(buffer,count,found)\ + PR_GetTraceEntries((buffer),(count),(found)) + + +PR_EXTERN(PRIntn) + PR_GetTraceEntries( + PRTraceEntry *buffer, /* where to write output */ + PRInt32 count, /* number to get */ + PRInt32 *found /* number you got */ +); + +#else /* !(defined (DEBUG) || defined (FORCE_NSPR_TRACE)) */ +/* +** Define the Trace Facility macros as No-Ops for when the trace +** facility is to be compiled-out of the application. +** +*/ +#define PR_DEFINE_TRACE(name) PRTraceHandle name +#define PR_INIT_TRACE_HANDLE(handle,value) +#define PR_CREATE_TRACE(handle,qName,rName,description) +#define PR_DESTROY_TRACE(handle) +#define PR_TRACE(handle,ud0,ud1,ud2,ud3,ud4,ud5,ud6,ud7) +#define PR_SET_TRACE_OPTION(command,value) +#define PR_GET_TRACE_OPTION(command,value) +#define PR_GET_TRACE_HANDLE_FROM_NAME(handle,qName,rName) +#define PR_GET_TRACE_NAME_FROM_HANDLE(handle,qName,rName,description) +#define PR_FIND_NEXT_TRACE_QNAME(next,handle) +#define PR_FIND_NEXT_TRACE_RNAME(next,rhandle,qhandle) +#define PR_GET_TRACE_ENTRIES(buffer,count,found) +#define PR_RECORD_TRACE_ENTRIES() + +#endif /* !(defined (DEBUG) || defined (FORCE_NSPR_TRACE)) */ + +PR_END_EXTERN_C + +#endif /* prtrace_h___ */ + diff --git a/pr/include/prtypes.h b/pr/include/prtypes.h index 16112b13..8e10743c 100644 --- a/pr/include/prtypes.h +++ b/pr/include/prtypes.h @@ -120,10 +120,6 @@ #endif -#if !defined(NO_NSPR_10_SUPPORT) -#define PR_PUBLIC_API PR_IMPLEMENT -#endif - /*********************************************************************** ** MACROS: PR_BEGIN_MACRO ** PR_END_MACRO @@ -179,7 +175,21 @@ PR_BEGIN_EXTERN_C ************************************************************************/ #if PR_BYTES_PER_BYTE == 1 typedef unsigned char PRUint8; +/* +** Some cfront-based C++ compilers do not like 'signed char' and +** issue the warning message: +** warning: "signed" not implemented (ignored) +** For these compilers, we have to define PRInt8 as plain 'char'. +** Make sure that plain 'char' is indeed signed under these compilers. +*/ +#if (defined(HPUX) && defined(__cplusplus) \ + && !defined(__GNUC__) && __cplusplus < 199707L) \ + || (defined(SCO) && defined(__cplusplus) \ + && !defined(__GNUC__) && __cplusplus == 1L) +typedef char PRInt8; +#else typedef signed char PRInt8; +#endif #else #error No suitable type for PRInt8/PRUint8 #endif @@ -333,6 +343,8 @@ typedef enum { PR_FAILURE = -1, PR_SUCCESS = 0 } PRStatus; ** Fundamental NSPR macros, used nearly everywhere. */ +#define PR_PUBLIC_API PR_IMPLEMENT + /* ** Macro body brackets so that macros with compound statement definitions ** behave syntactically more like functions when called. diff --git a/pr/include/prvrsion.h b/pr/include/prvrsion.h new file mode 100755 index 00000000..a8a0bf3c --- /dev/null +++ b/pr/include/prvrsion.h @@ -0,0 +1,108 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "NPL"); you may not use this file except in + * compliance with the NPL. You may obtain a copy of the NPL at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the NPL is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL + * for the specific language governing rights and limitations under the + * NPL. + * + * The Initial Developer of this code under the NPL is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All Rights + * Reserved. + */ + + +/* author: jstewart */ + +#if defined(_PRVERSION_H) +#else +#define _PRVERSION_H + +#include "prtypes.h" + +PR_BEGIN_EXTERN_C + +/* All components participating in the PR version protocol must expose + * a structure and a function. The structure is defined below and named + * according to the naming conventions outlined further below. The function + * is called libVersionPoint and returns a pointer to this structure. + */ + +/* on NT, always pack the structure the same. */ +#ifdef _WIN32 +#pragma pack(push, 8) +#endif + +typedef struct { + /* + * The first field defines which version of this structure is in use. + * At this time, only version 2 is specified. If this value is not + * 2, you must read no further into the structure. + */ + PRInt32 version; + + /* for Version 2, this is the body format. */ + PRInt64 buildTime; /* 64 bits - usecs since midnight, 1/1/1970 */ + char * buildTimeString;/* a human readable version of the time */ + + PRUint8 vMajor; /* Major version of this component */ + PRUint8 vMinor; /* Minor version of this component */ + PRUint8 vPatch; /* Patch level of this component */ + + PRBool beta; /* true if this is a beta component */ + PRBool debug; /* true if this is a debug component */ + PRBool special; /* true if this component is a special build */ + + char * filename; /* The original filename */ + char * description; /* description of this component */ + char * security; /* level of security in this component */ + char * copyright; /* The copyright for this file */ + char * comment; /* free form field for misc usage */ + char * specialString; /* the special variant for this build */ +} PRVersionDescription; + +/* on NT, restore the previous packing */ +#ifdef _WIN32 +#pragma pack(pop) +#endif + +/* + * All components must define an entrypoint named libVersionPoint which + * is of type versionEntryPointType. + */ +PR_EXTERN(const PRVersionDescription *) libVersionPoint(void); + +typedef const PRVersionDescription *(*versionEntryPointType)(void); + +/* + * Where you declare your libVersionPoint, do it like this: + * PR_IMPLEMENT(const PRVersionDescription *) libVersionPoint(void) { + * fill it in... + * } + */ + +/* + * NAMING CONVENTION FOR struct + * + * all components should also expose a static PRVersionDescription + * The name of the struct should be calculated as follows: + * Take the value of filename. (If filename is not specified, calculate + * a short, unique string.) Convert all non-alphanumeric characters + * to '_'. To this, prepend "PRVersionDescription_". Thus for libfoo.so, + * the symbol name is "PRVersionDescription_libfoo_so". + * so the file should have + * PRVersionDescription PRVersionDescription_libfoo_so { fill it in }; + * on NT, this file should be declspec export. + */ + +PR_END_EXTERN_C + +#endif /* defined(_PRVERSION_H) */ + +/* prvrsion.h */ + diff --git a/pr/src/Makefile b/pr/src/Makefile index e479b0f8..e799af79 100644 --- a/pr/src/Makefile +++ b/pr/src/Makefile @@ -21,10 +21,10 @@ MOD_DEPTH = ../.. include $(MOD_DEPTH)/config/config.mk -ifdef USE_PTHREADS - DIRS = io linking malloc md memory misc pthreads threads -else - DIRS = io linking malloc md memory misc threads +DIRS = io linking malloc md memory misc threads + +ifeq ($(USE_PTHREADS), 1) + DIRS += pthreads endif # @@ -52,22 +52,22 @@ endif # SunOS ifeq ($(OS_ARCH), IRIX) ifeq ($(USE_PTHREADS), 1) -OS_LIBS += -lpthread +OS_LIBS = -lpthread endif endif ifeq ($(OS_ARCH),AIX) ifeq ($(CLASSIC_NSPR),1) ifeq ($(OS_RELEASE),4.1) -OS_LIBS += -lsvld -lc +OS_LIBS = -lsvld -lc else -OS_LIBS += -ldl -lc +OS_LIBS = -ldl -lc endif else ifeq ($(OS_RELEASE),4.1) -OS_LIBS += -lsvld -lC_r -lC -lpthreads -lc_r -lm /usr/lib/libc.a +OS_LIBS = -lpthreads -lsvld -lC_r -lC -lc_r -lm /usr/lib/libc.a else -OS_LIBS += -ldl -lC_r -lC -lpthreads -lc_r -lm /usr/lib/libc.a +OS_LIBS = -lpthreads -ldl -lC_r -lC -lc_r -lm /usr/lib/libc.a endif endif endif @@ -84,11 +84,11 @@ endif endif ifeq ($(OS_ARCH),OSF1) -ifneq ($(OS_RELEASE),V2.0) -OS_LIBS = -lc_r -endif ifeq ($(USE_PTHREADS), 1) -OS_LIBS += -lpthread -lrt +OS_LIBS = -lpthread -lrt +endif +ifneq ($(OS_RELEASE),V2.0) +OS_LIBS += -lc_r endif ifeq ($(USE_IPV6), 1) OS_LIBS += -lip6 @@ -104,16 +104,20 @@ endif endif ifeq ($(OS_ARCH),HP-UX) -ifeq ($(basename $(OS_RELEASE)),A.09) -OS_LIBS = -ldld -L/lib/pa1.1 -lm +ifeq ($(USE_PTHREADS), 1) +ifeq (,$(filter-out B.10.10 B.10.20,$(OS_RELEASE))) +OS_LIBS = -ldce else -OS_LIBS = -ldld -lm -lc +OS_LIBS = -lpthread endif -ifeq ($(USE_PTHREADS), 1) -OS_LIBS += -lpthread endif ifeq ($(PTHREADS_USER), 1) -OS_LIBS += -lpthread +OS_LIBS = -lpthread +endif +ifeq ($(basename $(OS_RELEASE)),A.09) +OS_LIBS += -ldld -L/lib/pa1.1 -lm +else +OS_LIBS += -ldld -lm -lc endif endif @@ -140,16 +144,20 @@ endif # OBJS = \ + $(OBJDIR)/prvrsion.$(OBJ_SUFFIX) \ + io/$(OBJDIR)/prfdcach.$(OBJ_SUFFIX) \ io/$(OBJDIR)/prmwait.$(OBJ_SUFFIX) \ io/$(OBJDIR)/prmapopt.$(OBJ_SUFFIX) \ io/$(OBJDIR)/priometh.$(OBJ_SUFFIX) \ io/$(OBJDIR)/prlayer.$(OBJ_SUFFIX) \ io/$(OBJDIR)/prlog.$(OBJ_SUFFIX) \ io/$(OBJDIR)/prmmap.$(OBJ_SUFFIX) \ + io/$(OBJDIR)/prpolevt.$(OBJ_SUFFIX) \ io/$(OBJDIR)/prprf.$(OBJ_SUFFIX) \ io/$(OBJDIR)/prscanf.$(OBJ_SUFFIX) \ io/$(OBJDIR)/prstdio.$(OBJ_SUFFIX) \ threads/$(OBJDIR)/prcmon.$(OBJ_SUFFIX) \ + threads/$(OBJDIR)/prtpd.$(OBJ_SUFFIX) \ linking/$(OBJDIR)/prlink.$(OBJ_SUFFIX) \ malloc/$(OBJDIR)/prmalloc.$(OBJ_SUFFIX) \ malloc/$(OBJDIR)/prmem.$(OBJ_SUFFIX) \ @@ -157,6 +165,7 @@ OBJS = \ memory/$(OBJDIR)/prseg.$(OBJ_SUFFIX) \ misc/$(OBJDIR)/pralarm.$(OBJ_SUFFIX) \ misc/$(OBJDIR)/pratom.$(OBJ_SUFFIX) \ + misc/$(OBJDIR)/prcountr.$(OBJ_SUFFIX) \ misc/$(OBJDIR)/prdtoa.$(OBJ_SUFFIX) \ misc/$(OBJDIR)/prenv.$(OBJ_SUFFIX) \ misc/$(OBJDIR)/prerror.$(OBJ_SUFFIX) \ @@ -165,8 +174,10 @@ OBJS = \ misc/$(OBJDIR)/prlog2.$(OBJ_SUFFIX) \ misc/$(OBJDIR)/prlong.$(OBJ_SUFFIX) \ misc/$(OBJDIR)/prnetdb.$(OBJ_SUFFIX) \ + misc/$(OBJDIR)/prolock.$(OBJ_SUFFIX) \ misc/$(OBJDIR)/prsystem.$(OBJ_SUFFIX) \ misc/$(OBJDIR)/prthinfo.$(OBJ_SUFFIX) \ + misc/$(OBJDIR)/prtrace.$(OBJ_SUFFIX) \ misc/$(OBJDIR)/prtime.$(OBJ_SUFFIX) ifdef USE_PTHREADS @@ -185,7 +196,6 @@ OBJS += \ threads/$(OBJDIR)/prdump.$(OBJ_SUFFIX) \ threads/$(OBJDIR)/prmon.$(OBJ_SUFFIX) \ threads/$(OBJDIR)/prsem.$(OBJ_SUFFIX) \ - threads/$(OBJDIR)/prtpd.$(OBJ_SUFFIX) \ threads/combined/$(OBJDIR)/prucpu.$(OBJ_SUFFIX) \ threads/combined/$(OBJDIR)/prucv.$(OBJ_SUFFIX) \ threads/combined/$(OBJDIR)/prulock.$(OBJ_SUFFIX) \ @@ -193,6 +203,7 @@ OBJS += \ threads/combined/$(OBJDIR)/pruthr.$(OBJ_SUFFIX) endif + ifeq ($(USE_IPV6), 1) OBJS += io/$(OBJDIR)/pripv6.$(OBJ_SUFFIX) endif @@ -202,6 +213,11 @@ ifneq (,$(filter-out WIN16 OS2,$(OS_TARGET))) DLLBASE=/BASE:0x30000000 RES=$(OBJDIR)/nspr.res RESNAME=nspr.rc +ifdef MOZ_DEBUG +ifdef GLOWCODE +EXTRA_LIBS += $(GLOWDIR)/glowcode.lib +endif +endif endif ifeq ($(OS_TARGET), WIN16) @@ -238,14 +254,8 @@ OBJS += md/windows/$(OBJDIR)/w95io.$(OBJ_SUFFIX) \ md/windows/$(OBJDIR)/ntinrval.$(OBJ_SUFFIX) \ md/windows/$(OBJDIR)/ntsem.$(OBJ_SUFFIX) \ md/windows/$(OBJDIR)/win32_errors.$(OBJ_SUFFIX) \ - md/windows/$(OBJDIR)/w32poll.$(OBJ_SUFFIX) -ifeq ($(MOZ_BITS),32) -ifdef MOZ_DEBUG -ifdef GLOWCODE - EXTRA_LIBS += $(GLOWDIR)/glowcode.lib -endif -endif -endif + md/windows/$(OBJDIR)/w32poll.$(OBJ_SUFFIX) \ + md/windows/$(OBJDIR)/w95dllmain.$(OBJ_SUFFIX) else ifeq ($(OS_TARGET), OS2) OBJS += md/os2/$(OBJDIR)/os2io.$(OBJ_SUFFIX) \ @@ -259,7 +269,8 @@ OBJS += md/os2/$(OBJDIR)/os2io.$(OBJ_SUFFIX) \ md/os2/$(OBJDIR)/os2_errors.$(OBJ_SUFFIX) \ md/os2/$(OBJDIR)/os2poll.$(OBJ_SUFFIX) else -OBJS += md/windows/$(OBJDIR)/ntio.$(OBJ_SUFFIX) \ +OBJS += md/windows/$(OBJDIR)/ntdllmn.$(OBJ_SUFFIX) \ + md/windows/$(OBJDIR)/ntio.$(OBJ_SUFFIX) \ md/windows/$(OBJDIR)/ntgc.$(OBJ_SUFFIX) \ md/windows/$(OBJDIR)/ntthread.$(OBJ_SUFFIX) \ md/windows/$(OBJDIR)/ntmisc.$(OBJ_SUFFIX) \ @@ -297,13 +308,53 @@ TARGETS += $(AIX_RTL_LIBC) endif # +# Version information generation (begin) +# +RM = rm +ECHO = echo +INCLUDES = -I$(DIST)/include +TINC = $(OBJDIR)/_pr_bld.h +PROD = libnspr$(MOD_VERSION).$(DLL_SUFFIX) +NOW = $(MOD_DEPTH)/config/$(OBJDIR)/now +SH_DATE = $(shell date) +SH_NOW = $(shell $(NOW)) + +ifeq ($(OS_ARCH), WINNT) + SUF = i64 + SH_QUOTE = +else + SUF = LL + SH_QUOTE = " +endif + +$(TINC): + @$(MAKE_OBJDIR) + @$(ECHO) $(SH_QUOTE)#define _BUILD_STRING \"$(SH_DATE)\"$(SH_QUOTE) > $(TINC) + @$(ECHO) $(SH_QUOTE)#define _BUILD_TIME $(SH_NOW)$(SUF)$(SH_QUOTE) >> $(TINC) + @$(ECHO) $(SH_QUOTE)#define _PRODUCTION \"$(PROD)\"$(SH_QUOTE) >> $(TINC) + + +$(OBJDIR)/prvrsion.$(OBJ_SUFFIX): $(TINC) +ifeq ($(OS_ARCH), WINNT) + $(CC) -Fo$@ -c $(CFLAGS) -I$(OBJDIR) prvrsion.c +else + $(CC) -o $@ -c $(CFLAGS) -I$(OBJDIR) prvrsion.c +endif +# +# Version information generation (end) +# + + +# # The Client build wants the shared libraries in $(DIST)/bin, # so we also install them there. # export:: $(TARGETS) $(INSTALL) -m 444 $(TARGETS) $(DIST)/lib +ifdef SHARED_LIBRARY $(INSTALL) -m 444 $(SHARED_LIBRARY) $(DIST)/bin +endif ifeq ($(MOZ_BITS),16) $(INSTALL) -m 444 $(TARGETS) $(MOZ_DIST)/lib $(INSTALL) -m 444 $(TARGETS) $(MOZ_DIST)/bin diff --git a/pr/src/io/Makefile b/pr/src/io/Makefile index 68dda471..a3574793 100644 --- a/pr/src/io/Makefile +++ b/pr/src/io/Makefile @@ -29,12 +29,14 @@ endif endif CSRCS = \ + prfdcach.c \ prmwait.c \ priometh.c \ prmapopt.c \ prlayer.c \ prlog.c \ prmmap.c \ + prpolevt.c \ prprf.c \ prscanf.c \ prstdio.c \ @@ -45,11 +47,7 @@ ifndef USE_PTHREADS prdir.c \ prfile.c \ prio.c \ - prlog.c \ - prmmap.c \ - prprf.c \ prsocket.c \ - prstdio.c \ $(NULL) endif diff --git a/pr/src/io/prfdcach.c b/pr/src/io/prfdcach.c new file mode 100644 index 00000000..9c7c8ea7 --- /dev/null +++ b/pr/src/io/prfdcach.c @@ -0,0 +1,287 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "NPL"); you may not use this file except in + * compliance with the NPL. You may obtain a copy of the NPL at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the NPL is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL + * for the specific language governing rights and limitations under the + * NPL. + * + * The Initial Developer of this code under the NPL is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All Rights + * Reserved. + */ + +#include "primpl.h" +#include "pratom.h" + +#include <string.h> + +/*****************************************************************************/ +/*****************************************************************************/ +/************************** File descriptor caching **************************/ +/*****************************************************************************/ +/*****************************************************************************/ + +/* +** This code is built into debuggable versions of NSPR to assist in +** finding misused file descriptors. Since file descritors (PRFileDesc) +** are identified by a pointer to their structure, they can be the +** target of dangling references. Furthermore, NSPR caches and tries +** to aggressively reuse file descriptors, leading to more ambiguity. +** The following code will allow a debugging client to set environment +** variables and control the number of file descriptors that will be +** preserved before they are recycled. The environment variables are +** NSPR_FD_CACHE_SIZE_LOW and NSPR_FD_CACHE_SIZE_HIGH. The former sets +** the number of descriptors NSPR will allocate before beginning to +** recycle. The latter is the maximum number permitted in the cache +** (exclusive of those in use) at a time. +*/ +typedef struct _PR_Fd_Cache +{ + PRLock *ml; + PRIntn count; + PRStack *stack; + PRFileDesc *head, *tail; + PRIntn limit_low, limit_high; +} _PR_Fd_Cache; + +static _PR_Fd_Cache _pr_fd_cache; +static PRFileDesc **stack2fd = &(((PRFileDesc*)NULL)->higher); + + +/* +** Get a FileDescriptor from the cache if one exists. If not allocate +** a new one from the heap. +*/ +PRFileDesc *_PR_Getfd() +{ + PRFileDesc *fd; + /* + ** $$$ + ** This may look a little wasteful. We'll see. Right now I want to + ** be able to toggle between caching and not at runtime to measure + ** the differences. If it isn't too annoying, I'll leave it in. + ** $$$$ + ** + ** The test is against _pr_fd_cache.limit_high. If that's zero, + ** we're not doing the extended cache but going for performance. + */ + if (0 == _pr_fd_cache.limit_high) + { + PRStackElem *pop; + PR_ASSERT(NULL != _pr_fd_cache.stack); + pop = PR_StackPop(_pr_fd_cache.stack); + if (NULL == pop) goto allocate; + fd = (PRFileDesc*)((PRPtrdiff)pop - (PRPtrdiff)stack2fd); + } + else + { + do + { + if (NULL == _pr_fd_cache.head) goto allocate; /* nothing there */ + if (_pr_fd_cache.count < _pr_fd_cache.limit_low) goto allocate; + + /* we "should" be able to extract an fd from the cache */ + PR_Lock(_pr_fd_cache.ml); /* need the lock to do this safely */ + fd = _pr_fd_cache.head; /* protected extraction */ + if (NULL == fd) /* unexpected, but not fatal */ + { + PR_ASSERT(0 == _pr_fd_cache.count); + PR_ASSERT(NULL == _pr_fd_cache.tail); + } + else + { + _pr_fd_cache.count -= 1; + _pr_fd_cache.head = fd->higher; + if (NULL == _pr_fd_cache.head) + { + PR_ASSERT(0 == _pr_fd_cache.count); + _pr_fd_cache.tail = NULL; + } + PR_ASSERT(_PR_FILEDESC_FREED == fd->secret->state); + } + PR_Unlock(_pr_fd_cache.ml); + + } while (NULL == fd); /* then go around and allocate a new one */ + } + +finished: + fd->dtor = NULL; + fd->lower = fd->higher = NULL; + fd->identity = PR_NSPR_IO_LAYER; + memset(fd->secret, 0, sizeof(PRFilePrivate)); + return fd; + +allocate: + fd = PR_NEW(PRFileDesc); + if (NULL != fd) + { + fd->secret = PR_NEW(PRFilePrivate); + if (NULL == fd->secret) PR_DELETE(fd); + } + if (NULL != fd) goto finished; + else return NULL; + +} /* _PR_Getfd */ + +/* +** Return a file descriptor to the cache unless there are too many in +** there already. If put in cache, clear the fields first. +*/ +void _PR_Putfd(PRFileDesc *fd) +{ + PR_ASSERT(PR_NSPR_IO_LAYER == fd->identity); + fd->methods = &_pr_faulty_methods; + fd->identity = PR_INVALID_IO_LAYER; + fd->secret->state = _PR_FILEDESC_FREED; + + if (0 == _pr_fd_cache.limit_high) + { + PR_StackPush(_pr_fd_cache.stack, (PRStackElem*)(&fd->higher)); + } + else + { + if (_pr_fd_cache.count > _pr_fd_cache.limit_high) + { + PR_Free(fd->secret); + PR_Free(fd); + } + else + { + PR_Lock(_pr_fd_cache.ml); + if (NULL == _pr_fd_cache.tail) + { + PR_ASSERT(0 == _pr_fd_cache.count); + PR_ASSERT(NULL == _pr_fd_cache.head); + _pr_fd_cache.head = _pr_fd_cache.tail = fd; + } + else + { + PR_ASSERT(NULL == _pr_fd_cache.tail->higher); + _pr_fd_cache.tail->higher = fd; + _pr_fd_cache.tail = fd; /* new value */ + } + fd->higher = NULL; /* always so */ + _pr_fd_cache.count += 1; /* count the new entry */ + PR_Unlock(_pr_fd_cache.ml); + } + } +} /* _PR_Putfd */ + +PR_IMPLEMENT(PRStatus) PR_SetFDCacheSize(PRIntn low, PRIntn high) +{ + /* + ** This can be called at any time, may adjust the cache sizes, + ** turn the caches off, or turn them on. It is not dependent + ** on the compilation setting of DEBUG. + */ + if (low > high) low = high; /* sanity check the params */ + + PR_Lock(_pr_fd_cache.ml); + if (0 == high) /* shutting down or staying down */ + { + if (0 != _pr_fd_cache.limit_high) /* shutting down */ + { + _pr_fd_cache.limit_high = 0; /* stop use */ + /* + ** Hold the lock throughout - nobody's going to want it + ** other than another caller to this routine. Just don't + ** let that happen. + ** + ** Put all the cached fds onto the new cache. + */ + while (NULL != _pr_fd_cache.head) + { + PRFileDesc *fd = _pr_fd_cache.head; + _pr_fd_cache.head = fd->higher; + fd->identity = PR_NSPR_IO_LAYER; + _PR_Putfd(fd); + } + _pr_fd_cache.limit_low = 0; + _pr_fd_cache.tail = NULL; + _pr_fd_cache.count = 0; + } + } + else /* starting up or just adjusting parameters */ + { + PRBool was_using_cache = (0 != _pr_fd_cache.limit_high); + _pr_fd_cache.limit_low = low; + _pr_fd_cache.limit_high = high; + if (was_using_cache) /* was using stack - feed into cache */ + { + PRStackElem *pop; + while (NULL != (pop = PR_StackPop(_pr_fd_cache.stack))) + { + PRFileDesc *fd = (PRFileDesc*) + ((PRPtrdiff)pop - (PRPtrdiff)stack2fd); + fd->identity = PR_NSPR_IO_LAYER; + _PR_Putfd(fd); + } + } + } + PR_Unlock(_pr_fd_cache.ml); + return PR_SUCCESS; +} /* PR_SetFDCacheSize */ + +void _PR_InitFdCache() +{ + /* + ** The fd caching is enabled by default for DEBUG builds, + ** disabled by default for OPT builds. That default can + ** be overridden at runtime using environment variables + ** or a super-wiz-bang API. + */ + const char *low = PR_GetEnv("NSPR_FD_CACHE_SIZE_LOW"); + const char *high = PR_GetEnv("NSPR_FD_CACHE_SIZE_HIGH"); + + _pr_fd_cache.limit_low = _pr_fd_cache.limit_high = 0; + if (NULL != low) _pr_fd_cache.limit_low = atoi(low); + if (NULL != high) _pr_fd_cache.limit_high = atoi(high); + + /* + **_low is allowed to be zero, _high is not. + ** IF _high is zero, we're not doing the caching. + */ + +#if defined(DEBUG) + if (0 == _pr_fd_cache.limit_high) + _pr_fd_cache.limit_high = FD_SETSIZE; +#endif /* defined(DEBUG) */ + + if (_pr_fd_cache.limit_high < _pr_fd_cache.limit_low) + _pr_fd_cache.limit_high = _pr_fd_cache.limit_low; + + _pr_fd_cache.ml = PR_NewLock(); + PR_ASSERT(NULL != _pr_fd_cache.ml); + _pr_fd_cache.stack = PR_CreateStack("FD"); + PR_ASSERT(NULL != _pr_fd_cache.stack); + +} /* _PR_InitFdCache */ + +void _PR_CleanupFdCache(void) +{ + PRFileDesc *fd, *next; + PRStackElem *pop; + + for (fd = _pr_fd_cache.head; fd != NULL; fd = next) + { + next = fd->higher; + PR_DELETE(fd->secret); + PR_DELETE(fd); + } + PR_DestroyLock(_pr_fd_cache.ml); + while ((pop = PR_StackPop(_pr_fd_cache.stack)) != NULL) + { + fd = (PRFileDesc*)((PRPtrdiff)pop - (PRPtrdiff)stack2fd); + PR_DELETE(fd->secret); + PR_DELETE(fd); + } + PR_DestroyStack(_pr_fd_cache.stack); +} /* _PR_CleanupFdCache */ + +/* prfdcach.c */ diff --git a/pr/src/io/prfile.c b/pr/src/io/prfile.c index 95210eae..bb9730f1 100644 --- a/pr/src/io/prfile.c +++ b/pr/src/io/prfile.c @@ -182,22 +182,21 @@ static PRStatus PR_CALLBACK FileSync(PRFileDesc *fd) static PRStatus PR_CALLBACK FileClose(PRFileDesc *fd) { - PRInt32 rv; - - if (!fd || fd->secret->state != _PR_FILEDESC_OPEN) { + if (!fd || !fd->secret + || (fd->secret->state != _PR_FILEDESC_OPEN + && fd->secret->state != _PR_FILEDESC_CLOSED)) { PR_SetError(PR_BAD_DESCRIPTOR_ERROR, 0); return PR_FAILURE; } - fd->secret->state = _PR_FILEDESC_CLOSED; - - rv = _PR_MD_CLOSE_FILE(fd->secret->md.osfd); - PR_FreeFileDesc(fd); - if (rv < 0) { - return PR_FAILURE; - } else { - return PR_SUCCESS; + if (fd->secret->state == _PR_FILEDESC_OPEN) { + if (_PR_MD_CLOSE_FILE(fd->secret->md.osfd) < 0) { + return PR_FAILURE; + } + fd->secret->state = _PR_FILEDESC_CLOSED; } + PR_FreeFileDesc(fd); + return PR_SUCCESS; } static PRInt16 PR_CALLBACK FilePoll( @@ -207,7 +206,7 @@ static PRInt16 PR_CALLBACK FilePoll( return in_flags; } /* FilePoll */ -PRIOMethods _pr_fileMethods = { +static PRIOMethods _pr_fileMethods = { PR_DESC_FILE, FileClose, FileRead, @@ -357,6 +356,7 @@ PR_IMPLEMENT(PRStatus) PR_GetFileInfo64(const char *fn, PRFileInfo64 *info) { PRInt32 rv; + if (!_pr_initialized) _PR_ImplicitInitialization(); rv = _PR_MD_GETFILEINFO64(fn, info); if (rv < 0) { return PR_FAILURE; diff --git a/pr/src/io/prio.c b/pr/src/io/prio.c index fc8f005f..97987b92 100644 --- a/pr/src/io/prio.c +++ b/pr/src/io/prio.c @@ -25,15 +25,12 @@ PRLock *_pr_flock_lock; -PRFileDesc *_pr_filedesc_freelist; -PRLock *_pr_filedesc_freelist_lock; - void _PR_InitIO(void) { const PRIOMethods *methods = PR_GetFileMethods(); - _pr_filedesc_freelist = NULL; - _pr_filedesc_freelist_lock = PR_NewLock(); + _PR_InitFdCache(); + _pr_flock_lock = PR_NewLock(); #ifdef WIN32 @@ -87,26 +84,7 @@ PR_IMPLEMENT(PRFileDesc*) PR_AllocFileDesc( */ PR_ASSERT(osfd < FD_SETSIZE); #endif - if (_pr_filedesc_freelist) { - PR_Lock(_pr_filedesc_freelist_lock); - if (_pr_filedesc_freelist) { - PRFilePrivate *secretSave; - fd = _pr_filedesc_freelist; - _pr_filedesc_freelist = _pr_filedesc_freelist->secret->next; - PR_Unlock(_pr_filedesc_freelist_lock); - secretSave = fd->secret; - memset(fd, 0, sizeof(PRFileDesc)); - memset(secretSave, 0, sizeof(PRFilePrivate)); - fd->secret = secretSave; - } else { - PR_Unlock(_pr_filedesc_freelist_lock); - fd = PR_NEWZAP(PRFileDesc); - fd->secret = PR_NEWZAP(PRFilePrivate); - } - } else { - fd = PR_NEWZAP(PRFileDesc); - fd->secret = PR_NEWZAP(PRFilePrivate); - } + fd = _PR_Getfd(); if (fd) { /* Initialize the members of PRFileDesc and PRFilePrivate */ fd->methods = methods; @@ -122,64 +100,13 @@ PR_IMPLEMENT(PRFileDesc*) PR_AllocFileDesc( PR_IMPLEMENT(void) PR_FreeFileDesc(PRFileDesc *fd) { PR_ASSERT(fd); - PR_ASSERT(fd->secret->state == _PR_FILEDESC_CLOSED); - - fd->secret->state = _PR_FILEDESC_FREED; - - PR_Lock(_pr_filedesc_freelist_lock); - - /* Add to head of list- this is a LIFO structure to avoid constantly - * using different structs - */ - fd->secret->next = _pr_filedesc_freelist; - _pr_filedesc_freelist = fd; - - PR_Unlock(_pr_filedesc_freelist_lock); + _PR_Putfd(fd); } -#ifdef XP_UNIX -#include <fcntl.h> /* to pick up F_GETFL */ -#endif - /* ** Wait for some i/o to finish on one or more more poll descriptors. */ -PR_IMPLEMENT(PRInt32) PR_Poll(PRPollDesc *pds, PRIntn npds, - PRIntervalTime timeout) +PR_IMPLEMENT(PRInt32) PR_Poll(PRPollDesc *pds, PRIntn npds, PRIntervalTime timeout) { - PRPollDesc *pd, *epd; - PRInt32 ready; - PRThread *me = _PR_MD_CURRENT_THREAD(); - - if (_PR_PENDING_INTERRUPT(me)) { - me->flags &= ~_PR_INTERRUPT; - PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); - return -1; - } - /* - ** Before we do the poll operation, check each descriptor and see if - ** it needs special poll handling. If it does, use the method poll - ** proc to check for data before blocking. - */ - pd = pds; - ready = 0; - for (pd = pds, epd = pd + npds; pd < epd; pd++) { - PRFileDesc *fd = pd->fd; - PRInt16 in_flags = pd->in_flags; - if (NULL != fd) - { - if (in_flags && fd->methods->poll) { - PRInt16 out_flags; - in_flags = (*fd->methods->poll)(fd, in_flags, &out_flags); - if (0 != (in_flags & out_flags)) { - pd->out_flags = out_flags; /* ready already */ - ready++; - } - } - } - } - if (ready != 0) { - return ready; /* don't need to block */ - } return(_PR_MD_PR_POLL(pds, npds, timeout)); } diff --git a/pr/src/io/priometh.c b/pr/src/io/priometh.c index a65b5c53..e9e4847c 100644 --- a/pr/src/io/priometh.c +++ b/pr/src/io/priometh.c @@ -18,19 +18,61 @@ #include "primpl.h" -/* - * An invalid method that returns an integer - */ +/*****************************************************************************/ +/************************** Invalid I/O method object ************************/ +/*****************************************************************************/ +PRIOMethods _pr_faulty_methods = { + (PRDescType)0, + (PRCloseFN)_PR_InvalidStatus, + (PRReadFN)_PR_InvalidInt, + (PRWriteFN)_PR_InvalidInt, + (PRAvailableFN)_PR_InvalidInt, + (PRAvailable64FN)_PR_InvalidInt64, + (PRFsyncFN)_PR_InvalidStatus, + (PRSeekFN)_PR_InvalidInt, + (PRSeek64FN)_PR_InvalidInt64, + (PRFileInfoFN)_PR_InvalidStatus, + (PRFileInfo64FN)_PR_InvalidStatus, + (PRWritevFN)_PR_InvalidInt, + (PRConnectFN)_PR_InvalidStatus, + (PRAcceptFN)_PR_InvalidDesc, + (PRBindFN)_PR_InvalidStatus, + (PRListenFN)_PR_InvalidStatus, + (PRShutdownFN)_PR_InvalidStatus, + (PRRecvFN)_PR_InvalidInt, + (PRSendFN)_PR_InvalidInt, + (PRRecvfromFN)_PR_InvalidInt, + (PRSendtoFN)_PR_InvalidInt, + (PRPollFN)_PR_InvalidInt16, + (PRAcceptreadFN)_PR_InvalidInt, + (PRTransmitfileFN)_PR_InvalidInt, + (PRGetsocknameFN)_PR_InvalidStatus, + (PRGetpeernameFN)_PR_InvalidStatus, + (PRGetsockoptFN)_PR_InvalidStatus, + (PRSetsockoptFN)_PR_InvalidStatus, + (PRGetsocketoptionFN)_PR_InvalidStatus, + (PRSetsocketoptionFN)_PR_InvalidStatus +}; PRIntn _PR_InvalidInt() { + PR_ASSERT(!"I/O method is invalid"); + PR_SetError(PR_INVALID_METHOD_ERROR, 0); + return -1; +} /* _PR_InvalidInt */ + +PRInt16 _PR_InvalidInt16() +{ + PR_ASSERT(!"I/O method is invalid"); PR_SetError(PR_INVALID_METHOD_ERROR, 0); return -1; } /* _PR_InvalidInt */ PRInt64 _PR_InvalidInt64() { - PRInt64 rv = LL_INIT( 0xffffffff, 0xffffffff ); + PRInt64 rv; + LL_I2L(rv, -1); + PR_ASSERT(!"I/O method is invalid"); PR_SetError(PR_INVALID_METHOD_ERROR, 0); return rv; } /* _PR_InvalidInt */ @@ -41,6 +83,7 @@ PRInt64 _PR_InvalidInt64() PRStatus _PR_InvalidStatus() { + PR_ASSERT(!"I/O method is invalid"); PR_SetError(PR_INVALID_METHOD_ERROR, 0); return PR_FAILURE; } /* _PR_InvalidDesc */ @@ -51,6 +94,7 @@ PRStatus _PR_InvalidStatus() PRFileDesc *_PR_InvalidDesc() { + PR_ASSERT(!"I/O method is invalid"); PR_SetError(PR_INVALID_METHOD_ERROR, 0); return NULL; } /* _PR_InvalidDesc */ diff --git a/pr/src/io/prlayer.c b/pr/src/io/prlayer.c index 1ca15962..f6e1828f 100644 --- a/pr/src/io/prlayer.c +++ b/pr/src/io/prlayer.c @@ -50,6 +50,7 @@ static PRStatus PR_CALLBACK pl_TopClose (PRFileDesc *fd) PR_ASSERT(fd->methods->file_type == PR_DESC_LAYERED); status = (fd->lower->methods->close)(fd->lower); + fd->lower = fd->higher = NULL; fd->dtor(fd); return status; diff --git a/pr/src/io/prlog.c b/pr/src/io/prlog.c index 98c7e639..723cb699 100644 --- a/pr/src/io/prlog.c +++ b/pr/src/io/prlog.c @@ -1,4 +1,4 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* * The contents of this file are subject to the Netscape Public License * Version 1.0 (the "NPL"); you may not use this file except in @@ -68,6 +68,14 @@ static PRLock *_pr_logLock; #define _PR_USE_STDIO_FOR_LOGGING #endif +/* +** Coerce Win32 log output to use OutputDebugString() when +** NSPR_LOG_FILE is set to "WinDebug". +*/ +#if defined(XP_PC) +#define WIN32_DEBUG_FILE (FILE*)-2 +#endif + /* Macros used to reduce #ifdef pollution */ #if defined(_PR_USE_STDIO_FOR_LOGGING) @@ -279,7 +287,7 @@ static void _PR_SetLogModuleLevel( PRLogModuleInfo *lm ) lm->level = (PRLogModuleLevel)level; else if (strcasecmp(module, lm->name) == 0) { - lm->level = level; + lm->level = (PRLogModuleLevel)level; break; } lm = lm->next; @@ -310,33 +318,19 @@ PR_IMPLEMENT(PRLogModuleInfo*) PR_NewLogModule(const char *name) return lm; } -PR_IMPLEMENT(void) PR_DestroyLogModule(PRLogModuleInfo* lm) -{ - PR_LogFlush(); - - /* unlink this log module from the list */ - if (lm == logModules) { - logModules = logModules->next; - } - else { - PRLogModuleInfo* chain = logModules; - while (chain && chain->next != lm) - chain = chain->next; - PR_ASSERT(chain && chain->next); - chain->next = chain->next->next; - } - - /* and free it */ - free((void*)lm->name); - PR_Free(lm); -} - PR_IMPLEMENT(PRBool) PR_SetLogFile(const char *file) { #ifdef PR_LOGGING #ifdef _PR_USE_STDIO_FOR_LOGGING FILE *newLogFile; +#ifdef XP_PC + if ( strcmp( file, "WinDebug") == 0) + { + logFile = WIN32_DEBUG_FILE; + return(PR_TRUE); + } +#endif newLogFile = fopen(file, "w"); if (newLogFile) { /* We do buffering ourselves. */ @@ -427,7 +421,14 @@ PR_IMPLEMENT(void) PR_LogPrint(const char *fmt, ...) _PR_LOCK_LOG(); if (logBuf == 0) { +#ifdef XP_PC + if ( logFile == WIN32_DEBUG_FILE) + OutputDebugString( line ); + else + _PUT_LOG(logFile, line, nb); +#else _PUT_LOG(logFile, line, nb); +#endif } else { if (logp + nb > logEndp) { _PUT_LOG(logFile, logBuf, logp - logBuf); diff --git a/pr/src/io/prmwait.c b/pr/src/io/prmwait.c index c29628ea..5f6e9a72 100644 --- a/pr/src/io/prmwait.c +++ b/pr/src/io/prmwait.c @@ -16,48 +16,216 @@ * Reserved. */ -#include "prlog.h" -#include "prmem.h" #include "primpl.h" -#include "prmwait.h" -#include "prerror.h" #include "pprmwait.h" +#define _MW_REHASH_MAX 11 + static PRLock *mw_lock = NULL; static _PRGlobalState *mw_state = NULL; static PRIntervalTime max_polling_interval; -/******************************************************************/ -/******************************************************************/ -/************************ The private portion *********************/ -/******************************************************************/ -/******************************************************************/ -static PRStatus MW_Init(void) +#ifdef WINNT + +typedef struct TimerEvent { + PRIntervalTime absolute; + void (*func)(void *); + void *arg; + LONG ref_count; + PRCList links; +} TimerEvent; + +#define TIMER_EVENT_PTR(_qp) \ + ((TimerEvent *) ((char *) (_qp) - offsetof(TimerEvent, links))) + +struct { + PRLock *ml; + PRCondVar *new_timer; + PRCondVar *cancel_timer; + PRThread *manager_thread; + PRCList timer_queue; +} tm_vars; + +static PRStatus TimerInit(void); +static void TimerManager(void *arg); +static TimerEvent *CreateTimer(PRIntervalTime timeout, + void (*func)(void *), void *arg); +static PRBool CancelTimer(TimerEvent *timer); + +static void TimerManager(void *arg) { - if (NULL != mw_lock) return PR_SUCCESS; - if (NULL != (mw_lock = PR_NewLock())) + PRIntervalTime now; + PRIntervalTime timeout; + PRCList *head; + TimerEvent *timer; + + PR_Lock(tm_vars.ml); + while (1) { - _PRGlobalState *state = PR_NEWZAP(_PRGlobalState); - if (state == NULL) goto failed; + if (PR_CLIST_IS_EMPTY(&tm_vars.timer_queue)) + { + PR_WaitCondVar(tm_vars.new_timer, PR_INTERVAL_NO_TIMEOUT); + } + else + { + now = PR_IntervalNow(); + head = PR_LIST_HEAD(&tm_vars.timer_queue); + timer = TIMER_EVENT_PTR(head); + if ((PRInt32) (now - timer->absolute) >= 0) + { + PR_REMOVE_LINK(head); + /* + * make its prev and next point to itself so that + * it's obvious that it's not on the timer_queue. + */ + PR_INIT_CLIST(head); + PR_ASSERT(2 == timer->ref_count); + PR_Unlock(tm_vars.ml); + timer->func(timer->arg); + PR_Lock(tm_vars.ml); + timer->ref_count -= 1; + if (0 == timer->ref_count) + { + PR_NotifyAllCondVar(tm_vars.cancel_timer); + } + } + else + { + timeout = (PRIntervalTime)(timer->absolute - now); + PR_WaitCondVar(tm_vars.new_timer, timeout); + } + } + } + PR_Unlock(tm_vars.ml); +} - PR_INIT_CLIST(&state->group_list); +static TimerEvent *CreateTimer( + PRIntervalTime timeout, + void (*func)(void *), + void *arg) +{ + TimerEvent *timer; + PRCList *links, *tail; + TimerEvent *elem; - PR_Lock(mw_lock); - if (NULL == mw_state) /* is it still NULL? */ + timer = PR_NEW(TimerEvent); + if (NULL == timer) + { + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + return timer; + } + timer->absolute = PR_IntervalNow() + timeout; + timer->func = func; + timer->arg = arg; + timer->ref_count = 2; + PR_Lock(tm_vars.ml); + tail = links = PR_LIST_TAIL(&tm_vars.timer_queue); + while (links->prev != tail) + { + elem = TIMER_EVENT_PTR(links); + if ((PRInt32)(timer->absolute - elem->absolute) >= 0) { - mw_state = state; /* if yes, set our value */ - state = NULL; /* and indicate we've done the job */ - max_polling_interval = PR_MillisecondsToInterval(MAX_POLLING_INTERVAL); + break; } - PR_Unlock(mw_lock); - if (NULL != state) PR_DELETE(state); - return PR_SUCCESS; + links = links->prev; } + PR_INSERT_AFTER(&timer->links, links); + PR_NotifyCondVar(tm_vars.new_timer); + PR_Unlock(tm_vars.ml); + return timer; +} + +static PRBool CancelTimer(TimerEvent *timer) +{ + PRBool canceled = PR_FALSE; + + PR_Lock(tm_vars.ml); + timer->ref_count -= 1; + if (timer->links.prev == &timer->links) + { + while (timer->ref_count == 1) + { + PR_WaitCondVar(tm_vars.cancel_timer, PR_INTERVAL_NO_TIMEOUT); + } + } + else + { + PR_REMOVE_LINK(&timer->links); + canceled = PR_TRUE; + } + PR_Unlock(tm_vars.ml); + PR_DELETE(timer); + return canceled; +} + +static PRStatus TimerInit(void) +{ + tm_vars.ml = PR_NewLock(); + if (NULL == tm_vars.ml) + { + goto failed; + } + tm_vars.new_timer = PR_NewCondVar(tm_vars.ml); + if (NULL == tm_vars.new_timer) + { + goto failed; + } + tm_vars.cancel_timer = PR_NewCondVar(tm_vars.ml); + if (NULL == tm_vars.cancel_timer) + { + goto failed; + } + tm_vars.manager_thread = PR_CreateThread( + PR_SYSTEM_THREAD, TimerManager, NULL, PR_PRIORITY_NORMAL, + PR_LOCAL_THREAD, PR_UNJOINABLE_THREAD, 0); + if (NULL == tm_vars.manager_thread) + { + goto failed; + } + PR_INIT_CLIST(&tm_vars.timer_queue); + return PR_SUCCESS; failed: + if (NULL != tm_vars.cancel_timer) + { + PR_DestroyCondVar(tm_vars.cancel_timer); + } + if (NULL != tm_vars.new_timer) + { + PR_DestroyCondVar(tm_vars.new_timer); + } + if (NULL != tm_vars.ml) + { + PR_DestroyLock(tm_vars.ml); + } return PR_FAILURE; -} /* MW_Init */ +} + +#endif /* WINNT */ + +/******************************************************************/ +/******************************************************************/ +/************************ The private portion *********************/ +/******************************************************************/ +/******************************************************************/ +void _PR_InitMW(void) +{ +#ifdef WINNT + /* + * We use NT 4's InterlockedCompareExchange() to operate + * on PRMWStatus variables. + */ + PR_ASSERT(sizeof(PVOID) == sizeof(PRMWStatus)); + TimerInit(); +#endif + mw_lock = PR_NewLock(); + PR_ASSERT(NULL != mw_lock); + mw_state = PR_NEWZAP(_PRGlobalState); + PR_ASSERT(NULL != mw_state); + PR_INIT_CLIST(&mw_state->group_list); + max_polling_interval = PR_MillisecondsToInterval(MAX_POLLING_INTERVAL); +} /* _PR_InitMW */ static PRWaitGroup *MW_Init2(void) { @@ -92,15 +260,15 @@ static _PR_HashStory MW_AddHashInternal(PRRecvWait *desc, _PRWaiterHash *hash) ** will have at least that many zeros in the low order bits. ** This may not be a good assuption. ** - ** We try to put the entry in by rehashing three times. After + ** We try to put the entry in by rehashing _MW_REHASH_MAX times. After ** that we declare defeat and force the table to be reconstructed. ** Since some fds might be added more than once, won't that cause ** collisions even in an empty table? */ - PRIntn rehash = 11; + PRIntn rehash = _MW_REHASH_MAX; PRRecvWait **waiter; PRUintn hidx = _MW_HASH(desc->fd, hash->length); - do + while (rehash-- > 0) { waiter = &hash->recv_wait; if (NULL == waiter[hidx]) @@ -127,7 +295,7 @@ static _PR_HashStory MW_AddHashInternal(PRRecvWait *desc, _PRWaiterHash *hash) hidx, hash->count, hash->length, waiter[hidx], waiter[hidx]->fd); #endif hidx = _MW_REHASH(desc->fd, hidx, hash->length); - } while (--rehash > 0); + } return _prmw_rehash; } /* MW_AddHashInternal */ @@ -161,6 +329,11 @@ static _PR_HashStory MW_ExpandHashInternal(PRWaitGroup *group) /* allocate the new hash table and fill it in with the old */ newHash = (_PRWaiterHash*)PR_CALLOC( sizeof(_PRWaiterHash) + (length * sizeof(PRRecvWait*))); + if (NULL == newHash) + { + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + return _prmw_error; + } newHash->length = length; for (desc = &oldHash->recv_wait; newHash->count < oldHash->count; ++desc) @@ -177,9 +350,11 @@ static _PR_HashStory MW_ExpandHashInternal(PRWaitGroup *group) } PR_DELETE(group->waiter); group->waiter = newHash; + group->p_timestamp += 1; return _prmw_success; } /* MW_ExpandHashInternal */ +#ifndef WINNT static void _MW_DoneInternal( PRWaitGroup *group, PRRecvWait **waiter, PRMWStatus outcome) { @@ -200,6 +375,7 @@ static void _MW_DoneInternal( group->waiter->count -= 1; *waiter = NULL; } /* _MW_DoneInternal */ +#endif /* WINNT */ static PRRecvWait **_MW_LookupInternal(PRWaitGroup *group, PRFileDesc *fd) { @@ -208,7 +384,7 @@ static PRRecvWait **_MW_LookupInternal(PRWaitGroup *group, PRFileDesc *fd) ** Only search the wait group specified. */ PRRecvWait **desc; - PRIntn rehash = 11; + PRIntn rehash = _MW_REHASH_MAX; _PRWaiterHash *hash = group->waiter; PRUintn hidx = _MW_HASH(fd, hash->length); @@ -221,6 +397,7 @@ static PRRecvWait **_MW_LookupInternal(PRWaitGroup *group, PRFileDesc *fd) return NULL; } /* _MW_LookupInternal */ +#ifndef WINNT static PRStatus _MW_PollInternal(PRWaitGroup *group) { PRRecvWait **waiter; @@ -230,12 +407,23 @@ static PRStatus _MW_PollInternal(PRWaitGroup *group) group->poller = PR_GetCurrentThread(); - PR_Unlock(group->ml); - while (PR_TRUE) { PRIntervalTime now, since_last_poll; - PRPollDesc *poll_list = group->polling_list; + PRPollDesc *poll_list; + + while (0 == group->waiter->count) + { + PRStatus st; + st = PR_WaitCondVar(group->new_business, PR_INTERVAL_NO_TIMEOUT); + if (_prmw_running != group->state) + { + PR_SetError(PR_INVALID_STATE_ERROR, 0); + goto aborted; + } + if (_MW_ABORTED(st)) goto aborted; + } + /* ** There's something to do. See if our existing polling list ** is large enough for what we have to do? @@ -246,10 +434,24 @@ static PRStatus _MW_PollInternal(PRWaitGroup *group) PRUint32 old_count = group->waiter->count; PRUint32 new_count = PR_ROUNDUP(old_count, _PR_POLL_COUNT_FUDGE); PRSize new_size = sizeof(PRPollDesc) * new_count; + PRPollDesc *old_polling_list = group->polling_list; + + PR_Unlock(group->ml); poll_list = (PRPollDesc*)PR_CALLOC(new_size); - if (NULL == poll_list) goto failed_alloc; - if (NULL != group->polling_list) - PR_DELETE(group->polling_list); + if (NULL == poll_list) + { + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + PR_Lock(group->ml); + goto failed_alloc; + } + if (NULL != old_polling_list) + PR_DELETE(old_polling_list); + PR_Lock(group->ml); + if (_prmw_running != group->state) + { + PR_SetError(PR_INVALID_STATE_ERROR, 0); + goto aborted; + } group->polling_list = poll_list; group->polling_count = new_count; } @@ -257,14 +459,17 @@ static PRStatus _MW_PollInternal(PRWaitGroup *group) now = PR_IntervalNow(); polling_interval = max_polling_interval; since_last_poll = now - group->last_poll; - PR_Lock(group->ml); - waiter = &group->waiter->recv_wait; + waiter = &group->waiter->recv_wait; + poll_list = group->polling_list; for (count = 0; count < group->waiter->count; ++waiter) { + PR_ASSERT(waiter < &group->waiter->recv_wait + + group->waiter->length); if (NULL != *waiter) /* a live one! */ { - if (since_last_poll >= (*waiter)->timeout) + if ((PR_INTERVAL_NO_TIMEOUT != (*waiter)->timeout) + && (since_last_poll >= (*waiter)->timeout)) _MW_DoneInternal(group, waiter, PR_MW_TIMEOUT); else { @@ -274,6 +479,8 @@ static PRStatus _MW_PollInternal(PRWaitGroup *group) if ((*waiter)->timeout < polling_interval) polling_interval = (*waiter)->timeout; } + PR_ASSERT(poll_list < group->polling_list + + group->polling_count); poll_list->fd = (*waiter)->fd; poll_list->in_flags = PR_POLL_READ; poll_list->out_flags = 0; @@ -289,7 +496,15 @@ static PRStatus _MW_PollInternal(PRWaitGroup *group) } PR_ASSERT(count == group->waiter->count); - if (0 == count) break; + + /* + ** If there are no more threads waiting for completion, + ** we need to return. + */ + if ((!PR_CLIST_IS_EMPTY(&group->io_ready)) + && (1 == group->waiting_threads)) break; + + if (0 == count) continue; /* wait for new business */ group->last_poll = now; @@ -299,14 +514,32 @@ static PRStatus _MW_PollInternal(PRWaitGroup *group) PR_Lock(group->ml); - if (-1 == count_ready) goto failed_poll; /* that's a shame */ - for (poll_list = group->polling_list; count > 0; poll_list++, count--) + if (_prmw_running != group->state) + { + PR_SetError(PR_INVALID_STATE_ERROR, 0); + goto aborted; + } + if (-1 == count_ready) + { + goto failed_poll; /* that's a shame */ + } + else if (0 < count_ready) { - if (poll_list->out_flags != 0) + for (poll_list = group->polling_list; count > 0; + poll_list++, count--) { - waiter = _MW_LookupInternal(group, poll_list->fd); - if (NULL != waiter) - _MW_DoneInternal(group, waiter, PR_MW_SUCCESS); + PR_ASSERT( + poll_list < group->polling_list + group->polling_count); + if (poll_list->out_flags != 0) + { + waiter = _MW_LookupInternal(group, poll_list->fd); + /* + ** If 'waiter' is NULL, that means the wait receive + ** descriptor has been canceled. + */ + if (NULL != waiter) + _MW_DoneInternal(group, waiter, PR_MW_SUCCESS); + } } } /* @@ -315,18 +548,24 @@ static PRStatus _MW_PollInternal(PRWaitGroup *group) ** This thread was "borrowed" to do the polling, but it really ** belongs to the client. */ - if ((_prmw_running != group->state) - || (0 == group->waiting_threads)) break; - PR_Unlock(group->ml); + if ((!PR_CLIST_IS_EMPTY(&group->io_ready)) + && (1 == group->waiting_threads)) break; } rv = PR_SUCCESS; +aborted: failed_poll: failed_alloc: group->poller = NULL; /* we were that, not we ain't */ + if ((_prmw_running == group->state) && (group->waiting_threads > 1)) + { + /* Wake up one thread to become the new poller. */ + PR_NotifyCondVar(group->io_complete); + } return rv; /* we return with the lock held */ } /* _MW_PollInternal */ +#endif /* !WINNT */ static PRMWGroupState MW_TestForShutdownInternal(PRWaitGroup *group) { @@ -338,9 +577,7 @@ static PRMWGroupState MW_TestForShutdownInternal(PRWaitGroup *group) ** to make sure no more threads are made to wait. */ if ((_prmw_stopping == rv) - && (0 == group->waiting_threads) - && PR_CLIST_IS_EMPTY(&group->io_ready) - && (0 == group->waiter->count)) + && (0 == group->waiting_threads)) { rv = group->state = _prmw_stopped; PR_NotifyCondVar(group->mw_manage); @@ -348,6 +585,7 @@ static PRMWGroupState MW_TestForShutdownInternal(PRWaitGroup *group) return rv; } /* MW_TestForShutdownInternal */ +#ifndef WINNT static void _MW_InitialRecv(PRCList *io_ready) { PRRecvWait *desc = (PRRecvWait*)io_ready; @@ -363,6 +601,71 @@ static void _MW_InitialRecv(PRCList *io_ready) desc->outcome = PR_MW_FAILURE; } } /* _MW_InitialRecv */ +#endif + +#ifdef WINNT +static void NT_TimeProc(void *arg) +{ + _MDOverlapped *overlapped = (_MDOverlapped *)arg; + PRRecvWait *desc = overlapped->data.mw.desc; + PRFileDesc *bottom; + + if (InterlockedCompareExchange((PVOID *)&desc->outcome, + (PVOID)PR_MW_TIMEOUT, (PVOID)PR_MW_PENDING) != (PVOID)PR_MW_PENDING) + { + /* This wait recv descriptor has already completed. */ + return; + } + + /* close the osfd to abort the outstanding async io request */ + /* $$$$ + ** Little late to be checking if NSPR's on the bottom of stack, + ** but if we don't check, we can't assert that the private data + ** is what we think it is. + ** $$$$ + */ + bottom = PR_GetIdentitiesLayer(desc->fd, PR_NSPR_IO_LAYER); + PR_ASSERT(NULL != bottom); + if (NULL != bottom) /* now what!?!?! */ + { + bottom->secret->state = _PR_FILEDESC_CLOSED; + if (closesocket(bottom->secret->md.osfd) == SOCKET_ERROR) + { + fprintf(stderr, "closesocket failed: %d\n", WSAGetLastError()); + PR_ASSERT(!"What shall I do?"); + } + } + return; +} /* NT_TimeProc */ + +static PRStatus NT_HashRemove(PRWaitGroup *group, PRFileDesc *fd) +{ + PRRecvWait **waiter; + + _PR_MD_LOCK(&group->mdlock); + waiter = _MW_LookupInternal(group, fd); + if (NULL != waiter) + { + group->waiter->count -= 1; + *waiter = NULL; + } + _PR_MD_UNLOCK(&group->mdlock); + return (NULL != waiter) ? PR_SUCCESS : PR_FAILURE; +} + +PRStatus NT_HashRemoveInternal(PRWaitGroup *group, PRFileDesc *fd) +{ + PRRecvWait **waiter; + + waiter = _MW_LookupInternal(group, fd); + if (NULL != waiter) + { + group->waiter->count -= 1; + *waiter = NULL; + } + return (NULL != waiter) ? PR_SUCCESS : PR_FAILURE; +} +#endif /* WINNT */ /******************************************************************/ /******************************************************************/ @@ -374,8 +677,19 @@ PR_IMPLEMENT(PRStatus) PR_AddWaitFileDesc( { _PR_HashStory hrv; PRStatus rv = PR_FAILURE; - if (PR_FAILURE == MW_Init()) goto failed_init; - if ((NULL == group) && (NULL == (group = MW_Init2()))) goto failed_init; +#ifdef WINNT + _MDOverlapped *overlapped; + HANDLE hFile; + BOOL bResult; + DWORD dwError; + PRFileDesc *bottom; +#endif + + if (!_pr_initialized) _PR_ImplicitInitialization(); + if ((NULL == group) && (NULL == (group = MW_Init2()))) + { + return rv; + } PR_ASSERT(NULL != desc->fd); @@ -389,9 +703,14 @@ PR_IMPLEMENT(PRStatus) PR_AddWaitFileDesc( /* Not allowed to add after cancelling the group */ desc->outcome = PR_MW_INTERRUPT; PR_SetError(PR_INVALID_STATE_ERROR, 0); - goto invalid_state; + PR_Unlock(group->ml); + return rv; } +#ifdef WINNT + _PR_MD_LOCK(&group->mdlock); +#endif + /* ** If the waiter count is zero at this point, there's no telling ** how long we've been idle. Therefore, initialize the beginning @@ -400,6 +719,7 @@ PR_IMPLEMENT(PRStatus) PR_AddWaitFileDesc( */ if (0 == group->waiter->count) group->last_poll = PR_IntervalNow(); + do { hrv = MW_AddHashInternal(desc, group->waiter); @@ -408,20 +728,95 @@ PR_IMPLEMENT(PRStatus) PR_AddWaitFileDesc( if (_prmw_success != hrv) break; } while (PR_TRUE); +#ifdef WINNT + _PR_MD_UNLOCK(&group->mdlock); +#endif + PR_NotifyCondVar(group->new_business); /* tell the world */ rv = (_prmw_success == hrv) ? PR_SUCCESS : PR_FAILURE; - -failed_init: -invalid_state: PR_Unlock(group->ml); + +#ifdef WINNT + overlapped = PR_NEWZAP(_MDOverlapped); + if (NULL == overlapped) + { + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + NT_HashRemove(group, desc->fd); + return rv; + } + overlapped->ioModel = _MD_MultiWaitIO; + overlapped->data.mw.desc = desc; + overlapped->data.mw.group = group; + if (desc->timeout != PR_INTERVAL_NO_TIMEOUT) + { + overlapped->data.mw.timer = CreateTimer( + desc->timeout, + NT_TimeProc, + overlapped); + if (0 == overlapped->data.mw.timer) + { + NT_HashRemove(group, desc->fd); + PR_DELETE(overlapped); + /* + * XXX It appears that a maximum of 16 timer events can + * be outstanding. GetLastError() returns 0 when I try it. + */ + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, GetLastError()); + return PR_FAILURE; + } + } + + /* Reach to the bottom layer to get the OS fd */ + bottom = PR_GetIdentitiesLayer(desc->fd, PR_NSPR_IO_LAYER); + PR_ASSERT(NULL != bottom); + if (NULL == bottom) + { + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + return PR_FAILURE; + } + hFile = (HANDLE)bottom->secret->md.osfd; + if (!bottom->secret->md.io_model_committed) + { + PRInt32 st; + st = _md_Associate(hFile); + PR_ASSERT(0 != st); + bottom->secret->md.io_model_committed = PR_TRUE; + } + bResult = ReadFile(hFile, + desc->buffer.start, + (DWORD)desc->buffer.length, + NULL, + &overlapped->overlapped); + if (FALSE == bResult && (dwError = GetLastError()) != ERROR_IO_PENDING) + { + if (desc->timeout != PR_INTERVAL_NO_TIMEOUT) + { + if (InterlockedCompareExchange((PVOID *)&desc->outcome, + (PVOID)PR_MW_FAILURE, (PVOID)PR_MW_PENDING) + == (PVOID)PR_MW_PENDING) + { + CancelTimer(overlapped->data.mw.timer); + } + NT_HashRemove(group, desc->fd); + PR_DELETE(overlapped); + } + _PR_MD_MAP_READ_ERROR(dwError); + rv = PR_FAILURE; + } +#endif + return rv; } /* PR_AddWaitFileDesc */ PR_IMPLEMENT(PRRecvWait*) PR_WaitRecvReady(PRWaitGroup *group) { - PRStatus rv = PR_SUCCESS; PRCList *io_ready = NULL; - if (PR_FAILURE == MW_Init()) goto failed_init; +#ifdef WINNT + PRThread *me = _PR_MD_CURRENT_THREAD(); + _MDOverlapped *overlapped; +#endif + + if (!_pr_initialized) _PR_ImplicitInitialization(); if ((NULL == group) && (NULL == (group = MW_Init2()))) goto failed_init; PR_Lock(group->ml); @@ -434,6 +829,35 @@ PR_IMPLEMENT(PRRecvWait*) PR_WaitRecvReady(PRWaitGroup *group) group->waiting_threads += 1; /* the polling thread is counted */ +#ifdef WINNT + _PR_MD_LOCK(&group->mdlock); + while (PR_CLIST_IS_EMPTY(&group->io_ready)) + { + _PR_THREAD_LOCK(me); + me->state = _PR_IO_WAIT; + PR_APPEND_LINK(&me->waitQLinks, &group->wait_list); + if (!_PR_IS_NATIVE_THREAD(me)) + { + _PR_SLEEPQ_LOCK(me->cpu); + _PR_ADD_SLEEPQ(me, PR_INTERVAL_NO_TIMEOUT); + _PR_SLEEPQ_UNLOCK(me->cpu); + } + _PR_THREAD_UNLOCK(me); + _PR_MD_UNLOCK(&group->mdlock); + PR_Unlock(group->ml); + _PR_MD_WAIT(me, PR_INTERVAL_NO_TIMEOUT); + me->state = _PR_RUNNING; + PR_Lock(group->ml); + _PR_MD_LOCK(&group->mdlock); + } + io_ready = PR_LIST_HEAD(&group->io_ready); + PR_ASSERT(io_ready != NULL); + PR_REMOVE_LINK(io_ready); + _PR_MD_UNLOCK(&group->mdlock); + overlapped = (_MDOverlapped *) + ((char *)io_ready - offsetof(_MDOverlapped, data)); + io_ready = &overlapped->data.mw.desc->internal; +#else do { /* @@ -442,13 +866,6 @@ PR_IMPLEMENT(PRRecvWait*) PR_WaitRecvReady(PRWaitGroup *group) */ if (PR_CLIST_IS_EMPTY(&group->io_ready)) { - while ((NULL == group->waiter) || (0 == group->waiter->count)) - { - if (_prmw_running != group->state) goto aborted; - rv = PR_WaitCondVar(group->new_business, PR_INTERVAL_NO_TIMEOUT); - if (_MW_ABORTED(rv)) goto aborted; - } - /* ** Is there a polling thread yet? If not, grab this thread ** and use it. @@ -464,31 +881,102 @@ PR_IMPLEMENT(PRRecvWait*) PR_WaitRecvReady(PRWaitGroup *group) ** with some I/O ready. */ if (PR_FAILURE == _MW_PollInternal(group)) goto failed_poll; - if (PR_CLIST_IS_EMPTY(&group->io_ready)) continue; /* timeout */ } else { + /* + ** There are four reasons a thread can be awakened from + ** a wait on the io_complete condition variable. + ** 1. Some I/O has completed, i.e., the io_ready list + ** is nonempty. + ** 2. The wait group is canceled. + ** 3. The thread is interrupted. + ** 4. The current polling thread has to leave and needs + ** a replacement. + ** The logic to find a new polling thread is made more + ** complicated by all the other possible events. + ** I tried my best to write the logic clearly, but + ** it is still full of if's with continue and goto. + */ + PRStatus st; while (PR_CLIST_IS_EMPTY(&group->io_ready)) { - rv = PR_WaitCondVar(group->io_complete, PR_INTERVAL_NO_TIMEOUT); - if (_MW_ABORTED(rv)) goto aborted; + st = PR_WaitCondVar(group->io_complete, PR_INTERVAL_NO_TIMEOUT); + if (_prmw_running != group->state) + { + PR_SetError(PR_INVALID_STATE_ERROR, 0); + goto aborted; + } + if (_MW_ABORTED(st) || (NULL == group->poller)) break; + } + + /* + ** The thread is interrupted and has to leave. It might + ** have also been awakened to process ready i/o or be the + ** new poller. To be safe, if either condition is true, + ** we awaken another thread to take its place. + */ + if (_MW_ABORTED(st)) + { + if ((NULL == group->poller + || !PR_CLIST_IS_EMPTY(&group->io_ready)) + && group->waiting_threads > 1) + PR_NotifyCondVar(group->io_complete); + goto aborted; + } + + /* + ** A new poller is needed, but can I be the new poller? + ** If there is no i/o ready, sure. But if there is any + ** i/o ready, it has a higher priority. I want to + ** process the ready i/o first and wake up another + ** thread to be the new poller. + */ + if (NULL == group->poller) + { + if (PR_CLIST_IS_EMPTY(&group->io_ready)) + continue; + if (group->waiting_threads > 1) + PR_NotifyCondVar(group->io_complete); } } + PR_ASSERT(!PR_CLIST_IS_EMPTY(&group->io_ready)); } io_ready = PR_LIST_HEAD(&group->io_ready); PR_NotifyCondVar(group->io_taken); PR_ASSERT(io_ready != NULL); PR_REMOVE_LINK(io_ready); + } while (NULL == io_ready); + +aborted: +failed_poll: +#endif + + group->waiting_threads -= 1; +invalid_state: + (void)MW_TestForShutdownInternal(group); + PR_Unlock(group->ml); + +failed_init: + if (NULL != io_ready) + { /* If the operation failed, record the reason why */ switch (((PRRecvWait*)io_ready)->outcome) { case PR_MW_PENDING: - PR_ASSERT(PR_MW_PENDING != ((PRRecvWait*)io_ready)->outcome); + PR_ASSERT(0); break; case PR_MW_SUCCESS: +#ifndef WINNT _MW_InitialRecv(io_ready); +#endif break; +#ifdef WINNT + case PR_MW_FAILURE: + _PR_MD_MAP_READ_ERROR(overlapped->data.mw.error); + break; +#endif case PR_MW_TIMEOUT: PR_SetError(PR_IO_TIMEOUT_ERROR, 0); break; @@ -497,25 +985,30 @@ PR_IMPLEMENT(PRRecvWait*) PR_WaitRecvReady(PRWaitGroup *group) break; default: break; } - } while (NULL == io_ready); - -aborted: -failed_poll: - group->waiting_threads -= 1; -invalid_state: - (void)MW_TestForShutdownInternal(group); - PR_Unlock(group->ml); - -failed_init: - +#ifdef WINNT + if (NULL != overlapped->data.mw.timer) + { + PR_ASSERT(PR_INTERVAL_NO_TIMEOUT + != overlapped->data.mw.desc->timeout); + CancelTimer(overlapped->data.mw.timer); + } + else + { + PR_ASSERT(PR_INTERVAL_NO_TIMEOUT + == overlapped->data.mw.desc->timeout); + } + PR_DELETE(overlapped); +#endif + } return (PRRecvWait*)io_ready; } /* PR_WaitRecvReady */ PR_IMPLEMENT(PRStatus) PR_CancelWaitFileDesc(PRWaitGroup *group, PRRecvWait *desc) { +#if !defined(WINNT) PRRecvWait **recv_wait; +#endif PRStatus rv = PR_SUCCESS; - if (PR_FAILURE == MW_Init()) return rv; if (NULL == group) group = mw_state->group; PR_ASSERT(NULL != group); if (NULL == group) @@ -533,6 +1026,28 @@ PR_IMPLEMENT(PRStatus) PR_CancelWaitFileDesc(PRWaitGroup *group, PRRecvWait *des goto stopping; } +#ifdef WINNT + if (InterlockedCompareExchange((PVOID *)&desc->outcome, + (PVOID)PR_MW_INTERRUPT, (PVOID)PR_MW_PENDING) == (PVOID)PR_MW_PENDING) + { + PRFileDesc *bottom = PR_GetIdentitiesLayer(desc->fd, PR_NSPR_IO_LAYER); + PR_ASSERT(NULL != bottom); + if (NULL == bottom) + { + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + goto invalid_arg; + } + bottom->secret->state = _PR_FILEDESC_CLOSED; +#if 0 + fprintf(stderr, "cancel wait recv: closing socket\n"); +#endif + if (closesocket(bottom->secret->md.osfd) == SOCKET_ERROR) + { + fprintf(stderr, "closesocket failed: %d\n", WSAGetLastError()); + exit(1); + } + } +#else if (NULL != (recv_wait = _MW_LookupInternal(group, desc->fd))) { /* it was in the wait table */ @@ -554,7 +1069,9 @@ PR_IMPLEMENT(PRStatus) PR_CancelWaitFileDesc(PRWaitGroup *group, PRRecvWait *des rv = PR_FAILURE; found: +#endif stopping: +invalid_arg: PR_Unlock(group->ml); return rv; } /* PR_CancelWaitFileDesc */ @@ -563,11 +1080,12 @@ PR_IMPLEMENT(PRRecvWait*) PR_CancelWaitGroup(PRWaitGroup *group) { PRRecvWait **desc; PRRecvWait *recv_wait = NULL; - if (PR_FAILURE == MW_Init()) - { - PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); - return NULL; - } +#ifdef WINNT + _MDOverlapped *overlapped; + PRRecvWait **end; + PRThread *me = _PR_MD_CURRENT_THREAD(); +#endif + if (NULL == group) group = mw_state->group; PR_ASSERT(NULL != group); if (NULL == group) @@ -583,18 +1101,77 @@ PR_IMPLEMENT(PRRecvWait*) PR_CancelWaitGroup(PRWaitGroup *group) group->state = _prmw_stopping; /* so nothing new comes in */ if (0 == group->waiting_threads) /* is there anybody else? */ group->state = _prmw_stopped; /* we can stop right now */ + else + { + PR_NotifyAllCondVar(group->new_business); + PR_NotifyAllCondVar(group->io_complete); + } while (_prmw_stopped != group->state) (void)PR_WaitCondVar(group->mw_manage, PR_INTERVAL_NO_TIMEOUT); + } - /* make all the existing descriptors look done/interrupted */ - for (desc = &group->waiter->recv_wait; group->waiter->count > 0; ++desc) +#ifdef WINNT + _PR_MD_LOCK(&group->mdlock); +#endif + /* make all the existing descriptors look done/interrupted */ +#ifdef WINNT + end = &group->waiter->recv_wait + group->waiter->length; + for (desc = &group->waiter->recv_wait; desc < end; ++desc) + { + if (NULL != *desc) { - if (NULL != *desc) - _MW_DoneInternal(group, desc, PR_MW_INTERRUPT); + if (InterlockedCompareExchange((PVOID *)&(*desc)->outcome, + (PVOID)PR_MW_INTERRUPT, (PVOID)PR_MW_PENDING) + == (PVOID)PR_MW_PENDING) + { + PRFileDesc *bottom = PR_GetIdentitiesLayer( + (*desc)->fd, PR_NSPR_IO_LAYER); + PR_ASSERT(NULL != bottom); + if (NULL == bottom) + { + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + goto invalid_arg; + } + bottom->secret->state = _PR_FILEDESC_CLOSED; +#if 0 + fprintf(stderr, "cancel wait group: closing socket\n"); +#endif + if (closesocket(bottom->secret->md.osfd) == SOCKET_ERROR) + { + fprintf(stderr, "closesocket failed: %d\n", + WSAGetLastError()); + exit(1); + } + } } - - PR_NotifyAllCondVar(group->new_business); } + while (group->waiter->count > 0) + { + _PR_THREAD_LOCK(me); + me->state = _PR_IO_WAIT; + PR_APPEND_LINK(&me->waitQLinks, &group->wait_list); + if (!_PR_IS_NATIVE_THREAD(me)) + { + _PR_SLEEPQ_LOCK(me->cpu); + _PR_ADD_SLEEPQ(me, PR_INTERVAL_NO_TIMEOUT); + _PR_SLEEPQ_UNLOCK(me->cpu); + } + _PR_THREAD_UNLOCK(me); + _PR_MD_UNLOCK(&group->mdlock); + PR_Unlock(group->ml); + _PR_MD_WAIT(me, PR_INTERVAL_NO_TIMEOUT); + me->state = _PR_RUNNING; + PR_Lock(group->ml); + _PR_MD_LOCK(&group->mdlock); + } +#else + for (desc = &group->waiter->recv_wait; group->waiter->count > 0; ++desc) + { + PR_ASSERT(desc < &group->waiter->recv_wait + group->waiter->length); + if (NULL != *desc) + _MW_DoneInternal(group, desc, PR_MW_INTERRUPT); + } +#endif /* take first element of finished list and return it or NULL */ if (PR_CLIST_IS_EMPTY(&group->io_ready)) @@ -603,8 +1180,17 @@ PR_IMPLEMENT(PRRecvWait*) PR_CancelWaitGroup(PRWaitGroup *group) { PRCList *head = PR_LIST_HEAD(&group->io_ready); PR_REMOVE_AND_INIT_LINK(head); +#ifdef WINNT + overlapped = (_MDOverlapped *) + ((char *)head - offsetof(_MDOverlapped, data)); + head = &overlapped->data.mw.desc->internal; +#endif recv_wait = (PRRecvWait*)head; } +#ifdef WINNT +invalid_arg: + _PR_MD_UNLOCK(&group->mdlock); +#endif PR_Unlock(group->ml); return recv_wait; @@ -612,10 +1198,13 @@ PR_IMPLEMENT(PRRecvWait*) PR_CancelWaitGroup(PRWaitGroup *group) PR_IMPLEMENT(PRWaitGroup*) PR_CreateWaitGroup(PRInt32 size /* ignored */) { - PRWaitGroup *wg = NULL; - if (PR_FAILURE == MW_Init()) goto failed; + PRWaitGroup *wg; - if (NULL == (wg = PR_NEWZAP(PRWaitGroup))) goto failed; + if (NULL == (wg = PR_NEWZAP(PRWaitGroup))) + { + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + goto failed; + } /* the wait group itself */ wg->ml = PR_NewLock(); if (NULL == wg->ml) goto failed_lock; @@ -635,10 +1224,19 @@ PR_IMPLEMENT(PRWaitGroup*) PR_CreateWaitGroup(PRInt32 size /* ignored */) wg->waiter = (_PRWaiterHash*)PR_CALLOC( sizeof(_PRWaiterHash) + (_PR_DEFAULT_HASH_LENGTH * sizeof(PRRecvWait*))); - if (NULL == wg->waiter) goto failed_waiter; + if (NULL == wg->waiter) + { + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + goto failed_waiter; + } wg->waiter->count = 0; wg->waiter->length = _PR_DEFAULT_HASH_LENGTH; +#ifdef WINNT + _PR_MD_NEW_LOCK(&wg->mdlock); + PR_INIT_CLIST(&wg->wait_list); +#endif /* WINNT */ + PR_Lock(mw_lock); PR_APPEND_LINK(&wg->group_link, &mw_state->group_list); PR_Unlock(mw_lock); @@ -649,13 +1247,14 @@ failed_waiter: failed_cvar3: PR_DestroyCondVar(wg->new_business); failed_cvar2: - PR_DestroyCondVar(wg->io_taken); -failed_cvar1: PR_DestroyCondVar(wg->io_complete); +failed_cvar1: + PR_DestroyCondVar(wg->io_taken); failed_cvar0: PR_DestroyLock(wg->ml); failed_lock: PR_DELETE(wg); + wg = NULL; failed: return wg; @@ -668,27 +1267,36 @@ PR_IMPLEMENT(PRStatus) PR_DestroyWaitGroup(PRWaitGroup *group) PR_ASSERT(NULL != group); if (NULL != group) { - if (_prmw_stopped != group->state) /* quick, unsafe test */ + PR_Lock(group->ml); + if ((group->waiting_threads == 0) + && (group->waiter->count == 0) + && PR_CLIST_IS_EMPTY(&group->io_ready)) { - PRMWGroupState mws; - /* One shot to correct the situation */ - PR_Lock(group->ml); - if (group->state < _prmw_stopped) /* safer test */ - group->state = _prmw_stopping; - mws = MW_TestForShutdownInternal(group); - PR_Unlock(group->ml); - if (_prmw_stopped != mws) /* quick test again */ - { - PR_SetError(PR_INVALID_STATE_ERROR, 0); - return PR_FAILURE; - } + group->state = _prmw_stopped; } + else + { + PR_SetError(PR_INVALID_STATE_ERROR, 0); + rv = PR_FAILURE; + } + PR_Unlock(group->ml); + if (PR_FAILURE == rv) return rv; PR_Lock(mw_lock); PR_REMOVE_LINK(&group->group_link); PR_Unlock(mw_lock); +#ifdef WINNT + /* + * XXX make sure wait_list is empty and waiter is empty. + * These must be checked while holding mdlock. + */ + _PR_MD_FREE_LOCK(&group->mdlock); +#endif + PR_DELETE(group->waiter); + PR_DELETE(group->polling_list); + PR_DestroyCondVar(group->mw_manage); PR_DestroyCondVar(group->new_business); PR_DestroyCondVar(group->io_complete); PR_DestroyCondVar(group->io_taken); @@ -696,7 +1304,108 @@ PR_IMPLEMENT(PRStatus) PR_DestroyWaitGroup(PRWaitGroup *group) if (group == mw_state->group) mw_state->group = NULL; PR_DELETE(group); } + else + { + /* The default wait group is not created yet. */ + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + rv = PR_FAILURE; + } return rv; } /* PR_DestroyWaitGroup */ +/********************************************************************** +*********************************************************************** +******************** Wait group enumerations ************************** +*********************************************************************** +**********************************************************************/ + +PR_IMPLEMENT(PRMWaitEnumerator*) PR_CreateMWaitEnumerator(PRWaitGroup *group) +{ + PRMWaitEnumerator *enumerator = PR_NEWZAP(PRMWaitEnumerator); + if (NULL == enumerator) PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + else + { + enumerator->group = group; + enumerator->seal = _PR_ENUM_SEALED; + } + return enumerator; +} /* PR_CreateMWaitEnumerator */ + +PR_IMPLEMENT(PRStatus) PR_DestroyMWaitEnumerator(PRMWaitEnumerator* enumerator) +{ + PR_ASSERT(NULL != enumerator); + PR_ASSERT(_PR_ENUM_SEALED == enumerator->seal); + if ((NULL == enumerator) || (_PR_ENUM_SEALED != enumerator->seal)) + { + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + return PR_FAILURE; + } + enumerator->seal = _PR_ENUM_UNSEALED; + PR_Free(enumerator); + return PR_SUCCESS; +} /* PR_DestroyMWaitEnumerator */ + +PR_IMPLEMENT(PRRecvWait*) PR_EnumerateWaitGroup( + PRMWaitEnumerator *enumerator, const PRRecvWait *previous) +{ + PRRecvWait *result = NULL; + + /* entry point sanity checking */ + PR_ASSERT(NULL != enumerator); + PR_ASSERT(_PR_ENUM_SEALED == enumerator->seal); + if ((NULL == enumerator) + || (_PR_ENUM_SEALED != enumerator->seal)) goto bad_argument; + + /* beginning of enumeration */ + if (NULL == previous) + { + if (NULL == enumerator->group) + { + enumerator->group = mw_state->group; + if (NULL == enumerator->group) + { + PR_SetError(PR_GROUP_EMPTY_ERROR, 0); + return NULL; + } + } + enumerator->waiter = &enumerator->group->waiter->recv_wait; + enumerator->p_timestamp = enumerator->group->p_timestamp; + enumerator->thread = PR_GetCurrentThread(); + enumerator->index = 0; + } + /* continuing an enumeration */ + else + { + PRThread *me = PR_GetCurrentThread(); + PR_ASSERT(me == enumerator->thread); + if (me != enumerator->thread) goto bad_argument; + + /* need to restart the enumeration */ + if (enumerator->p_timestamp != enumerator->group->p_timestamp) + return PR_EnumerateWaitGroup(enumerator, NULL); + } + + /* actually progress the enumeration */ +#if defined(WINNT) + _PR_MD_LOCK(&enumerator->group->mdlock); +#else + PR_Lock(enumerator->group->ml); +#endif + while (enumerator->index++ < enumerator->group->waiter->length) + { + if (NULL != (result = *(enumerator->waiter)++)) break; + } +#if defined(WINNT) + _PR_MD_UNLOCK(&enumerator->group->mdlock); +#else + PR_Unlock(enumerator->group->ml); +#endif + + return result; /* what we live for */ + +bad_argument: + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + return NULL; /* probably ambiguous */ +} /* PR_EnumerateWaitGroup */ + /* prmwait.c */ diff --git a/pr/src/io/prpolevt.c b/pr/src/io/prpolevt.c new file mode 100644 index 00000000..a1ca3760 --- /dev/null +++ b/pr/src/io/prpolevt.c @@ -0,0 +1,121 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "NPL"); you may not use this file except in + * compliance with the NPL. You may obtain a copy of the NPL at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the NPL is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL + * for the specific language governing rights and limitations under the + * NPL. + * + * The Initial Developer of this code under the NPL is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All Rights + * Reserved. + */ + +/* + ********************************************************************* + * + * Pollable events + * + ********************************************************************* + */ + +#include "primpl.h" + +typedef struct MyFilePrivate { + PRFilePrivate copy; + PRFileDesc *writeEnd; + PRFilePrivate *oldSecret; +} MyFilePrivate; + +#ifndef XP_UNIX +#define USE_TCP_SOCKETPAIR +#endif + +PR_IMPLEMENT(PRFileDesc *) PR_NewPollableEvent(void) +{ + PRFileDesc *fd[2]; /* fd[0] is the read end; fd[1] is the write end */ + MyFilePrivate *secret; + + secret = PR_NEW(MyFilePrivate); + if (secret == NULL) { + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + goto errorExit; + } + +#ifndef USE_TCP_SOCKETPAIR + if (PR_CreatePipe(&fd[0], &fd[1]) == PR_FAILURE) { + goto errorExit; + } +#else + if (PR_NewTCPSocketPair(fd) == PR_FAILURE) { + goto errorExit; + } +#endif + + secret->copy = *fd[0]->secret; + secret->oldSecret = fd[0]->secret; + secret->writeEnd = fd[1]; + fd[0]->secret = (PRFilePrivate *) secret; + + return fd[0]; + +errorExit: + PR_DELETE(secret); + return NULL; +} + +PR_IMPLEMENT(PRStatus) PR_DestroyPollableEvent(PRFileDesc *event) +{ + MyFilePrivate *secret; + + secret = (MyFilePrivate *) event->secret; + event->secret = secret->oldSecret; + PR_Close(event); + PR_Close(secret->writeEnd); + PR_DELETE(secret); + return PR_SUCCESS; +} + +static const char magicChar = '\x38'; + +PR_IMPLEMENT(PRStatus) PR_SetPollableEvent(PRFileDesc *event) +{ + MyFilePrivate *secret; + + secret = (MyFilePrivate *) event->secret; + if (PR_Write(secret->writeEnd, &magicChar, 1) != 1) { + return PR_FAILURE; + } + return PR_SUCCESS; +} + +PR_IMPLEMENT(PRStatus) PR_WaitForPollableEvent(PRFileDesc *event) +{ + char buf[1024]; + PRInt32 nBytes; +#ifdef DEBUG + PRIntn i; +#endif + + nBytes = PR_Read(event, buf, sizeof(buf)); + if (nBytes == -1) { + return PR_FAILURE; + } + +#ifdef DEBUG + /* + * Make sure people do not write to the pollable event fd + * directly. + */ + for (i = 0; i < nBytes; i++) { + PR_ASSERT(buf[i] == magicChar); + } +#endif + + return PR_SUCCESS; +} diff --git a/pr/src/io/prsocket.c b/pr/src/io/prsocket.c index d0fbcf82..11611cfa 100644 --- a/pr/src/io/prsocket.c +++ b/pr/src/io/prsocket.c @@ -221,14 +221,16 @@ PR_IMPLEMENT(PRStatus) PR_GetConnectStatus(const PRPollDesc *pd) #elif defined(WIN32) || defined(WIN16) - if (pd->out_flags & PR_POLL_EXCEPT) { - int len = sizeof(err); #if defined(WIN32) -/* Note: There is a bug in Win32 WinSock. The sleep circumvents the -** bug. See wtc. /s lth. -*/ - Sleep(0); + /* + * The sleep circumvents a bug in Win32 WinSock. + * See Microsoft Knowledge Base article ID: Q165989. + */ + Sleep(0); #endif /* WIN32 */ + + if (pd->out_flags & PR_POLL_EXCEPT) { + int len = sizeof(err); if (getsockopt(osfd, (int)SOL_SOCKET, SO_ERROR, (char *) &err, &len) == SOCKET_ERROR) { _PR_MD_MAP_GETSOCKOPT_ERROR(WSAGetLastError()); @@ -517,20 +519,21 @@ static PRInt32 PR_CALLBACK SocketWrite(PRFileDesc *fd, const void *buf, PRInt32 static PRStatus PR_CALLBACK SocketClose(PRFileDesc *fd) { - PRInt32 rv; - - if (!fd || fd->secret->state != _PR_FILEDESC_OPEN) { + if (!fd || !fd->secret + || (fd->secret->state != _PR_FILEDESC_OPEN + && fd->secret->state != _PR_FILEDESC_CLOSED)) { PR_SetError(PR_BAD_DESCRIPTOR_ERROR, 0); return PR_FAILURE; } - fd->secret->state = _PR_FILEDESC_CLOSED; + if (fd->secret->state == _PR_FILEDESC_OPEN) { + if (_PR_MD_CLOSE_SOCKET(fd->secret->md.osfd) < 0) { + return PR_FAILURE; + } + fd->secret->state = _PR_FILEDESC_CLOSED; + } - rv = _PR_MD_CLOSE_SOCKET(fd->secret->md.osfd); PR_FreeFileDesc(fd); - if (rv < 0) { - return PR_FAILURE; - } return PR_SUCCESS; } @@ -632,6 +635,11 @@ PRIntervalTime timeout) PR_SetError(PR_IO_PENDING_ERROR, 0); return -1; } + /* The socket must be in blocking mode. */ + if (sd->secret->nonblocking) { + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + return -1; + } *nd = NULL; #if defined(WINNT) @@ -784,6 +792,11 @@ PRIntervalTime timeout) PR_SetError(PR_IO_PENDING_ERROR, 0); return -1; } + /* The socket must be in blocking mode. */ + if (sd->secret->nonblocking) { + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + return -1; + } #if defined(WINNT) rv = _PR_MD_TRANSMITFILE( sd, fd, @@ -797,7 +810,6 @@ PRIntervalTime timeout) * that _PR_MD_CLOSE_SOCKET(sd->secret->md.osfd) should * not be called because the socket will be recycled. */ - sd->secret->state = _PR_FILEDESC_CLOSED; PR_FreeFileDesc(sd); } #else @@ -885,7 +897,7 @@ static PRStatus PR_CALLBACK SocketGetSockOpt( else { rv = _PR_MD_GETSOCKOPT( - fd, level, name, optval, optlen); + fd, level, name, (char*)optval, optlen); } } return rv; @@ -940,7 +952,7 @@ static PRStatus PR_CALLBACK SocketSetSockOpt( else { rv = _PR_MD_SETSOCKOPT( - fd, level, name, optval, optlen); + fd, level, name, (const char*)optval, optlen); } } return rv; @@ -1126,20 +1138,62 @@ PR_IMPLEMENT(PRStatus) PR_NewTCPSocketPair(PRFileDesc *f[]) _PR_MD_MAKE_NONBLOCK(f[0]); _PR_MD_MAKE_NONBLOCK(f[1]); return PR_SUCCESS; -#endif - - /* XXX: this needs to be implemented for MAC and NT */ -#ifdef XP_MAC -#pragma unused (f) +#else /* XP_UNIX */ + PRFileDesc *listenSock; + PRNetAddr selfAddr; + PRUint16 port; + + f[0] = f[1] = NULL; + listenSock = PR_NewTCPSocket(); + if (listenSock == NULL) { + goto failed; + } + PR_InitializeNetAddr(PR_IpAddrAny, 0, &selfAddr); + if (PR_Bind(listenSock, &selfAddr) == PR_FAILURE) { + goto failed; + } + if (PR_GetSockName(listenSock, &selfAddr) == PR_FAILURE) { + goto failed; + } + port = ntohs(selfAddr.inet.port); + if (PR_Listen(listenSock, 5) == PR_FAILURE) { + goto failed; + } + f[0] = PR_NewTCPSocket(); + if (f[0] == NULL) { + goto failed; + } + PR_InitializeNetAddr(PR_IpAddrLoopback, port, &selfAddr); - PR_SetError(PR_NOT_IMPLEMENTED_ERROR, unimpErr); - return PR_FAILURE; -#endif + /* + * Only a thread is used to do the connect and accept. + * I am relying on the fact that PR_Connect returns + * successfully as soon as the connect request is put + * into the listen queue (but before PR_Accept is called). + * This is the behavior of the BSD socket code. If + * connect does not return until accept is called, we + * will need to create another thread to call connect. + */ + if (PR_Connect(f[0], &selfAddr, PR_INTERVAL_NO_TIMEOUT) + == PR_FAILURE) { + goto failed; + } + f[1] = PR_Accept(listenSock, NULL, PR_INTERVAL_NO_TIMEOUT); + if (f[1] == NULL) { + goto failed; + } + PR_Close(listenSock); + return PR_SUCCESS; -#ifdef XP_PC - PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); - return PR_FAILURE; -#endif +failed: + if (listenSock) { + PR_Close(listenSock); + } + if (f[0]) { + PR_Close(f[0]); + } + return PR_FAILURE; +#endif /* XP_UNIX */ } PR_IMPLEMENT(PRInt32) @@ -1196,7 +1250,7 @@ PRIntervalTime timeout) return -1; } - buf = PR_MALLOC(_TRANSMITFILE_BUFSIZE); + buf = (char*)PR_MALLOC(_TRANSMITFILE_BUFSIZE); if (buf == NULL) { PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); return -1; @@ -1262,47 +1316,49 @@ done: * newly accepted socket, read 'amount' bytes from the accepted * socket. * - * buf is a buffer of length = (amount + sizeof(PRNetAddr)) + * buf is a buffer of length = (amount + 2 * sizeof(PRNetAddr)) * *raddr points to the PRNetAddr of the accepted connection upon * return * * return number of bytes read or -1 on error * */ -PRInt32 _PR_EmulateAcceptRead(PRFileDesc *sd, PRFileDesc **nd, -PRNetAddr **raddr, void *buf, PRInt32 amount, PRIntervalTime timeout) +PRInt32 _PR_EmulateAcceptRead( + PRFileDesc *sd, PRFileDesc **nd, PRNetAddr **raddr, + void *buf, PRInt32 amount, PRIntervalTime timeout) { - PRInt32 rv; - PRFileDesc *newsockfd; - PRIntervalTime start, elapsed; + PRInt32 rv = -1; + PRNetAddr remote; + PRFileDesc *accepted = NULL; - if (PR_INTERVAL_NO_TIMEOUT != timeout) { - start = PR_IntervalNow(); - } - *raddr = (PRNetAddr *) ((char *) buf + amount); - if ((newsockfd = PR_Accept(sd, *raddr, timeout)) == NULL) { - return -1; - } + /* The socket must be in blocking mode. */ + if (sd->secret->nonblocking) + { + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + return rv; + } - if (PR_INTERVAL_NO_TIMEOUT != timeout) { - elapsed = (PRIntervalTime) (PR_IntervalNow() - start); - if (elapsed > timeout) { - PR_SetError(PR_IO_TIMEOUT_ERROR, 0); - goto failed; - } else { - timeout = timeout - elapsed; - } - } + /* + ** The timeout does not apply to the accept portion of the + ** operation - it waits indefinitely. + */ + accepted = PR_Accept(sd, &remote, PR_INTERVAL_NO_TIMEOUT); + if (NULL == accepted) return rv; - rv = PR_Recv(newsockfd, buf, amount, 0, timeout); - if (rv >= 0) { - *nd = newsockfd; - return rv; - } + rv = PR_Recv(accepted, buf, amount, 0, timeout); + if (rv >= 0) + { + /* copy the new info out where caller can see it */ + PRPtrdiff aligned = (PRPtrdiff)buf + amount + sizeof(void*) - 1; + *raddr = (PRNetAddr*)(aligned & ~(sizeof(void*) - 1)); + memcpy(*raddr, &remote, PR_NETADDR_SIZE(&remote)); + *nd = accepted; + return rv; + } failed: - PR_Close(newsockfd); - return -1; + PR_Close(accepted); + return rv; } /* @@ -1403,7 +1459,7 @@ static PRPollDesc *_pr_setfd( if ((PRFileDesc*)-1 == poll[pdidx].fd) { /* our vector is full - extend and condition it */ - poll = PR_Realloc( + poll = (PRPollDesc*)PR_Realloc( poll, (pdidx + 1 + PD_INCR) * sizeof(PRPollDesc)); if (NULL == poll) goto out_of_memory; memset( @@ -1495,7 +1551,7 @@ PR_IMPLEMENT(PRInt32) PR_Select( return 0; } - copy = poll = PR_Calloc(npds + PD_INCR, sizeof(PRPollDesc)); + copy = poll = (PRPollDesc*)PR_Calloc(npds + PD_INCR, sizeof(PRPollDesc)); if (NULL == poll) goto out_of_memory; poll[npds + PD_INCR - 1].fd = (PRFileDesc*)-1; diff --git a/pr/src/linking/prlink.c b/pr/src/linking/prlink.c index 93f0b45a..ff06b33d 100644 --- a/pr/src/linking/prlink.c +++ b/pr/src/linking/prlink.c @@ -32,7 +32,7 @@ #include <dlfcn.h> #elif defined(USE_HPSHL) #include <dl.h> -#elif defined(USE_RLD) +#elif defined(RHAPSODY) #include <mach-o/dyld.h> #endif @@ -42,6 +42,13 @@ #endif #endif /* XP_UNIX */ +/* + * On these platforms, symbols have a leading '_'. + */ +#if defined(SUNOS4) || defined(RHAPSODY) || defined(WIN16) +#define NEED_LEADING_UNDERSCORE +#endif + #ifdef XP_PC typedef PRStaticLinkTable *NODL_PROC(void); #endif @@ -49,25 +56,25 @@ typedef PRStaticLinkTable *NODL_PROC(void); /************************************************************************/ struct PRLibrary { - char* name; /* Our own copy of the name string */ - PRLibrary* next; - int refCount; - const PRStaticLinkTable* staticTable; + char* name; /* Our own copy of the name string */ + PRLibrary* next; + int refCount; + const PRStaticLinkTable* staticTable; #ifdef XP_PC - HINSTANCE dlh; + HINSTANCE dlh; #endif #ifdef XP_MAC - CFragConnectionID dlh; + CFragConnectionID dlh; #endif #ifdef XP_UNIX #if defined(USE_HPSHL) - shl_t dlh; -#elif defined(USE_RLD) - NSModule dlh; + shl_t dlh; +#elif defined(RHAPSODY) + NSModule dlh; #else - void* dlh; + void* dlh; #endif #endif }; @@ -81,11 +88,11 @@ static char* _pr_currentLibPath = NULL; #if !defined(USE_DLFCN) && !defined(HAVE_STRERROR) static char* errStrBuf = NULL; -#define ERR_STR_BUF_LENGTH 20 +#define ERR_STR_BUF_LENGTH 20 static char* errno_string(PRIntn oserr) { if (errStrBuf == NULL) - errStrBuf = PR_MALLOC(ERR_STR_BUF_LENGTH); + errStrBuf = PR_MALLOC(ERR_STR_BUF_LENGTH); PR_snprintf(errStrBuf, ERR_STR_BUF_LENGTH, "error %d", oserr); return errStrBuf; } @@ -140,31 +147,31 @@ void _PR_InitLinker(void) lm->dlh = (HINSTANCE)NULL; #endif /* ! _WIN32 */ - lm->refCount = 1; + lm->refCount = 1; lm->staticTable = NULL; - pr_exe_loadmap = lm; - pr_loadmap = lm; + pr_exe_loadmap = lm; + pr_loadmap = lm; #elif defined(XP_UNIX) #ifdef HAVE_DLL #ifdef USE_DLFCN h = dlopen(0, RTLD_LAZY); - if (!h) { - char *error; - - DLLErrorInternal(_MD_ERRNO()); - error = (char*)PR_MALLOC(PR_GetErrorTextLength()); - (void) PR_GetErrorText(error); - fprintf(stderr, "failed to initialize shared libraries [%s]\n", - error); - PR_DELETE(error); - abort();/* XXX */ - } + if (!h) { + char *error; + + DLLErrorInternal(_MD_ERRNO()); + error = (char*)PR_MALLOC(PR_GetErrorTextLength()); + (void) PR_GetErrorText(error); + fprintf(stderr, "failed to initialize shared libraries [%s]\n", + error); + PR_DELETE(error); + abort();/* XXX */ + } #elif defined(USE_HPSHL) - h = NULL; - /* don't abort with this NULL */ -#elif defined(USE_RLD) - h = NULL; /* XXXX toshok */ + h = NULL; + /* don't abort with this NULL */ +#elif defined(RHAPSODY) + h = NULL; /* XXXX toshok */ #else #error no dll strategy #endif /* USE_DLFCN */ @@ -172,7 +179,7 @@ void _PR_InitLinker(void) lm = PR_NEWZAP(PRLibrary); if (lm) { lm->name = strdup("a.out"); - lm->refCount = 1; + lm->refCount = 1; lm->dlh = h; lm->staticTable = NULL; } @@ -194,14 +201,14 @@ void _PR_ShutdownLinker(void) PR_EnterMonitor(pr_linker_lock); while (pr_loadmap) { - if (pr_loadmap->refCount > 1) { + if (pr_loadmap->refCount > 1) { #ifdef DEBUG - fprintf(stderr, "# Forcing library to unload: %s (%d outstanding references)\n", - pr_loadmap->name, pr_loadmap->refCount); + fprintf(stderr, "# Forcing library to unload: %s (%d outstanding references)\n", + pr_loadmap->name, pr_loadmap->refCount); #endif - pr_loadmap->refCount = 1; - } - PR_UnloadLibrary(pr_loadmap); + pr_loadmap->refCount = 1; + } + PR_UnloadLibrary(pr_loadmap); } PR_ExitMonitor(pr_linker_lock); @@ -223,7 +230,7 @@ PR_IMPLEMENT(PRStatus) PR_SetLibraryPath(const char *path) _pr_currentLibPath = strdup(path); if (!_pr_currentLibPath) { PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); - rv = PR_FAILURE; + rv = PR_FAILURE; } } else { _pr_currentLibPath = 0; @@ -251,78 +258,78 @@ PR_GetLibraryPath() #ifdef XP_PC ev = getenv("LD_LIBRARY_PATH"); if (!ev) { - ev = ".;\\lib"; + ev = ".;\\lib"; } ev = strdup(ev); #endif #ifdef XP_MAC - { - char *p; - int len; + { + char *p; + int len; ev = getenv("LD_LIBRARY_PATH"); /* if we couldn't find something make up a default */ - if (!ev) - ev = "/usr/local/netscape;/usr/local/netscape/java/bin"; /* do we put the classes in here too? */ - - len = strlen(ev) + 1; /* +1 for the null */ - p = (char*) PR_MALLOC(len); - if (p) { - strcpy(p, ev); - } - ev = p; - } + if (!ev) + ev = "/usr/local/netscape;/usr/local/netscape/java/bin"; /* do we put the classes in here too? */ + + len = strlen(ev) + 1; /* +1 for the null */ + p = (char*) PR_MALLOC(len); + if (p) { + strcpy(p, ev); + } + ev = p; + } #endif #ifdef XP_UNIX -#if defined USE_DLFCN || defined USE_RLD +#if defined USE_DLFCN || defined RHAPSODY { - char *home; - char *local; - char *p=NULL; + char *home; + char *local; + char *p=NULL; char * mozilla_home=NULL; - int len; - - ev = getenv("LD_LIBRARY_PATH"); - if (!ev) { - ev = "/usr/lib:/lib"; - } - home = getenv("HOME"); - - /* - ** Augment the path automatically by adding in ~/.netscape and - ** /usr/local/netscape - */ - len = strlen(ev) + 1; /* +1 for the null */ - if (home && home[0]) { - len += strlen(home) + 1; /* +1 for the colon */ - } - - mozilla_home = getenv("MOZILLA_HOME"); - if (mozilla_home && mozilla_home[0]) { - len += strlen(mozilla_home) + 5 ; /* +5 for initial : and trailing "/lib" */ - } - - local = ":/usr/local/netscape/lib/" PR_LINKER_ARCH; - len += strlen(local); /* already got the : */ - p = (char*) PR_MALLOC(len+50); - if (p) { - strcpy(p, ev); - if (home) { - strcat(p, ":"); - strcat(p, home); - } + int len; + + ev = getenv("LD_LIBRARY_PATH"); + if (!ev) { + ev = "/usr/lib:/lib"; + } + home = getenv("HOME"); + + /* + ** Augment the path automatically by adding in ~/.netscape and + ** /usr/local/netscape + */ + len = strlen(ev) + 1; /* +1 for the null */ + if (home && home[0]) { + len += strlen(home) + 1; /* +1 for the colon */ + } + + mozilla_home = getenv("MOZILLA_HOME"); + if (mozilla_home && mozilla_home[0]) { + len += strlen(mozilla_home) + 5 ; /* +5 for initial : and trailing "/lib" */ + } + + local = ":/usr/local/netscape/lib/" PR_LINKER_ARCH; + len += strlen(local); /* already got the : */ + p = (char*) PR_MALLOC(len+50); + if (p) { + strcpy(p, ev); + if (home) { + strcat(p, ":"); + strcat(p, home); + } if (mozilla_home && mozilla_home[0]) { strcat(p, ":"); strcat(p, mozilla_home); strcat(p, "/lib"); } - strcat(p, local); - } /* if (p) */ - ev = p; - PR_LOG(_pr_io_lm, PR_LOG_NOTICE, ("linker path '%s'", ev)); + strcat(p, local); + } /* if (p) */ + ev = p; + PR_LOG(_pr_io_lm, PR_LOG_NOTICE, ("linker path '%s'", ev)); printf("linker_path = %s\n", ev); @@ -360,7 +367,7 @@ PR_GetLibraryName(const char *path, const char *lib) #ifdef XP_PC if (strstr(lib, PR_DLL_SUFFIX) == NULL) { - fullname = PR_smprintf("%s\\%s%s", path, lib, PR_DLL_SUFFIX); + fullname = PR_smprintf("%s\\%s%s", path, lib, PR_DLL_SUFFIX); } else { fullname = PR_smprintf("%s\\%s", path, lib); } @@ -395,23 +402,23 @@ pr_UnlockedFindLibrary(const char *name) const char* np = strrchr(name, PR_DIRECTORY_SEPARATOR); np = np ? np + 1 : name; while (lm) { - const char* cp = strrchr(lm->name, PR_DIRECTORY_SEPARATOR); - cp = cp ? cp + 1 : lm->name; + const char* cp = strrchr(lm->name, PR_DIRECTORY_SEPARATOR); + cp = cp ? cp + 1 : lm->name; #ifdef XP_PC /* Windows DLL names are case insensitive... */ - if (strcmpi(np, cp) == 0) + if (strcmpi(np, cp) == 0) #else - if (strcmp(np, cp) == 0) -#endif - { - /* found */ - lm->refCount++; - PR_LOG(_pr_linker_lm, PR_LOG_MIN, - ("%s incr => %d (find lib)", - lm->name, lm->refCount)); - return lm; - } - lm = lm->next; + if (strcmp(np, cp) == 0) +#endif + { + /* found */ + lm->refCount++; + PR_LOG(_pr_linker_lm, PR_LOG_MIN, + ("%s incr => %d (find lib)", + lm->name, lm->refCount)); + return lm; + } + lm = lm->next; } return NULL; } @@ -448,31 +455,31 @@ PR_LoadLibrary(const char *name) retry: ulRc = DosLoadModule(pszError, _MAX_PATH, (PSZ) name, &h); - if (ulRc != NO_ERROR) { - PR_DELETE(lm); - goto unlock; - } - lm->name = strdup(name); - lm->dlh = h; - lm->next = pr_loadmap; - pr_loadmap = lm; + if (ulRc != NO_ERROR) { + PR_DELETE(lm); + goto unlock; + } + lm->name = strdup(name); + lm->dlh = h; + lm->next = pr_loadmap; + pr_loadmap = lm; } #endif /* XP_OS2 */ #if defined(WIN32) || defined(WIN16) { - HINSTANCE h; + HINSTANCE h; NODL_PROC *pfn; - h = LoadLibrary(name); - if (h < (HINSTANCE)HINSTANCE_ERROR) { - PR_DELETE(lm); - goto unlock; - } - lm->name = strdup(name); - lm->dlh = h; - lm->next = pr_loadmap; - pr_loadmap = lm; + h = LoadLibrary(name); + if (h < (HINSTANCE)HINSTANCE_ERROR) { + PR_DELETE(lm); + goto unlock; + } + lm->name = strdup(name); + lm->dlh = h; + lm->next = pr_loadmap; + pr_loadmap = lm; /* ** Try to load a table of "static functions" provided by the DLL @@ -487,139 +494,139 @@ PR_LoadLibrary(const char *name) #if defined(XP_MAC) && GENERATINGCFM { - OSErr err; - Ptr main; - CFragConnectionID connectionID; - Str255 errName; - Str255 pName; - char cName[64]; - const char* libName; - - /* - * Algorithm: The "name" passed in could be either a shared - * library name that we should look for in the normal library - * search paths, or a full path name to a specific library on - * disk. Since the full path will always contain a ":" - * (shortest possible path is "Volume:File"), and since a - * library name can not contain a ":", we can test for the - * presence of a ":" to see which type of library we should load. - * or its a full UNIX path which we for now assume is Java - * enumerating all the paths (see below) - */ - if (strchr(name, PR_PATH_SEPARATOR) == NULL) - { - if (strchr(name, PR_DIRECTORY_SEPARATOR) == NULL) - { - /* - * The name did not contain a ":", so it must be a - * library name. Convert the name to a Pascal string - * and try to find the library. - */ - } - else - { - /* name contained a "/" which means we need to suck off the last part */ - /* of the path and pass that on the NSGetSharedLibrary */ - /* this may not be what we really want to do .. because Java could */ - /* be iterating through the whole LD path, and we'll find it if it's */ - /* anywhere on that path -- it appears that's what UNIX and the PC do */ - /* too...so we'll emulate but it could be wrong. */ - name = strrchr(name, PR_DIRECTORY_SEPARATOR) + 1; - } - - PStrFromCStr(name, pName); - - err = NSGetSharedLibrary(pName, &connectionID, &main); - if (err != noErr) - goto unlock; - - libName = name; - } - else - { - /* - * The name did contain a ":", so it must be a full path name. - * Now we have to do a lot of work to convert the path name to - * an FSSpec (silly, since we were probably just called from the - * MacFE plug-in code that already knew the FSSpec and converted - * it to a full path just to pass to us). First we copy out the - * volume name (the text leading up to the first ":"); then we - * separate the file name (the text following the last ":") from - * rest of the path. After converting the strings to Pascal - * format we can call GetCatInfo to get the parent directory ID - * of the file, and then (finally) make an FSSpec and call - * GetDiskFragment. - */ - char* cMacPath = NULL; - char* cFileName = NULL; - char* position = NULL; - CInfoPBRec pb; - FSSpec fileSpec; - PRUint32 index; - - /* Copy the name: we'll change it */ - cMacPath = strdup(name); - if (cMacPath == NULL) - goto unlock; - - /* First, get the vRefNum */ - position = strchr(cMacPath, PR_PATH_SEPARATOR); - if ((position == cMacPath) || (position == NULL)) - fileSpec.vRefNum = 0; /* Use application relative searching */ - else - { - char cVolName[32]; - memset(cVolName, 0, sizeof(cVolName)); - strncpy(cVolName, cMacPath, position-cMacPath); - fileSpec.vRefNum = GetVolumeRefNumFromName(cVolName); - } - - /* Next, break the path and file name apart */ - index = 0; - while (cMacPath[index] != 0) - index++; - while (cMacPath[index] != PR_PATH_SEPARATOR && index > 0) - index--; - if (index == 0 || index == strlen(cMacPath)) - { - PR_DELETE(cMacPath); - goto unlock; - } - cMacPath[index] = 0; - cFileName = &(cMacPath[index + 1]); - - /* Convert the path and name into Pascal strings */ - strcpy((char*) &pName, cMacPath); - c2pstr((char*) &pName); - strcpy((char*) &fileSpec.name, cFileName); - c2pstr((char*) &fileSpec.name); - strcpy(cName, cFileName); - PR_DELETE(cMacPath); - cMacPath = NULL; - - /* Now we can look up the path on the volume */ - pb.dirInfo.ioNamePtr = pName; - pb.dirInfo.ioVRefNum = fileSpec.vRefNum; - pb.dirInfo.ioDrDirID = 0; - pb.dirInfo.ioFDirIndex = 0; - err = PBGetCatInfoSync(&pb); - if (err != noErr) - goto unlock; - fileSpec.parID = pb.dirInfo.ioDrDirID; - - /* Finally, try to load the library */ - err = GetDiskFragment(&fileSpec, 0, kCFragGoesToEOF, fileSpec.name, - kLoadCFrag, &connectionID, &main, errName); - - libName = cName; - if (err != noErr) - goto unlock; - } - - lm->name = strdup(libName); - lm->dlh = connectionID; - lm->next = pr_loadmap; - pr_loadmap = lm; + OSErr err; + Ptr main; + CFragConnectionID connectionID; + Str255 errName; + Str255 pName; + char cName[64]; + const char* libName; + + /* + * Algorithm: The "name" passed in could be either a shared + * library name that we should look for in the normal library + * search paths, or a full path name to a specific library on + * disk. Since the full path will always contain a ":" + * (shortest possible path is "Volume:File"), and since a + * library name can not contain a ":", we can test for the + * presence of a ":" to see which type of library we should load. + * or its a full UNIX path which we for now assume is Java + * enumerating all the paths (see below) + */ + if (strchr(name, PR_PATH_SEPARATOR) == NULL) + { + if (strchr(name, PR_DIRECTORY_SEPARATOR) == NULL) + { + /* + * The name did not contain a ":", so it must be a + * library name. Convert the name to a Pascal string + * and try to find the library. + */ + } + else + { + /* name contained a "/" which means we need to suck off the last part */ + /* of the path and pass that on the NSGetSharedLibrary */ + /* this may not be what we really want to do .. because Java could */ + /* be iterating through the whole LD path, and we'll find it if it's */ + /* anywhere on that path -- it appears that's what UNIX and the PC do */ + /* too...so we'll emulate but it could be wrong. */ + name = strrchr(name, PR_DIRECTORY_SEPARATOR) + 1; + } + + PStrFromCStr(name, pName); + + err = NSGetSharedLibrary(pName, &connectionID, &main); + if (err != noErr) + goto unlock; + + libName = name; + } + else + { + /* + * The name did contain a ":", so it must be a full path name. + * Now we have to do a lot of work to convert the path name to + * an FSSpec (silly, since we were probably just called from the + * MacFE plug-in code that already knew the FSSpec and converted + * it to a full path just to pass to us). First we copy out the + * volume name (the text leading up to the first ":"); then we + * separate the file name (the text following the last ":") from + * rest of the path. After converting the strings to Pascal + * format we can call GetCatInfo to get the parent directory ID + * of the file, and then (finally) make an FSSpec and call + * GetDiskFragment. + */ + char* cMacPath = NULL; + char* cFileName = NULL; + char* position = NULL; + CInfoPBRec pb; + FSSpec fileSpec; + PRUint32 index; + + /* Copy the name: we'll change it */ + cMacPath = strdup(name); + if (cMacPath == NULL) + goto unlock; + + /* First, get the vRefNum */ + position = strchr(cMacPath, PR_PATH_SEPARATOR); + if ((position == cMacPath) || (position == NULL)) + fileSpec.vRefNum = 0; /* Use application relative searching */ + else + { + char cVolName[32]; + memset(cVolName, 0, sizeof(cVolName)); + strncpy(cVolName, cMacPath, position-cMacPath); + fileSpec.vRefNum = GetVolumeRefNumFromName(cVolName); + } + + /* Next, break the path and file name apart */ + index = 0; + while (cMacPath[index] != 0) + index++; + while (cMacPath[index] != PR_PATH_SEPARATOR && index > 0) + index--; + if (index == 0 || index == strlen(cMacPath)) + { + PR_DELETE(cMacPath); + goto unlock; + } + cMacPath[index] = 0; + cFileName = &(cMacPath[index + 1]); + + /* Convert the path and name into Pascal strings */ + strcpy((char*) &pName, cMacPath); + c2pstr((char*) &pName); + strcpy((char*) &fileSpec.name, cFileName); + c2pstr((char*) &fileSpec.name); + strcpy(cName, cFileName); + PR_DELETE(cMacPath); + cMacPath = NULL; + + /* Now we can look up the path on the volume */ + pb.dirInfo.ioNamePtr = pName; + pb.dirInfo.ioVRefNum = fileSpec.vRefNum; + pb.dirInfo.ioDrDirID = 0; + pb.dirInfo.ioFDirIndex = 0; + err = PBGetCatInfoSync(&pb); + if (err != noErr) + goto unlock; + fileSpec.parID = pb.dirInfo.ioDrDirID; + + /* Finally, try to load the library */ + err = GetDiskFragment(&fileSpec, 0, kCFragGoesToEOF, fileSpec.name, + kLoadCFrag, &connectionID, &main, errName); + + libName = cName; + if (err != noErr) + goto unlock; + } + + lm->name = strdup(libName); + lm->dlh = connectionID; + lm->next = pr_loadmap; + pr_loadmap = lm; } #elif defined(XP_MAC) && !GENERATINGCFM { @@ -631,14 +638,10 @@ PR_LoadLibrary(const char *name) #ifdef HAVE_DLL { #if defined(USE_DLFCN) - void *h = dlopen(name, RTLD_LAZY); + void *h = dlopen(name, RTLD_LAZY); #elif defined(USE_HPSHL) - /* - * Shared libraries built using aCC cannot be dynamically loaded - * with BIND_DEFERRED, so we have to use the BIND_IMMEDIATE flag. - */ - shl_t h = shl_load(name, BIND_IMMEDIATE | DYNAMIC_PATH, 0L); -#elif defined(USE_RLD) + shl_t h = shl_load(name, BIND_DEFERRED | DYNAMIC_PATH, 0L); +#elif defined(RHAPSODY) NSObjectFileImage ofi; NSModule h = NULL; if (NSCreateObjectFileImageFromFile(name, &ofi) @@ -648,20 +651,20 @@ PR_LoadLibrary(const char *name) #else #error Configuration error #endif - if (!h) { - PR_DELETE(lm); - goto unlock; - } - lm->name = strdup(name); - lm->dlh = h; - lm->next = pr_loadmap; - pr_loadmap = lm; + if (!h) { + PR_DELETE(lm); + goto unlock; + } + lm->name = strdup(name); + lm->dlh = h; + lm->next = pr_loadmap; + pr_loadmap = lm; } #endif /* HAVE_DLL */ #endif /* XP_UNIX */ lm->refCount = 1; - result = lm; /* success */ + result = lm; /* success */ PR_LOG(_pr_linker_lm, PR_LOG_MIN, ("Loaded library %s (load lib)", lm->name)); unlock: @@ -700,10 +703,10 @@ PR_UnloadLibrary(PRLibrary *lib) PR_EnterMonitor(pr_linker_lock); if (--lib->refCount > 0) { - PR_LOG(_pr_linker_lm, PR_LOG_MIN, - ("%s decr => %d", - lib->name, lib->refCount)); - goto done; + PR_LOG(_pr_linker_lm, PR_LOG_MIN, + ("%s decr => %d", + lib->name, lib->refCount)); + goto done; } #ifdef XP_UNIX #ifdef HAVE_DLL @@ -711,7 +714,7 @@ PR_UnloadLibrary(PRLibrary *lib) result = dlclose(lib->dlh); #elif defined(USE_HPSHL) result = shl_unload(lib->dlh); -#elif defined(USE_RLD) +#elif defined(RHAPSODY) result = NSUnLinkModule(lib->dlh, FALSE); #else #error Configuration error @@ -727,23 +730,23 @@ PR_UnloadLibrary(PRLibrary *lib) #if defined(XP_MAC) && GENERATINGCFM /* Close the connection */ - CloseConnection(&(lib->dlh)); + CloseConnection(&(lib->dlh)); #endif /* unlink from library search list */ if (pr_loadmap == lib) - pr_loadmap = pr_loadmap->next; + pr_loadmap = pr_loadmap->next; else if (pr_loadmap != NULL) { - PRLibrary* prev = pr_loadmap; - PRLibrary* next = pr_loadmap->next; - while (next != NULL) { - if (next == lib) { - prev->next = next->next; - goto freeLib; - } - prev = next; - next = next->next; - } + PRLibrary* prev = pr_loadmap; + PRLibrary* next = pr_loadmap->next; + while (next != NULL) { + if (next == lib) { + prev->next = next->next; + goto freeLib; + } + prev = next; + next = next->next; + } /* * fail (the library is not on the _pr_loadmap list), * but don't wipe out an error from dlclose/shl_unload. @@ -780,12 +783,12 @@ pr_FindSymbolInLib(PRLibrary *lm, const char *name) void *f = NULL; if (lm->staticTable != NULL) { - const PRStaticLinkTable* tp; - for (tp = lm->staticTable; tp->name; tp++) { - if (strcmp(name, tp->name) == 0) { - return (void*) tp->fp; - } - } + const PRStaticLinkTable* tp; + for (tp = lm->staticTable; tp->name; tp++) { + if (strcmp(name, tp->name) == 0) { + return (void*) tp->fp; + } + } /* ** If the symbol was not found in the static table then check if ** the symbol was exported in the DLL... Win16 only!! @@ -806,14 +809,14 @@ pr_FindSymbolInLib(PRLibrary *lm, const char *name) #ifdef XP_MAC { - Ptr symAddr; - CFragSymbolClass symClass; - Str255 pName; - - PStrFromCStr(name, pName); - - f = (NSFindSymbol(lm->dlh, pName, &symAddr, &symClass) == noErr) ? symAddr : NULL; - } + Ptr symAddr; + CFragSymbolClass symClass; + Str255 pName; + + PStrFromCStr(name, pName); + + f = (NSFindSymbol(lm->dlh, pName, &symAddr, &symClass) == noErr) ? symAddr : NULL; + } #endif /* XP_MAC */ #ifdef XP_UNIX @@ -821,9 +824,10 @@ pr_FindSymbolInLib(PRLibrary *lm, const char *name) #ifdef USE_DLFCN f = dlsym(lm->dlh, name); #elif defined(USE_HPSHL) - if (shl_findsym(&lm->dlh, name, TYPE_PROCEDURE, &f) == -1) - f = NULL; -#elif defined(USE_RLD) + if (shl_findsym(&lm->dlh, name, TYPE_PROCEDURE, &f) == -1) { + f = NULL; + } +#elif defined(RHAPSODY) f = NSAddressOfSymbol(NSLookupAndBindSymbol(name)); #endif #endif /* HAVE_DLL */ @@ -842,7 +846,7 @@ PR_IMPLEMENT(void*) PR_FindSymbol(PRLibrary *lib, const char *raw_name) { void *f = NULL; -#if defined(SUNOS4) || defined(WIN16) +#if defined(NEED_LEADING_UNDERSCORE) char *name; #else const char *name; @@ -850,7 +854,7 @@ PR_FindSymbol(PRLibrary *lib, const char *raw_name) /* ** Mangle the raw symbol name in any way that is platform specific. */ -#if defined(SUNOS4) || defined(RHAPSODY) +#if defined(NEED_LEADING_UNDERSCORE) /* Need a leading _ */ name = PR_smprintf("_%s", raw_name); #elif defined(AIX) @@ -860,11 +864,6 @@ PR_FindSymbol(PRLibrary *lib, const char *raw_name) ** figure. */ name = raw_name; -#elif defined(WIN16) - /* - ** Win16. symbols have a leading '_' - */ - name = PR_smprintf("_%s", raw_name); #else name = raw_name; #endif @@ -873,7 +872,7 @@ PR_FindSymbol(PRLibrary *lib, const char *raw_name) PR_ASSERT(lib != NULL); f = pr_FindSymbolInLib(lib, name); -#if defined(SUNOS4) || defined(WIN16) +#if defined(NEED_LEADING_UNDERSCORE) PR_smprintf_free(name); #endif @@ -885,7 +884,7 @@ PR_IMPLEMENT(void*) PR_FindSymbolAndLibrary(const char *raw_name, PRLibrary* *lib) { void *f = NULL; -#if defined(SUNOS4) || defined(WIN16) +#if defined(NEED_LEADING_UNDERSCORE) char *name; #else const char *name; @@ -895,7 +894,7 @@ PR_FindSymbolAndLibrary(const char *raw_name, PRLibrary* *lib) /* ** Mangle the raw symbol name in any way that is platform specific. */ -#if defined(SUNOS4) || defined(RHAPSODY) +#if defined(NEED_LEADING_UNDERSCORE) /* Need a leading _ */ name = PR_smprintf("_%s", raw_name); #elif defined(AIX) @@ -905,30 +904,25 @@ PR_FindSymbolAndLibrary(const char *raw_name, PRLibrary* *lib) ** figure. */ name = raw_name; -#elif defined(WIN16) - /* - ** Win16. symbols have a leading '_' - */ - name = PR_smprintf("_%s", raw_name); #else name = raw_name; #endif PR_EnterMonitor(pr_linker_lock); - /* search all libraries */ - for (lm = pr_loadmap; lm != NULL; lm = lm->next) { - f = pr_FindSymbolInLib(lm, name); - if (f != NULL) { - *lib = lm; - lm->refCount++; - PR_LOG(_pr_linker_lm, PR_LOG_MIN, - ("%s incr => %d (for %s)", - lm->name, lm->refCount, name)); - break; - } - } -#if defined(SUNOS4) || defined(WIN16) + /* search all libraries */ + for (lm = pr_loadmap; lm != NULL; lm = lm->next) { + f = pr_FindSymbolInLib(lm, name); + if (f != NULL) { + *lib = lm; + lm->refCount++; + PR_LOG(_pr_linker_lm, PR_LOG_MIN, + ("%s incr => %d (for %s)", + lm->name, lm->refCount, name)); + break; + } + } +#if defined(NEED_LEADING_UNDERSCORE) PR_smprintf_free(name); #endif @@ -970,7 +964,7 @@ PR_LoadStaticLibrary(const char *name, const PRStaticLinkTable *slt) lm->next = pr_loadmap; pr_loadmap = lm; - result = lm; /* success */ + result = lm; /* success */ PR_ASSERT(lm->refCount == 1); unlock: PR_LOG(_pr_linker_lm, PR_LOG_MIN, ("Loaded library %s (static lib)", lm->name)); diff --git a/pr/src/malloc/prmalloc.c b/pr/src/malloc/prmalloc.c index dc3b3983..61f50023 100644 --- a/pr/src/malloc/prmalloc.c +++ b/pr/src/malloc/prmalloc.c @@ -366,7 +366,7 @@ map_pages(int pages, int update) static int extend_page_directory(u_long index) { - struct pginfo **new,**old; + struct pginfo **young, **old; int i; TRACE(("%6d E %lu\n",malloc_event++,index)); @@ -377,13 +377,13 @@ extend_page_directory(u_long index) i += 2; /* Get new pages, if you used this much mem you don't care :-) */ - new = (struct pginfo**) map_pages(i,0); - if (!new) + young = (struct pginfo**) map_pages(i,0); + if (!young) return 0; /* Copy the old stuff */ - memset(new, 0, i * malloc_pagesize); - memcpy(new, page_dir, + memset(young, 0, i * malloc_pagesize); + memcpy(young, page_dir, malloc_ninfo * sizeof *page_dir); /* register the new size */ @@ -391,10 +391,10 @@ extend_page_directory(u_long index) /* swap the pointers */ old = page_dir; - page_dir = new; + page_dir = young; /* Mark the pages */ - index = ((u_long)new >> malloc_pageshift) - malloc_origo; + index = ((u_long)young >> malloc_pageshift) - malloc_origo; page_dir[index] = MALLOC_FIRST; while (--i) { page_dir[++index] = MALLOC_FOLLOW; @@ -590,7 +590,7 @@ static void *malloc_pages(size_t size) } if (delay_free) { if (!px) - px = delay_free; + px = (struct pgfree*)delay_free; else _PR_UnlockedFree(delay_free); } @@ -626,7 +626,7 @@ malloc_make_chunks(int bits) bp->shift = bits; bp->total = bp->free = malloc_pagesize >> bits; bp->next = page_dir[bits]; - bp->page = pp; + bp->page = (char*)pp; i = set_pgdir(pp,bp); if (!i) return 0; @@ -944,7 +944,7 @@ free_pages(char *ptr, u_long page, int index, struct pginfo *info) /* add to free-list */ if (!px) - px = _PR_UnlockedMalloc(sizeof *pt); + px = (struct pgfree*)_PR_UnlockedMalloc(sizeof *pt); /* XXX check success */ px->page = ptr; px->end = tail; @@ -1148,7 +1148,7 @@ void _PR_UnlockedFree(void *ptr) /* handle as page-allocation or chunk allocation */ info = page_dir[index]; if (info < MALLOC_MAGIC) - free_pages(ptr,page,index,info); + free_pages((char*)ptr, page, index, info); else free_bytes(ptr,page,index,info); return; diff --git a/pr/src/malloc/prmem.c b/pr/src/malloc/prmem.c index c9319216..c3fdcebc 100644 --- a/pr/src/malloc/prmem.c +++ b/pr/src/malloc/prmem.c @@ -116,6 +116,26 @@ static pthread_mutex_t _PR_MD_malloc_crustylock; #else /* _PR_PTHREADS */ static _MDLock _PR_MD_malloc_crustylock; +#ifdef IRIX +#define _PR_Lock_Malloc() { \ + PRIntn _is; \ + if(PR_TRUE == _PR_malloc_initialised) { \ + if (_PR_MD_GET_ATTACHED_THREAD() && \ + !_PR_IS_NATIVE_THREAD( \ + _PR_MD_GET_ATTACHED_THREAD())) \ + _PR_INTSOFF(_is); \ + _PR_MD_LOCK(&_PR_MD_malloc_crustylock); \ + } + +#define _PR_Unlock_Malloc() if(PR_TRUE == _PR_malloc_initialised) { \ + _PR_MD_UNLOCK(&_PR_MD_malloc_crustylock); \ + if (_PR_MD_GET_ATTACHED_THREAD() && \ + !_PR_IS_NATIVE_THREAD( \ + _PR_MD_GET_ATTACHED_THREAD())) \ + _PR_INTSON(_is); \ + } \ + } +#else /* IRIX */ #define _PR_Lock_Malloc() { \ PRIntn _is; \ if(PR_TRUE == _PR_malloc_initialised) { \ @@ -134,6 +154,7 @@ static _MDLock _PR_MD_malloc_crustylock; _PR_INTSON(_is); \ } \ } +#endif /* IRIX */ #endif /* _PR_PTHREADS */ PR_IMPLEMENT(PRStatus) _PR_MallocInit(void) diff --git a/pr/src/md/mac/macio.c b/pr/src/md/mac/macio.c index ae5aa2ff..8a1474f4 100644 --- a/pr/src/md/mac/macio.c +++ b/pr/src/md/mac/macio.c @@ -55,12 +55,12 @@ static void AsyncIOCompletion (ExtendedParamBlock *pbAsyncPtr) thread->md.notifyPending = PR_TRUE; return; } - _PR_SET_INTSOFF(1); + _PR_MD_SET_INTSOFF(1); thread->md.osErrCode = noErr; DoneWaitingOnThisThread(thread); - _PR_SET_INTSOFF(0); + _PR_MD_SET_INTSOFF(0); } @@ -393,7 +393,7 @@ ErrorExit: /* _MD_CLOSE_FILE, _MD_READ, _MD_WRITE, _MD_GET_FILE_ERROR are defined in _macos.h */ -PRInt32 _MD_LSeek(PRFileDesc *fd, PRInt32 offset, int how) +PRInt32 _MD_LSeek(PRFileDesc *fd, PRInt32 offset, PRSeekWhence how) { PRInt32 refNum = fd->secret->md.osfd; OSErr err = noErr; diff --git a/pr/src/md/mac/macsockclient.c b/pr/src/md/mac/macsockclient.c index 3ae9b0e5..93d3b100 100644 --- a/pr/src/md/mac/macsockclient.c +++ b/pr/src/md/mac/macsockclient.c @@ -457,90 +457,75 @@ ErrorExit: PRInt32 _MD_poll(PRPollDesc *pds, PRIntn npds, PRIntervalTime timeout) { - PRPollDesc *pd, *epd; - PRInt32 n; - + PRInt32 osfd; fd_set rd, wt, ex; + PRFileDesc *bottom; + PRPollDesc *pd, *epd; + PRInt32 ready, maxfd = -1; + PRInt16 in_flags, out_flags; struct timeval tv, *tvp = NULL; - int maxfd = -1; FD_ZERO(&rd); FD_ZERO(&wt); FD_ZERO(&ex); - for (pd = pds, epd = pd + npds; pd < epd; pd++) { - PRInt32 osfd; - PRInt16 in_flags = pd->in_flags; - PRFileDesc *bottom = pd->fd; - - if (NULL == bottom) { - continue; - } - while (bottom->lower != NULL) { - bottom = bottom->lower; - } - osfd = bottom->secret->md.osfd; - - if (osfd > maxfd) { - maxfd = osfd; - } - if (in_flags & PR_POLL_READ) { - FD_SET(osfd, &rd); - } - if (in_flags & PR_POLL_WRITE) { - FD_SET(osfd, &wt); - } - if (in_flags & PR_POLL_EXCEPT) { - FD_SET(osfd, &ex); + for (pd = pds, epd = pd + npds; pd < epd; pd++) + { + if (NULL == pd->fd) continue; + + in_flags = (bottom->methods->poll)(pd->fd, pd->in_flags, &pd->out_flags); + if (0 != (in_flags & pd->out_flags)) ready += 1; + else + { + bottom = PR_GetIdentitiesLayer(pd->fd, PR_NSPR_IO_LAYER); + PR_ASSERT(NULL != bottom); + osfd = bottom->secret->md.osfd; + + if (osfd > maxfd) maxfd = osfd; + if (in_flags & PR_POLL_READ) FD_SET(osfd, &rd); + if (in_flags & PR_POLL_WRITE) FD_SET(osfd, &wt); + if (in_flags & PR_POLL_EXCEPT) FD_SET(osfd, &ex); } } - if (timeout != PR_INTERVAL_NO_TIMEOUT) { - tv.tv_sec = PR_IntervalToSeconds(timeout); - tv.tv_usec = PR_IntervalToMicroseconds(timeout) % PR_USEC_PER_SEC; - tvp = &tv; - } + + if (timeout != PR_INTERVAL_NO_TIMEOUT) + { + PRInt32 ticksPerSecond = PR_TicksPerSecond(); + tv.tv_sec = timeout / ticksPerSecond; + tv.tv_usec = timeout - (ticksPerSecond * tv.tv_sec); + tv.tv_usec = (PR_USEC_PER_SEC * tv.tv_usec) / ticksPerSecond; + tvp = &tv; + } - n = select(maxfd + 1, &rd, &wt, &ex, tvp); + ready = select(maxfd + 1, &rd, &wt, &ex, tvp); - if (n > 0) { - n = 0; - for (pd = pds, epd = pd + npds; pd < epd; pd++) { - PRInt32 osfd; - PRInt16 in_flags = pd->in_flags; - PRInt16 out_flags = 0; - PRFileDesc *bottom = pd->fd; - - if (NULL == bottom) { - continue; - } - while (bottom->lower != NULL) { - bottom = bottom->lower; - } + if (ready > 0) + { + ready = 0; + for (pd = pds, epd = pd + npds; pd < epd; pd++) + { + out_flags = 0; + in_flags = pd->in_flags; + + if ((NULL == pd->fd) || (0 == in_flags)) continue; + bottom = PR_GetIdentitiesLayer(pd->fd, PR_NSPR_IO_LAYER); osfd = bottom->secret->md.osfd; - if ((in_flags & PR_POLL_READ) && FD_ISSET(osfd, &rd)) { - out_flags |= PR_POLL_READ; - } - if ((in_flags & PR_POLL_WRITE) && FD_ISSET(osfd, &wt)) { - out_flags |= PR_POLL_WRITE; - } - if ((in_flags & PR_POLL_EXCEPT) && FD_ISSET(osfd, &ex)) { - out_flags |= PR_POLL_EXCEPT; - } - pd->out_flags = out_flags; - if (out_flags) { - n++; - } + if (FD_ISSET(osfd, &ex)) out_flags |= PR_POLL_EXCEPT; + else if (FD_ISSET(osfd, &rd) || FD_ISSET(osfd, &wt)) + out_flags = pd->in_flags & (PR_POLL_READ | PR_POLL_WRITE); + pd->out_flags = out_flags; + if (out_flags) ready++; } /* Can't do this assert because MacSock returns write fds even if we did not set it in the original write fd set. */ - /*PR_ASSERT(n > 0);*/ - } else - PR_ASSERT(n == 0); + /*PR_ASSERT(ready > 0);*/ + } + else PR_ASSERT(ready == 0); - return n; + return ready; } int _MD_mac_get_nonblocking_connect_error(int osfd) diff --git a/pr/src/md/mac/macsockotpt.c b/pr/src/md/mac/macsockotpt.c index 04217a74..4af516cc 100644 --- a/pr/src/md/mac/macsockotpt.c +++ b/pr/src/md/mac/macsockotpt.c @@ -22,28 +22,28 @@ #include <Gestalt.h> /* - Since Apple put out new headers without - putting in a way to test for them, we found some random symbol which - isn't defined in the "1.1" headers. + Since Apple put out new headers without + putting in a way to test for them, we found some random symbol which + isn't defined in the "1.1" headers. */ #include <OpenTransport.h> #ifdef kOTInvalidStreamRef /* old */ -#define GESTALT_OPEN_TPT_PRESENT gestaltOpenTptPresent -#define GESTALT_OPEN_TPT_TCP_PRESENT gestaltOpenTptTCPPresent +#define GESTALT_OPEN_TPT_PRESENT gestaltOpenTptPresent +#define GESTALT_OPEN_TPT_TCP_PRESENT gestaltOpenTptTCPPresent #else /* new */ -#define GESTALT_OPEN_TPT_PRESENT gestaltOpenTptPresentMask -#define GESTALT_OPEN_TPT_TCP_PRESENT gestaltOpenTptTCPPresentMask +#define GESTALT_OPEN_TPT_PRESENT gestaltOpenTptPresentMask +#define GESTALT_OPEN_TPT_TCP_PRESENT gestaltOpenTptTCPPresentMask #endif -#include <OpenTptInternet.h> // All the internet typedefs +#include <OpenTptInternet.h> // All the internet typedefs #include "macsocket.h" #include "primpl.h" typedef enum SndRcvOpCode { kSTREAM_SEND, - kSTREAM_RECEIVE , + kSTREAM_RECEIVE , kDGRAM_SEND, kDGRAM_RECEIVE } SndRcvOpCode; @@ -52,7 +52,7 @@ typedef enum SndRcvOpCode { static InetSvcRef sSvcRef; static pascal void NotifierRoutine(void * contextPtr, OTEventCode code, - OTResult result, void * cookie); + OTResult result, void * cookie); static PRBool GetState(EndpointRef endpoint, PRBool *readReady, PRBool *writeReady, PRBool *exceptReady); @@ -61,130 +61,130 @@ extern void DoneWaitingOnThisThread(PRThread *thread); void _MD_InitNetAccess() { - OSErr err; - OSStatus errOT; - PRBool hasOTTCPIP = PR_FALSE; - PRBool hasOT = PR_FALSE; - long gestaltResult; - PRThread *me = _PR_MD_CURRENT_THREAD(); - - err = Gestalt(gestaltOpenTpt, &gestaltResult); - if (err == noErr) - if (gestaltResult & GESTALT_OPEN_TPT_PRESENT) - hasOT = PR_TRUE; - - if (hasOT) - if (gestaltResult & GESTALT_OPEN_TPT_TCP_PRESENT) - hasOTTCPIP = PR_TRUE; - - PR_ASSERT(hasOTTCPIP == PR_TRUE); - - errOT = InitOpenTransport(); - PR_ASSERT(err == kOTNoError); - - sSvcRef = OTOpenInternetServices(kDefaultInternetServicesPath, NULL, &errOT); - if (errOT != kOTNoError) return; /* no network -- oh well */ - PR_ASSERT((sSvcRef != NULL) && (errOT == kOTNoError)); + OSErr err; + OSStatus errOT; + PRBool hasOTTCPIP = PR_FALSE; + PRBool hasOT = PR_FALSE; + long gestaltResult; + PRThread *me = _PR_MD_CURRENT_THREAD(); + + err = Gestalt(gestaltOpenTpt, &gestaltResult); + if (err == noErr) + if (gestaltResult & GESTALT_OPEN_TPT_PRESENT) + hasOT = PR_TRUE; + + if (hasOT) + if (gestaltResult & GESTALT_OPEN_TPT_TCP_PRESENT) + hasOTTCPIP = PR_TRUE; + + PR_ASSERT(hasOTTCPIP == PR_TRUE); + + errOT = InitOpenTransport(); + PR_ASSERT(err == kOTNoError); + + sSvcRef = OTOpenInternetServices(kDefaultInternetServicesPath, NULL, &errOT); + if (errOT != kOTNoError) return; /* no network -- oh well */ + PR_ASSERT((sSvcRef != NULL) && (errOT == kOTNoError)); /* Install notify function for DNR Address To String completion */ - errOT = OTInstallNotifier(sSvcRef, NotifierRoutine, me); - PR_ASSERT(errOT == kOTNoError); + errOT = OTInstallNotifier(sSvcRef, NotifierRoutine, me); + PR_ASSERT(errOT == kOTNoError); /* Put us into async mode */ - errOT = OTSetAsynchronous(sSvcRef); - PR_ASSERT(errOT == kOTNoError); + errOT = OTSetAsynchronous(sSvcRef); + PR_ASSERT(errOT == kOTNoError); /* XXX Does not handle absence of open tpt and tcp yet! */ } static void macsock_map_error(OSStatus err) { - _PR_MD_CURRENT_THREAD()->md.osErrCode = err; - - if (IsEError(err) || (err >= EPERM && err <= ELASTERRNO)) { - switch (IsEError(err) ? OSStatus2E(err) : err) { - case EBADF: - PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); - break; - case EADDRNOTAVAIL: - PR_SetError(PR_ADDRESS_NOT_AVAILABLE_ERROR, err); - break; - case EINPROGRESS: - PR_SetError(PR_IN_PROGRESS_ERROR, err); - break; - case EWOULDBLOCK: - case EAGAIN: - PR_SetError(PR_WOULD_BLOCK_ERROR, err); - break; - case ENOTSOCK: - PR_SetError(PR_NOT_SOCKET_ERROR, err); - break; - case ETIMEDOUT: - PR_SetError(PR_IO_TIMEOUT_ERROR, err); - break; - case ECONNREFUSED: - PR_SetError(PR_CONNECT_REFUSED_ERROR, err); - break; - case ENETUNREACH: - PR_SetError(PR_NETWORK_UNREACHABLE_ERROR, err); - break; - case EADDRINUSE: - PR_SetError(PR_ADDRESS_IN_USE_ERROR, err); - break; - case EFAULT: - PR_SetError(PR_ACCESS_FAULT_ERROR, err); - break; - case EINTR: - PR_SetError(PR_PENDING_INTERRUPT_ERROR, err); - break; - case EINVAL: - PR_SetError(PR_INVALID_ARGUMENT_ERROR, err); - break; - case EIO: - PR_SetError(PR_IO_ERROR, err); - break; - case ENOENT: - PR_SetError(PR_ADDRESS_NOT_SUPPORTED_ERROR, err); - break; - case ENXIO: - PR_SetError(PR_IO_ERROR, err); - break; - case EPROTOTYPE: - PR_SetError(PR_PROTOCOL_NOT_SUPPORTED_ERROR, err); - break; - case EOPNOTSUPP: - PR_SetError(PR_OPERATION_NOT_SUPPORTED_ERROR, err); - break; - default: - PR_SetError(PR_UNKNOWN_ERROR, err); - break; - } - } else { - PR_ASSERT(IsXTIError(err)); - switch (err) { - case kOTNoDataErr: - case kOTFlowErr: - PR_SetError(PR_WOULD_BLOCK_ERROR, err); - break; - default: - PR_ASSERT(0); - PR_SetError(PR_UNKNOWN_ERROR, err); - break; - } - } + _PR_MD_CURRENT_THREAD()->md.osErrCode = err; + + if (IsEError(err) || (err >= EPERM && err <= ELASTERRNO)) { + switch (IsEError(err) ? OSStatus2E(err) : err) { + case EBADF: + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); + break; + case EADDRNOTAVAIL: + PR_SetError(PR_ADDRESS_NOT_AVAILABLE_ERROR, err); + break; + case EINPROGRESS: + PR_SetError(PR_IN_PROGRESS_ERROR, err); + break; + case EWOULDBLOCK: + case EAGAIN: + PR_SetError(PR_WOULD_BLOCK_ERROR, err); + break; + case ENOTSOCK: + PR_SetError(PR_NOT_SOCKET_ERROR, err); + break; + case ETIMEDOUT: + PR_SetError(PR_IO_TIMEOUT_ERROR, err); + break; + case ECONNREFUSED: + PR_SetError(PR_CONNECT_REFUSED_ERROR, err); + break; + case ENETUNREACH: + PR_SetError(PR_NETWORK_UNREACHABLE_ERROR, err); + break; + case EADDRINUSE: + PR_SetError(PR_ADDRESS_IN_USE_ERROR, err); + break; + case EFAULT: + PR_SetError(PR_ACCESS_FAULT_ERROR, err); + break; + case EINTR: + PR_SetError(PR_PENDING_INTERRUPT_ERROR, err); + break; + case EINVAL: + PR_SetError(PR_INVALID_ARGUMENT_ERROR, err); + break; + case EIO: + PR_SetError(PR_IO_ERROR, err); + break; + case ENOENT: + PR_SetError(PR_ADDRESS_NOT_SUPPORTED_ERROR, err); + break; + case ENXIO: + PR_SetError(PR_IO_ERROR, err); + break; + case EPROTOTYPE: + PR_SetError(PR_PROTOCOL_NOT_SUPPORTED_ERROR, err); + break; + case EOPNOTSUPP: + PR_SetError(PR_OPERATION_NOT_SUPPORTED_ERROR, err); + break; + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } + } else { + PR_ASSERT(IsXTIError(err)); + switch (err) { + case kOTNoDataErr: + case kOTFlowErr: + PR_SetError(PR_WOULD_BLOCK_ERROR, err); + break; + default: + PR_ASSERT(0); + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } + } } static void PrepareThreadForAsyncIO(PRThread *thread, EndpointRef endpoint, PRInt32 osfd) { - OSStatus err; + OSStatus err; thread->io_pending = PR_TRUE; thread->io_fd = osfd; thread->md.osErrCode = noErr; - OTRemoveNotifier(endpoint); - err = OTInstallNotifier(endpoint, NotifierRoutine, thread); - PR_ASSERT(err == kOTNoError); + OTRemoveNotifier(endpoint); + err = OTInstallNotifier(endpoint, NotifierRoutine, thread); + PR_ASSERT(err == kOTNoError); } // Notification routine @@ -192,96 +192,96 @@ static void PrepareThreadForAsyncIO(PRThread *thread, EndpointRef endpoint, PRIn // A5 is OK. Cannot allocate memory here pascal void NotifierRoutine(void * contextPtr, OTEventCode code, OTResult result, void * cookie) { - PRThread * thread = (PRThread *) contextPtr; - _PRCPU *cpu = _PR_MD_CURRENT_CPU(); - - switch (code) - { + PRThread * thread = (PRThread *) contextPtr; + _PRCPU *cpu = _PR_MD_CURRENT_CPU(); + + switch (code) + { // Async Completion Event - case T_OPENCOMPLETE: - case T_BINDCOMPLETE: - case T_UNBINDCOMPLETE: - case T_GETPROTADDRCOMPLETE: - case T_ACCEPTCOMPLETE: + case T_OPENCOMPLETE: + case T_BINDCOMPLETE: + case T_UNBINDCOMPLETE: + case T_GETPROTADDRCOMPLETE: + case T_ACCEPTCOMPLETE: // Connect callback - case T_CONNECT: + case T_CONNECT: // Standard or expedited data is available - case T_DATA: - case T_EXDATA: + case T_DATA: + case T_EXDATA: // Standard or expedited data Flow control lifted - case T_GODATA: - case T_GOEXDATA: + case T_GODATA: + case T_GOEXDATA: // Asynchronous Listen Event - case T_LISTEN: + case T_LISTEN: // DNR String To Address Complete Event - case T_DNRSTRINGTOADDRCOMPLETE: + case T_DNRSTRINGTOADDRCOMPLETE: // Option Management Request Complete Event - case T_OPTMGMTCOMPLETE: - thread->md.osErrCode = result; - thread->md.cookie = cookie; - if (_PR_MD_GET_INTSOFF()) { - cpu->u.missed[cpu->where] |= _PR_MISSED_IO; - thread->md.notifyPending = PR_TRUE; - return; - } - DoneWaitingOnThisThread(thread); - break; + case T_OPTMGMTCOMPLETE: + thread->md.osErrCode = result; + thread->md.cookie = cookie; + if (_PR_MD_GET_INTSOFF()) { + cpu->u.missed[cpu->where] |= _PR_MISSED_IO; + thread->md.notifyPending = PR_TRUE; + return; + } + DoneWaitingOnThisThread(thread); + break; // T_ORDREL orderly release is available; nothing to do - case T_ORDREL: - break; + case T_ORDREL: + break; // T_PASSCON; nothing to do - case T_PASSCON: - break; + case T_PASSCON: + break; // T_DISCONNECT; disconnect is available; nothing to do - case T_DISCONNECT: - break; + case T_DISCONNECT: + break; // UDP Send error; clear the error - case T_UDERR: - (void) OTRcvUDErr((EndpointRef) cookie, NULL); - break; - - default: - PR_ASSERT(0); - break; - } + case T_UDERR: + (void) OTRcvUDErr((EndpointRef) cookie, NULL); + break; + + default: + PR_ASSERT(0); + break; + } } static OSErr CreateSocket(int type, EndpointRef *endpoint) { - OSStatus err; - PRThread *me = _PR_MD_CURRENT_THREAD(); - - switch (type){ - case SOCK_STREAM: - err = OTAsyncOpenEndpoint(OTCreateConfiguration(kTCPName), 0, NULL, - NotifierRoutine, me); - break; - case SOCK_DGRAM: - err = OTAsyncOpenEndpoint(OTCreateConfiguration(kUDPName), 0, NULL, - NotifierRoutine, me); - break; - } - if (err != kOTNoError) - goto ErrorExit; + OSStatus err; + PRThread *me = _PR_MD_CURRENT_THREAD(); + + switch (type){ + case SOCK_STREAM: + err = OTAsyncOpenEndpoint(OTCreateConfiguration(kTCPName), 0, NULL, + NotifierRoutine, me); + break; + case SOCK_DGRAM: + err = OTAsyncOpenEndpoint(OTCreateConfiguration(kUDPName), 0, NULL, + NotifierRoutine, me); + break; + } + if (err != kOTNoError) + goto ErrorExit; - WaitOnThisThread(me, PR_INTERVAL_NO_TIMEOUT); + WaitOnThisThread(me, PR_INTERVAL_NO_TIMEOUT); - err = me->md.osErrCode; - if (err != kOTNoError) - goto ErrorExit; + err = me->md.osErrCode; + if (err != kOTNoError) + goto ErrorExit; - *endpoint = me->md.cookie; - PR_ASSERT(*endpoint != NULL); + *endpoint = me->md.cookie; + PR_ASSERT(*endpoint != NULL); - return kOTNoError; + return kOTNoError; ErrorExit: - return err; + return err; } @@ -291,52 +291,52 @@ ErrorExit: // ENOBUFS - not enough space for another socket, or failure in socket creation routine PRInt32 _MD_socket(int domain, int type, int protocol) { - OSStatus err; - EndpointRef endpoint; - - // We only deal with internet domain - if (domain != AF_INET) { - err = kEPROTONOSUPPORTErr; - goto ErrorExit; - } - - // We only know about tcp & udp - if ((type != SOCK_STREAM) && (type != SOCK_DGRAM)) { - err = kEPROTONOSUPPORTErr; - goto ErrorExit; - } - - // Convert default types to specific types. - if (protocol == 0) { - if (type == SOCK_DGRAM) - protocol = IPPROTO_UDP; - else if (type == SOCK_STREAM) - protocol = IPPROTO_TCP; - } - - // Only support default protocol for tcp - if ((type == SOCK_STREAM) && (protocol != IPPROTO_TCP)) { - err = kEPROTONOSUPPORTErr; - goto ErrorExit; - } - - // Only support default protocol for udp - if ((type == SOCK_DGRAM) && (protocol != IPPROTO_UDP)) { - err = kEPROTONOSUPPORTErr; - goto ErrorExit; - } - - // Create a socket, we might run out of memory - err = CreateSocket(type, &endpoint); - if (err != kOTNoError) - goto ErrorExit; - - PR_ASSERT((PRInt32)endpoint != -1); - - return ((PRInt32)endpoint); + OSStatus err; + EndpointRef endpoint; + + // We only deal with internet domain + if (domain != AF_INET) { + err = kEPROTONOSUPPORTErr; + goto ErrorExit; + } + + // We only know about tcp & udp + if ((type != SOCK_STREAM) && (type != SOCK_DGRAM)) { + err = kEPROTONOSUPPORTErr; + goto ErrorExit; + } + + // Convert default types to specific types. + if (protocol == 0) { + if (type == SOCK_DGRAM) + protocol = IPPROTO_UDP; + else if (type == SOCK_STREAM) + protocol = IPPROTO_TCP; + } + + // Only support default protocol for tcp + if ((type == SOCK_STREAM) && (protocol != IPPROTO_TCP)) { + err = kEPROTONOSUPPORTErr; + goto ErrorExit; + } + + // Only support default protocol for udp + if ((type == SOCK_DGRAM) && (protocol != IPPROTO_UDP)) { + err = kEPROTONOSUPPORTErr; + goto ErrorExit; + } + + // Create a socket, we might run out of memory + err = CreateSocket(type, &endpoint); + if (err != kOTNoError) + goto ErrorExit; + + PR_ASSERT((PRInt32)endpoint != -1); + + return ((PRInt32)endpoint); ErrorExit: - macsock_map_error(err); + macsock_map_error(err); return -1; } @@ -345,28 +345,28 @@ ErrorExit: // EFAULT -- bad address format PRInt32 _MD_bind(PRFileDesc *fd, PRNetAddr *addr, PRUint32 addrlen) { - PRInt32 osfd = fd->secret->md.osfd; - OSStatus err; - EndpointRef endpoint = (EndpointRef) osfd; - TBind bindReq; - PRThread *me = _PR_MD_CURRENT_THREAD(); - PRUint32 retryCount = 0; - - if (endpoint == NULL) { - err = kEBADFErr; - goto ErrorExit; - } - - if (addr == NULL) { - err = kEFAULTErr; - goto ErrorExit; - } - - // setup our request + PRInt32 osfd = fd->secret->md.osfd; + OSStatus err; + EndpointRef endpoint = (EndpointRef) osfd; + TBind bindReq; + PRThread *me = _PR_MD_CURRENT_THREAD(); + PRUint32 retryCount = 0; + + if (endpoint == NULL) { + err = kEBADFErr; + goto ErrorExit; + } + + if (addr == NULL) { + err = kEFAULTErr; + goto ErrorExit; + } + + // setup our request #if 0 - if ((addr->inet.port == 0) || (addr->inet.ip == 0)) - bindReq.addr.len = 0; - else + if ((addr->inet.port == 0) || (addr->inet.ip == 0)) + bindReq.addr.len = 0; + else #endif /* * There seems to be a bug with OT ralted to OTBind failing with kOTNoAddressErr eventhough @@ -375,36 +375,36 @@ PRInt32 _MD_bind(PRFileDesc *fd, PRNetAddr *addr, PRUint32 addrlen) */ TryAgain: - bindReq.addr.len = addrlen; - - bindReq.addr.maxlen = addrlen; - bindReq.addr.buf = (UInt8*) addr; - bindReq.qlen = 1; - - PrepareThreadForAsyncIO(me, endpoint, osfd); + bindReq.addr.len = addrlen; + + bindReq.addr.maxlen = addrlen; + bindReq.addr.buf = (UInt8*) addr; + bindReq.qlen = 1; + + PrepareThreadForAsyncIO(me, endpoint, osfd); - err = OTBind(endpoint, &bindReq, NULL); - if (err != kOTNoError) - goto ErrorExit; + err = OTBind(endpoint, &bindReq, NULL); + if (err != kOTNoError) + goto ErrorExit; - WaitOnThisThread(me, PR_INTERVAL_NO_TIMEOUT); + WaitOnThisThread(me, PR_INTERVAL_NO_TIMEOUT); - err = me->md.osErrCode; - if (err != kOTNoError) - goto ErrorExit; + err = me->md.osErrCode; + if (err != kOTNoError) + goto ErrorExit; - PR_ASSERT(me->md.cookie == NULL); + PR_ASSERT(me->md.cookie == NULL); - return kOTNoError; + return kOTNoError; ErrorExit: - if ((err == kOTNoAddressErr) && (++retryCount <= 4)) { - long finalTicks; - - Delay(100,&finalTicks); - goto TryAgain; - } - macsock_map_error(err); + if ((err == kOTNoAddressErr) && (++retryCount <= 4)) { + long finalTicks; + + Delay(100,&finalTicks); + goto TryAgain; + } + macsock_map_error(err); return -1; } @@ -413,77 +413,77 @@ ErrorExit: PRInt32 _MD_listen(PRFileDesc *fd, PRIntn backlog) { #if 0 - PRInt32 osfd = fd->secret->md.osfd; - OSStatus err; - EndpointRef endpoint = (EndpointRef) osfd; - TBind bindReq; - PRNetAddr addr; - PRThread *me = _PR_MD_CURRENT_THREAD(); - - if (backlog == 0) - backlog = 1; - - if (endpoint == NULL) { - err = EBADF; - goto ErrorExit; - } - - addr.inet.port = addr.inet.ip = 0; + PRInt32 osfd = fd->secret->md.osfd; + OSStatus err; + EndpointRef endpoint = (EndpointRef) osfd; + TBind bindReq; + PRNetAddr addr; + PRThread *me = _PR_MD_CURRENT_THREAD(); + + if (backlog == 0) + backlog = 1; + + if (endpoint == NULL) { + err = EBADF; + goto ErrorExit; + } + + addr.inet.port = addr.inet.ip = 0; - bindReq.addr.maxlen = PR_NETADDR_SIZE (&addr); - bindReq.addr.len = 0; - bindReq.addr.buf = (UInt8*) &addr; - bindReq.qlen = 0; - - PrepareThreadForAsyncIO(me, endpoint, osfd); + bindReq.addr.maxlen = PR_NETADDR_SIZE (&addr); + bindReq.addr.len = 0; + bindReq.addr.buf = (UInt8*) &addr; + bindReq.qlen = 0; + + PrepareThreadForAsyncIO(me, endpoint, osfd); - err = OTGetProtAddress(endpoint, &bindReq, NULL); - if (err != kOTNoError) - goto ErrorExit; + err = OTGetProtAddress(endpoint, &bindReq, NULL); + if (err != kOTNoError) + goto ErrorExit; - WaitOnThisThread(me, PR_INTERVAL_NO_TIMEOUT); + WaitOnThisThread(me, PR_INTERVAL_NO_TIMEOUT); - err = me->md.osErrCode; - if (err != kOTNoError) - goto ErrorExit; + err = me->md.osErrCode; + if (err != kOTNoError) + goto ErrorExit; - PrepareThreadForAsyncIO(me, endpoint, osfd); + PrepareThreadForAsyncIO(me, endpoint, osfd); - err = OTUnbind(endpoint); - if (err != kOTNoError) - goto ErrorExit; + err = OTUnbind(endpoint); + if (err != kOTNoError) + goto ErrorExit; - WaitOnThisThread(me, PR_INTERVAL_NO_TIMEOUT); + WaitOnThisThread(me, PR_INTERVAL_NO_TIMEOUT); - err = me->md.osErrCode; - if (err != kOTNoError) - goto ErrorExit; + err = me->md.osErrCode; + if (err != kOTNoError) + goto ErrorExit; - bindReq.qlen = backlog; - - PrepareThreadForAsyncIO(me, endpoint, osfd); + bindReq.qlen = backlog; + + PrepareThreadForAsyncIO(me, endpoint, osfd); - err = OTBind(endpoint, &bindReq, NULL); - if (err != kOTNoError) - goto ErrorExit; + err = OTBind(endpoint, &bindReq, NULL); + if (err != kOTNoError) + goto ErrorExit; - WaitOnThisThread(me, PR_INTERVAL_NO_TIMEOUT); + WaitOnThisThread(me, PR_INTERVAL_NO_TIMEOUT); - err = me->md.osErrCode; - if (err != kOTNoError) - goto ErrorExit; + err = me->md.osErrCode; + if (err != kOTNoError) + goto ErrorExit; - PR_ASSERT(me->md.cookie == NULL); + PR_ASSERT(me->md.cookie == NULL); - return kOTNoError; + return kOTNoError; ErrorExit: - macsock_map_error(err); + macsock_map_error(err); return -1; #endif -#pragma unused (fd, backlog) - return kOTNoError; +#pragma unused (fd, backlog) + return kOTNoError; } @@ -491,514 +491,514 @@ ErrorExit: // EBADF -- bad socket id PRInt32 _MD_getsockname(PRFileDesc *fd, PRNetAddr *addr, PRUint32 *addrlen) { - PRInt32 osfd = fd->secret->md.osfd; - OSStatus err; - EndpointRef endpoint = (EndpointRef) osfd; - TBind bindReq; - PRThread *me = _PR_MD_CURRENT_THREAD(); - - if (endpoint == NULL) { - err = kEBADFErr; - goto ErrorExit; - } - - if (addr == NULL) { - err = kEFAULTErr; - goto ErrorExit; - } - -#if !defined(_PR_INET6) - addr->inet.family = AF_INET; + PRInt32 osfd = fd->secret->md.osfd; + OSStatus err; + EndpointRef endpoint = (EndpointRef) osfd; + TBind bindReq; + PRThread *me = _PR_MD_CURRENT_THREAD(); + + if (endpoint == NULL) { + err = kEBADFErr; + goto ErrorExit; + } + + if (addr == NULL) { + err = kEFAULTErr; + goto ErrorExit; + } + +#if !defined(_PR_INET6) + addr->inet.family = AF_INET; #endif - - PR_ASSERT(PR_NETADDR_SIZE(addr) >= (*addrlen)); + + PR_ASSERT(PR_NETADDR_SIZE(addr) >= (*addrlen)); - bindReq.addr.len = *addrlen; - bindReq.addr.maxlen = *addrlen; - bindReq.addr.buf = (UInt8*) addr; - bindReq.qlen = 0; - - PrepareThreadForAsyncIO(me, endpoint, osfd); + bindReq.addr.len = *addrlen; + bindReq.addr.maxlen = *addrlen; + bindReq.addr.buf = (UInt8*) addr; + bindReq.qlen = 0; + + PrepareThreadForAsyncIO(me, endpoint, osfd); - err = OTGetProtAddress(endpoint, &bindReq, NULL); - if (err != kOTNoError) - goto ErrorExit; + err = OTGetProtAddress(endpoint, &bindReq, NULL); + if (err != kOTNoError) + goto ErrorExit; - WaitOnThisThread(me, PR_INTERVAL_NO_TIMEOUT); + WaitOnThisThread(me, PR_INTERVAL_NO_TIMEOUT); - err = me->md.osErrCode; - if (err != kOTNoError) - goto ErrorExit; + err = me->md.osErrCode; + if (err != kOTNoError) + goto ErrorExit; - PR_ASSERT(me->md.cookie == &bindReq); + PR_ASSERT(me->md.cookie == &bindReq); - return kOTNoError; + return kOTNoError; ErrorExit: - macsock_map_error(err); + macsock_map_error(err); return -1; } PRStatus _MD_getsockopt(PRFileDesc *fd, PRInt32 level, PRInt32 optname, char* optval, PRInt32* optlen) { - OSStatus err; - PRInt32 osfd = fd->secret->md.osfd; - EndpointRef endpoint = (EndpointRef) osfd; - TOptMgmt cmd; - TOption *opt; - PRThread *me = _PR_MD_CURRENT_THREAD(); - unsigned char optionBuffer[kOTOptionHeaderSize + sizeof(PRSocketOptionData)]; - - if (endpoint == NULL) { - err = kEBADFErr; - goto ErrorExit; - } - - /* - OT wants IPPROTO_IP for level and not XTI_GENERIC. SO_REUSEADDR and SO_KEEPALIVE - are equated to IP level and TCP level options respectively and hence we need to set - the level correctly. - */ - if (level == SOL_SOCKET) { - if (optname == SO_REUSEADDR) - level = IPPROTO_IP; - else if (optname == SO_KEEPALIVE) - level = INET_TCP; - } - - opt = (TOption *)&optionBuffer[0]; - opt->len = sizeof(TOption); - opt->level = level; - opt->name = optname; - opt->status = 0; - - cmd.opt.len = sizeof(TOption); - cmd.opt.maxlen = sizeof(optionBuffer); - cmd.opt.buf = (UInt8*)optionBuffer; - cmd.flags = T_CURRENT; - - PrepareThreadForAsyncIO(me, endpoint, osfd); - - err = OTOptionManagement(endpoint, &cmd, &cmd); - if (err != kOTNoError) - goto ErrorExit; - - WaitOnThisThread(me, PR_INTERVAL_NO_TIMEOUT); - - err = me->md.osErrCode; - if (err != kOTNoError) - goto ErrorExit; - - if (opt->status == T_FAILURE || opt->status == T_NOTSUPPORT){ - err = kEOPNOTSUPPErr; - goto ErrorExit; - } - - PR_ASSERT(opt->status == T_SUCCESS); - - switch (optname) { - case SO_LINGER: - *((t_linger*)optval) = *((t_linger*)&opt->value); - *optlen = sizeof(t_linger); - break; - case SO_REUSEADDR: - case TCP_NODELAY: - case SO_KEEPALIVE: - case SO_RCVBUF: - case SO_SNDBUF: - *((PRIntn*)optval) = *((PRIntn*)&opt->value); - *optlen = sizeof(PRIntn); - break; - case IP_MULTICAST_LOOP: - *((PRUint8*)optval) = *((PRIntn*)&opt->value); - *optlen = sizeof(PRUint8); - break; - case IP_TTL: - *((PRUintn*)optval) = *((PRUint8*)&opt->value); - *optlen = sizeof(PRUintn); - break; - case IP_MULTICAST_TTL: - *((PRUint8*)optval) = *((PRUint8*)&opt->value); - *optlen = sizeof(PRUint8); - break; - case IP_ADD_MEMBERSHIP: - case IP_DROP_MEMBERSHIP: - { - /* struct ip_mreq and TIPAddMulticast are the same size and optval - is pointing to struct ip_mreq */ - *((struct ip_mreq *)optval) = *((struct ip_mreq *)&opt->value); - *optlen = sizeof(struct ip_mreq); - break; - } - case IP_MULTICAST_IF: - { - *((PRUint32*)optval) = *((PRUint32*)&opt->value); - *optlen = sizeof(PRUint32); - break; - } - /*case IP_TOS:*/ /*IP_TOS has same value as TCP_MAXSEG */ - case TCP_MAXSEG: - if (level == IPPROTO_TCP) { /* it is TCP_MAXSEG */ - *((PRIntn*)optval) = *((PRIntn*)&opt->value); - *optlen = sizeof(PRIntn); - } else { /* it is IP_TOS */ - *((PRUintn*)optval) = *((PRUint8*)&opt->value); - *optlen = sizeof(PRUintn); - } - break; - default: - PR_ASSERT(0); - break; - } - - return PR_SUCCESS; + OSStatus err; + PRInt32 osfd = fd->secret->md.osfd; + EndpointRef endpoint = (EndpointRef) osfd; + TOptMgmt cmd; + TOption *opt; + PRThread *me = _PR_MD_CURRENT_THREAD(); + unsigned char optionBuffer[kOTOptionHeaderSize + sizeof(PRSocketOptionData)]; + + if (endpoint == NULL) { + err = kEBADFErr; + goto ErrorExit; + } + + /* + OT wants IPPROTO_IP for level and not XTI_GENERIC. SO_REUSEADDR and SO_KEEPALIVE + are equated to IP level and TCP level options respectively and hence we need to set + the level correctly. + */ + if (level == SOL_SOCKET) { + if (optname == SO_REUSEADDR) + level = IPPROTO_IP; + else if (optname == SO_KEEPALIVE) + level = INET_TCP; + } + + opt = (TOption *)&optionBuffer[0]; + opt->len = sizeof(TOption); + opt->level = level; + opt->name = optname; + opt->status = 0; + + cmd.opt.len = sizeof(TOption); + cmd.opt.maxlen = sizeof(optionBuffer); + cmd.opt.buf = (UInt8*)optionBuffer; + cmd.flags = T_CURRENT; + + PrepareThreadForAsyncIO(me, endpoint, osfd); + + err = OTOptionManagement(endpoint, &cmd, &cmd); + if (err != kOTNoError) + goto ErrorExit; + + WaitOnThisThread(me, PR_INTERVAL_NO_TIMEOUT); + + err = me->md.osErrCode; + if (err != kOTNoError) + goto ErrorExit; + + if (opt->status == T_FAILURE || opt->status == T_NOTSUPPORT){ + err = kEOPNOTSUPPErr; + goto ErrorExit; + } + + PR_ASSERT(opt->status == T_SUCCESS); + + switch (optname) { + case SO_LINGER: + *((t_linger*)optval) = *((t_linger*)&opt->value); + *optlen = sizeof(t_linger); + break; + case SO_REUSEADDR: + case TCP_NODELAY: + case SO_KEEPALIVE: + case SO_RCVBUF: + case SO_SNDBUF: + *((PRIntn*)optval) = *((PRIntn*)&opt->value); + *optlen = sizeof(PRIntn); + break; + case IP_MULTICAST_LOOP: + *((PRUint8*)optval) = *((PRIntn*)&opt->value); + *optlen = sizeof(PRUint8); + break; + case IP_TTL: + *((PRUintn*)optval) = *((PRUint8*)&opt->value); + *optlen = sizeof(PRUintn); + break; + case IP_MULTICAST_TTL: + *((PRUint8*)optval) = *((PRUint8*)&opt->value); + *optlen = sizeof(PRUint8); + break; + case IP_ADD_MEMBERSHIP: + case IP_DROP_MEMBERSHIP: + { + /* struct ip_mreq and TIPAddMulticast are the same size and optval + is pointing to struct ip_mreq */ + *((struct ip_mreq *)optval) = *((struct ip_mreq *)&opt->value); + *optlen = sizeof(struct ip_mreq); + break; + } + case IP_MULTICAST_IF: + { + *((PRUint32*)optval) = *((PRUint32*)&opt->value); + *optlen = sizeof(PRUint32); + break; + } + /*case IP_TOS:*/ /*IP_TOS has same value as TCP_MAXSEG */ + case TCP_MAXSEG: + if (level == IPPROTO_TCP) { /* it is TCP_MAXSEG */ + *((PRIntn*)optval) = *((PRIntn*)&opt->value); + *optlen = sizeof(PRIntn); + } else { /* it is IP_TOS */ + *((PRUintn*)optval) = *((PRUint8*)&opt->value); + *optlen = sizeof(PRUintn); + } + break; + default: + PR_ASSERT(0); + break; + } + + return PR_SUCCESS; ErrorExit: - macsock_map_error(err); + macsock_map_error(err); return PR_FAILURE; } PRStatus _MD_setsockopt(PRFileDesc *fd, PRInt32 level, PRInt32 optname, const char* optval, PRInt32 optlen) { - OSStatus err; - PRInt32 osfd = fd->secret->md.osfd; - EndpointRef endpoint = (EndpointRef) osfd; - TOptMgmt cmd; - TOption *opt; - PRThread *me = _PR_MD_CURRENT_THREAD(); - unsigned char optionBuffer[kOTOptionHeaderSize + sizeof(PRSocketOptionData) + 1]; - - if (endpoint == NULL) { - err = kEBADFErr; - goto ErrorExit; - } - - /* - OT wants IPPROTO_IP for level and not XTI_GENERIC. SO_REUSEADDR and SO_KEEPALIVE - are equated to IP level and TCP level options respectively and hence we need to set - the level correctly. - */ - if (level == SOL_SOCKET) { - if (optname == SO_REUSEADDR) - level = IPPROTO_IP; - else if (optname == SO_KEEPALIVE) - level = INET_TCP; - } - - opt = (TOption *)&optionBuffer[0]; - opt->len = kOTOptionHeaderSize + optlen; - - /* special case adjustments for length follow */ - if (optname == SO_KEEPALIVE) /* we need to pass the timeout value for OT */ - opt->len = kOTOptionHeaderSize + sizeof(t_kpalive); - if (optname == IP_MULTICAST_TTL || optname == IP_TTL) /* it is an unsigned char value */ - opt->len = kOTOneByteOptionSize; - if (optname == IP_TOS && level == IPPROTO_IP) - opt->len = kOTOneByteOptionSize; - - opt->level = level; - opt->name = optname; - opt->status = 0; - - cmd.opt.len = opt->len; - cmd.opt.maxlen = sizeof(optionBuffer); - cmd.opt.buf = (UInt8*)optionBuffer; - - optionBuffer[opt->len] = 0; - - cmd.flags = T_NEGOTIATE; - - switch (optname) { - case SO_LINGER: - *((t_linger*)&opt->value) = *((t_linger*)optval); - break; - case SO_REUSEADDR: - case TCP_NODELAY: - case SO_RCVBUF: - case SO_SNDBUF: - *((PRIntn*)&opt->value) = *((PRIntn*)optval); - break; - case IP_MULTICAST_LOOP: - if (*optval != 0) - opt->value[0] = T_YES; - else - opt->value[0] = T_NO; - break; - case SO_KEEPALIVE: - { - t_kpalive *kpalive = (t_kpalive *)&opt->value; - - kpalive->kp_onoff = *((long*)optval); - kpalive->kp_timeout = 10; /* timeout in minutes */ - break; - } - case IP_TTL: - *((unsigned char*)&opt->value) = *((PRUintn*)optval); - break; - case IP_MULTICAST_TTL: - *((unsigned char*)&opt->value) = *optval; - break; - case IP_ADD_MEMBERSHIP: - case IP_DROP_MEMBERSHIP: - { - /* struct ip_mreq and TIPAddMulticast are the same size and optval - is pointing to struct ip_mreq */ - *((TIPAddMulticast *)&opt->value) = *((TIPAddMulticast *)optval); - break; - } - case IP_MULTICAST_IF: - { - *((PRUint32*)&opt->value) = *((PRUint32*)optval); - break; - } - /*case IP_TOS:*/ /*IP_TOS has same value as TCP_MAXSEG */ - case TCP_MAXSEG: - if (level == IPPROTO_TCP) { /* it is TCP_MAXSEG */ - *((PRIntn*)&opt->value) = *((PRIntn*)optval); - } else { /* it is IP_TOS */ - *((unsigned char*)&opt->value) = *((PRUintn*)optval); - } - break; - default: - PR_ASSERT(0); - break; - } - - PrepareThreadForAsyncIO(me, endpoint, osfd); - - err = OTOptionManagement(endpoint, &cmd, &cmd); - if (err != kOTNoError) - goto ErrorExit; - - WaitOnThisThread(me, PR_INTERVAL_NO_TIMEOUT); - - err = me->md.osErrCode; - if (err != kOTNoError) - goto ErrorExit; - - if (opt->status == T_FAILURE || opt->status == T_NOTSUPPORT){ - err = kEOPNOTSUPPErr; - goto ErrorExit; - } - - if (level == IPPROTO_TCP && optname == TCP_MAXSEG && opt->status == T_READONLY) { - err = kEOPNOTSUPPErr; - goto ErrorExit; - } - - PR_ASSERT(opt->status == T_SUCCESS); - - return PR_SUCCESS; + OSStatus err; + PRInt32 osfd = fd->secret->md.osfd; + EndpointRef endpoint = (EndpointRef) osfd; + TOptMgmt cmd; + TOption *opt; + PRThread *me = _PR_MD_CURRENT_THREAD(); + unsigned char optionBuffer[kOTOptionHeaderSize + sizeof(PRSocketOptionData) + 1]; + + if (endpoint == NULL) { + err = kEBADFErr; + goto ErrorExit; + } + + /* + OT wants IPPROTO_IP for level and not XTI_GENERIC. SO_REUSEADDR and SO_KEEPALIVE + are equated to IP level and TCP level options respectively and hence we need to set + the level correctly. + */ + if (level == SOL_SOCKET) { + if (optname == SO_REUSEADDR) + level = IPPROTO_IP; + else if (optname == SO_KEEPALIVE) + level = INET_TCP; + } + + opt = (TOption *)&optionBuffer[0]; + opt->len = kOTOptionHeaderSize + optlen; + + /* special case adjustments for length follow */ + if (optname == SO_KEEPALIVE) /* we need to pass the timeout value for OT */ + opt->len = kOTOptionHeaderSize + sizeof(t_kpalive); + if (optname == IP_MULTICAST_TTL || optname == IP_TTL) /* it is an unsigned char value */ + opt->len = kOTOneByteOptionSize; + if (optname == IP_TOS && level == IPPROTO_IP) + opt->len = kOTOneByteOptionSize; + + opt->level = level; + opt->name = optname; + opt->status = 0; + + cmd.opt.len = opt->len; + cmd.opt.maxlen = sizeof(optionBuffer); + cmd.opt.buf = (UInt8*)optionBuffer; + + optionBuffer[opt->len] = 0; + + cmd.flags = T_NEGOTIATE; + + switch (optname) { + case SO_LINGER: + *((t_linger*)&opt->value) = *((t_linger*)optval); + break; + case SO_REUSEADDR: + case TCP_NODELAY: + case SO_RCVBUF: + case SO_SNDBUF: + *((PRIntn*)&opt->value) = *((PRIntn*)optval); + break; + case IP_MULTICAST_LOOP: + if (*optval != 0) + opt->value[0] = T_YES; + else + opt->value[0] = T_NO; + break; + case SO_KEEPALIVE: + { + t_kpalive *kpalive = (t_kpalive *)&opt->value; + + kpalive->kp_onoff = *((long*)optval); + kpalive->kp_timeout = 10; /* timeout in minutes */ + break; + } + case IP_TTL: + *((unsigned char*)&opt->value) = *((PRUintn*)optval); + break; + case IP_MULTICAST_TTL: + *((unsigned char*)&opt->value) = *optval; + break; + case IP_ADD_MEMBERSHIP: + case IP_DROP_MEMBERSHIP: + { + /* struct ip_mreq and TIPAddMulticast are the same size and optval + is pointing to struct ip_mreq */ + *((TIPAddMulticast *)&opt->value) = *((TIPAddMulticast *)optval); + break; + } + case IP_MULTICAST_IF: + { + *((PRUint32*)&opt->value) = *((PRUint32*)optval); + break; + } + /*case IP_TOS:*/ /*IP_TOS has same value as TCP_MAXSEG */ + case TCP_MAXSEG: + if (level == IPPROTO_TCP) { /* it is TCP_MAXSEG */ + *((PRIntn*)&opt->value) = *((PRIntn*)optval); + } else { /* it is IP_TOS */ + *((unsigned char*)&opt->value) = *((PRUintn*)optval); + } + break; + default: + PR_ASSERT(0); + break; + } + + PrepareThreadForAsyncIO(me, endpoint, osfd); + + err = OTOptionManagement(endpoint, &cmd, &cmd); + if (err != kOTNoError) + goto ErrorExit; + + WaitOnThisThread(me, PR_INTERVAL_NO_TIMEOUT); + + err = me->md.osErrCode; + if (err != kOTNoError) + goto ErrorExit; + + if (opt->status == T_FAILURE || opt->status == T_NOTSUPPORT){ + err = kEOPNOTSUPPErr; + goto ErrorExit; + } + + if (level == IPPROTO_TCP && optname == TCP_MAXSEG && opt->status == T_READONLY) { + err = kEOPNOTSUPPErr; + goto ErrorExit; + } + + PR_ASSERT(opt->status == T_SUCCESS); + + return PR_SUCCESS; ErrorExit: - macsock_map_error(err); + macsock_map_error(err); return PR_FAILURE; } PRInt32 _MD_socketavailable(PRFileDesc *fd) { - PRInt32 osfd = fd->secret->md.osfd; - OSStatus err; - EndpointRef endpoint = (EndpointRef) osfd; - size_t bytes; - - if (endpoint == NULL) { - err = kEBADFErr; - goto ErrorExit; - } - - bytes = 0; - - err = OTCountDataBytes(endpoint, &bytes); - if ((err == kOTLookErr) || // Not really errors, we just need to do a read, - (err == kOTNoDataErr)) // or thereÕs nothing there. - err = kOTNoError; - - if (err != kOTNoError) - goto ErrorExit; - - return bytes; + PRInt32 osfd = fd->secret->md.osfd; + OSStatus err; + EndpointRef endpoint = (EndpointRef) osfd; + size_t bytes; + + if (endpoint == NULL) { + err = kEBADFErr; + goto ErrorExit; + } + + bytes = 0; + + err = OTCountDataBytes(endpoint, &bytes); + if ((err == kOTLookErr) || // Not really errors, we just need to do a read, + (err == kOTNoDataErr)) // or thereÕs nothing there. + err = kOTNoError; + + if (err != kOTNoError) + goto ErrorExit; + + return bytes; ErrorExit: - macsock_map_error(err); + macsock_map_error(err); return -1; } PRInt32 _MD_accept(PRFileDesc *fd, PRNetAddr *addr, PRUint32 *addrlen, PRIntervalTime timeout) { - PRInt32 osfd = fd->secret->md.osfd; - OSStatus err; - EndpointRef endpoint = (EndpointRef) osfd; - PRThread *me = _PR_MD_CURRENT_THREAD(); - TBind bindReq; - PRNetAddr bindAddr; - PRInt32 newosfd = -1; - EndpointRef newEndpoint; - TCall call; - PRNetAddr callAddr; - - if (endpoint == NULL) { - err = kEBADFErr; - goto ErrorExit; - } - - memset(&call, 0 , sizeof(call)); - - call.addr.maxlen = PR_NETADDR_SIZE(&callAddr); - call.addr.len = PR_NETADDR_SIZE(&callAddr); - call.addr.buf = (UInt8*) &callAddr; - - PrepareThreadForAsyncIO(me, endpoint, osfd); - - err = OTListen (endpoint, &call); - if (err != kOTNoError && (err != kOTNoDataErr || fd->secret->nonblocking)) { - me->io_pending = PR_FALSE; - goto ErrorExit; - } - - while (err == kOTNoDataErr) { - WaitOnThisThread(me, timeout); - err = me->md.osErrCode; - if (err != kOTNoError) - goto ErrorExit; - - PrepareThreadForAsyncIO(me, endpoint, osfd); - - err = OTListen (endpoint, &call); - if (err == kOTNoError) - break; - - PR_ASSERT(err == kOTNoDataErr); - } - - newosfd = _MD_socket(AF_INET, SOCK_STREAM, 0); - if (newosfd == -1) - return -1; - - newEndpoint = (EndpointRef)newosfd; - - // Bind to a local port; let the system assign it. - - bindAddr.inet.port = bindAddr.inet.ip = 0; - - bindReq.addr.maxlen = PR_NETADDR_SIZE (&bindAddr); - bindReq.addr.len = 0; - bindReq.addr.buf = (UInt8*) &bindAddr; - bindReq.qlen = 0; - - PrepareThreadForAsyncIO(me, newEndpoint, newosfd); - - err = OTBind(newEndpoint, &bindReq, NULL); - if (err != kOTNoError) - goto ErrorExit; - - WaitOnThisThread(me, timeout); - - err = me->md.osErrCode; - if (err != kOTNoError) - goto ErrorExit; - - PrepareThreadForAsyncIO(me, endpoint, newosfd); - - err = OTAccept (endpoint, newEndpoint, &call); - if (err != kOTNoError) - goto ErrorExit; - - WaitOnThisThread(me, timeout); - - err = me->md.osErrCode; - if (err != kOTNoError) - goto ErrorExit; - - PR_ASSERT(me->md.cookie != NULL); - - if (addr != NULL) - *addr = callAddr; - if (addrlen != NULL) - *addrlen = call.addr.len; - - return newosfd; + PRInt32 osfd = fd->secret->md.osfd; + OSStatus err; + EndpointRef endpoint = (EndpointRef) osfd; + PRThread *me = _PR_MD_CURRENT_THREAD(); + TBind bindReq; + PRNetAddr bindAddr; + PRInt32 newosfd = -1; + EndpointRef newEndpoint; + TCall call; + PRNetAddr callAddr; + + if (endpoint == NULL) { + err = kEBADFErr; + goto ErrorExit; + } + + memset(&call, 0 , sizeof(call)); + + call.addr.maxlen = PR_NETADDR_SIZE(&callAddr); + call.addr.len = PR_NETADDR_SIZE(&callAddr); + call.addr.buf = (UInt8*) &callAddr; + + PrepareThreadForAsyncIO(me, endpoint, osfd); + + err = OTListen (endpoint, &call); + if (err != kOTNoError && (err != kOTNoDataErr || fd->secret->nonblocking)) { + me->io_pending = PR_FALSE; + goto ErrorExit; + } + + while (err == kOTNoDataErr) { + WaitOnThisThread(me, timeout); + err = me->md.osErrCode; + if (err != kOTNoError) + goto ErrorExit; + + PrepareThreadForAsyncIO(me, endpoint, osfd); + + err = OTListen (endpoint, &call); + if (err == kOTNoError) + break; + + PR_ASSERT(err == kOTNoDataErr); + } + + newosfd = _MD_socket(AF_INET, SOCK_STREAM, 0); + if (newosfd == -1) + return -1; + + newEndpoint = (EndpointRef)newosfd; + + // Bind to a local port; let the system assign it. + + bindAddr.inet.port = bindAddr.inet.ip = 0; + + bindReq.addr.maxlen = PR_NETADDR_SIZE (&bindAddr); + bindReq.addr.len = 0; + bindReq.addr.buf = (UInt8*) &bindAddr; + bindReq.qlen = 0; + + PrepareThreadForAsyncIO(me, newEndpoint, newosfd); + + err = OTBind(newEndpoint, &bindReq, NULL); + if (err != kOTNoError) + goto ErrorExit; + + WaitOnThisThread(me, timeout); + + err = me->md.osErrCode; + if (err != kOTNoError) + goto ErrorExit; + + PrepareThreadForAsyncIO(me, endpoint, newosfd); + + err = OTAccept (endpoint, newEndpoint, &call); + if (err != kOTNoError) + goto ErrorExit; + + WaitOnThisThread(me, timeout); + + err = me->md.osErrCode; + if (err != kOTNoError) + goto ErrorExit; + + PR_ASSERT(me->md.cookie != NULL); + + if (addr != NULL) + *addr = callAddr; + if (addrlen != NULL) + *addrlen = call.addr.len; + + return newosfd; ErrorExit: - if (newosfd != -1) - _MD_closesocket(newosfd); - macsock_map_error(err); + if (newosfd != -1) + _MD_closesocket(newosfd); + macsock_map_error(err); return -1; } PRInt32 _MD_connect(PRFileDesc *fd, PRNetAddr *addr, PRUint32 addrlen, PRIntervalTime timeout) { - PRInt32 osfd = fd->secret->md.osfd; - OSStatus err; - EndpointRef endpoint = (EndpointRef) osfd; - PRThread *me = _PR_MD_CURRENT_THREAD(); - TCall sndCall; - TBind bindReq; - PRNetAddr bindAddr; - - if (endpoint == NULL) { - err = kEBADFErr; - goto ErrorExit; - } - - if (addr == NULL) { - err = kEFAULTErr; - goto ErrorExit; - } - - // Bind to a local port; let the system assign it. - - bindAddr.inet.port = bindAddr.inet.ip = 0; - - bindReq.addr.maxlen = PR_NETADDR_SIZE (&bindAddr); - bindReq.addr.len = 0; - bindReq.addr.buf = (UInt8*) &bindAddr; - bindReq.qlen = 0; - - PrepareThreadForAsyncIO(me, endpoint, osfd); - - err = OTBind(endpoint, &bindReq, NULL); - if (err != kOTNoError) - goto ErrorExit; - - WaitOnThisThread(me, PR_INTERVAL_NO_TIMEOUT); - - err = me->md.osErrCode; - if (err != kOTNoError) - goto ErrorExit; - - memset(&sndCall, 0 , sizeof(sndCall)); - - sndCall.addr.maxlen = addrlen; - sndCall.addr.len = addrlen; - sndCall.addr.buf = (UInt8*) addr; - - PrepareThreadForAsyncIO(me, endpoint, osfd); - - err = OTConnect (endpoint, &sndCall, NULL); - if (err != kOTNoError && err != kOTNoDataErr) - goto ErrorExit; - if (err == kOTNoDataErr && fd->secret->nonblocking) { - err = kEINPROGRESSErr; - me->io_pending = PR_FALSE; - goto ErrorExit; - } - - WaitOnThisThread(me, timeout); - - err = me->md.osErrCode; - if (err != kOTNoError) - goto ErrorExit; - - PR_ASSERT(me->md.cookie != NULL); - - err = OTRcvConnect(endpoint, NULL); - PR_ASSERT(err == kOTNoError); - - return kOTNoError; + PRInt32 osfd = fd->secret->md.osfd; + OSStatus err; + EndpointRef endpoint = (EndpointRef) osfd; + PRThread *me = _PR_MD_CURRENT_THREAD(); + TCall sndCall; + TBind bindReq; + PRNetAddr bindAddr; + + if (endpoint == NULL) { + err = kEBADFErr; + goto ErrorExit; + } + + if (addr == NULL) { + err = kEFAULTErr; + goto ErrorExit; + } + + // Bind to a local port; let the system assign it. + + bindAddr.inet.port = bindAddr.inet.ip = 0; + + bindReq.addr.maxlen = PR_NETADDR_SIZE (&bindAddr); + bindReq.addr.len = 0; + bindReq.addr.buf = (UInt8*) &bindAddr; + bindReq.qlen = 0; + + PrepareThreadForAsyncIO(me, endpoint, osfd); + + err = OTBind(endpoint, &bindReq, NULL); + if (err != kOTNoError) + goto ErrorExit; + + WaitOnThisThread(me, PR_INTERVAL_NO_TIMEOUT); + + err = me->md.osErrCode; + if (err != kOTNoError) + goto ErrorExit; + + memset(&sndCall, 0 , sizeof(sndCall)); + + sndCall.addr.maxlen = addrlen; + sndCall.addr.len = addrlen; + sndCall.addr.buf = (UInt8*) addr; + + PrepareThreadForAsyncIO(me, endpoint, osfd); + + err = OTConnect (endpoint, &sndCall, NULL); + if (err != kOTNoError && err != kOTNoDataErr) + goto ErrorExit; + if (err == kOTNoDataErr && fd->secret->nonblocking) { + err = kEINPROGRESSErr; + me->io_pending = PR_FALSE; + goto ErrorExit; + } + + WaitOnThisThread(me, timeout); + + err = me->md.osErrCode; + if (err != kOTNoError) + goto ErrorExit; + + PR_ASSERT(me->md.cookie != NULL); + + err = OTRcvConnect(endpoint, NULL); + PR_ASSERT(err == kOTNoError); + + return kOTNoError; ErrorExit: - macsock_map_error(err); + macsock_map_error(err); return -1; } @@ -1008,93 +1008,93 @@ ErrorExit: static PRInt32 SendReceiveStream(PRFileDesc *fd, void *buf, PRInt32 amount, PRIntn flags, PRIntervalTime timeout, SndRcvOpCode opCode) { - OSStatus err; - OTResult result; - PRInt32 osfd = fd->secret->md.osfd; - EndpointRef endpoint = (EndpointRef) osfd; - PRThread *me = _PR_MD_CURRENT_THREAD(); - PRInt32 bytesLeft = amount; - - PR_ASSERT(flags == 0); - - if (endpoint == NULL) { - err = kEBADFErr; - goto ErrorExit; - } - - if (buf == NULL) { - err = kEFAULTErr; - goto ErrorExit; - } - - if (opCode != kSTREAM_SEND && opCode != kSTREAM_RECEIVE) { - err = kEINVALErr; - goto ErrorExit; - } - - while (bytesLeft > 0) { - - PrepareThreadForAsyncIO(me, endpoint, osfd); - - if (opCode == kSTREAM_SEND) - result = OTSnd(endpoint, buf, bytesLeft, NULL); - else - result = OTRcv(endpoint, buf, bytesLeft, NULL); - - if (result > 0) { - buf = (void *) ( (UInt32) buf + (UInt32)result ); - bytesLeft -= result; - me->io_pending = PR_FALSE; - if (opCode == kSTREAM_RECEIVE) - return result; - } else { - if (result == kOTOutStateErr) { /* it has been closed */ - me->io_pending = PR_FALSE; - return 0; - } - if (result == kOTLookErr) { - PRBool readReady,writeReady,exceptReady; - /* process the event and then continue the operation */ - (void) GetState(endpoint, &readReady, &writeReady, &exceptReady); - continue; - } - if (result != kOTNoDataErr && result != kOTFlowErr && - result != kEAGAINErr && result != kEWOULDBLOCKErr) { - me->io_pending = PR_FALSE; - err = result; - goto ErrorExit; - } else if (fd->secret->nonblocking) { - me->io_pending = PR_FALSE; - err = result; - goto ErrorExit; - } - WaitOnThisThread(me, timeout); - me->io_pending = PR_FALSE; - err = me->md.osErrCode; - if (err != kOTNoError) - goto ErrorExit; - - PR_ASSERT(me->md.cookie != NULL); - } - } - - return amount; + OSStatus err; + OTResult result; + PRInt32 osfd = fd->secret->md.osfd; + EndpointRef endpoint = (EndpointRef) osfd; + PRThread *me = _PR_MD_CURRENT_THREAD(); + PRInt32 bytesLeft = amount; + + PR_ASSERT(flags == 0); + + if (endpoint == NULL) { + err = kEBADFErr; + goto ErrorExit; + } + + if (buf == NULL) { + err = kEFAULTErr; + goto ErrorExit; + } + + if (opCode != kSTREAM_SEND && opCode != kSTREAM_RECEIVE) { + err = kEINVALErr; + goto ErrorExit; + } + + while (bytesLeft > 0) { + + PrepareThreadForAsyncIO(me, endpoint, osfd); + + if (opCode == kSTREAM_SEND) + result = OTSnd(endpoint, buf, bytesLeft, NULL); + else + result = OTRcv(endpoint, buf, bytesLeft, NULL); + + if (result > 0) { + buf = (void *) ( (UInt32) buf + (UInt32)result ); + bytesLeft -= result; + me->io_pending = PR_FALSE; + if (opCode == kSTREAM_RECEIVE) + return result; + } else { + if (result == kOTOutStateErr) { /* it has been closed */ + me->io_pending = PR_FALSE; + return 0; + } + if (result == kOTLookErr) { + PRBool readReady,writeReady,exceptReady; + /* process the event and then continue the operation */ + (void) GetState(endpoint, &readReady, &writeReady, &exceptReady); + continue; + } + if (result != kOTNoDataErr && result != kOTFlowErr && + result != kEAGAINErr && result != kEWOULDBLOCKErr) { + me->io_pending = PR_FALSE; + err = result; + goto ErrorExit; + } else if (fd->secret->nonblocking) { + me->io_pending = PR_FALSE; + err = result; + goto ErrorExit; + } + WaitOnThisThread(me, timeout); + me->io_pending = PR_FALSE; + err = me->md.osErrCode; + if (err != kOTNoError) + goto ErrorExit; + + PR_ASSERT(me->md.cookie != NULL); + } + } + + return amount; ErrorExit: - macsock_map_error(err); + macsock_map_error(err); return -1; } PRInt32 _MD_recv(PRFileDesc *fd, void *buf, PRInt32 amount, PRIntn flags, PRIntervalTime timeout) { - return (SendReceiveStream(fd, buf, amount, flags, timeout, kSTREAM_RECEIVE)); + return (SendReceiveStream(fd, buf, amount, flags, timeout, kSTREAM_RECEIVE)); } PRInt32 _MD_send(PRFileDesc *fd,const void *buf, PRInt32 amount, PRIntn flags, PRIntervalTime timeout) { - return (SendReceiveStream(fd, (void *)buf, amount, flags, timeout, kSTREAM_SEND)); + return (SendReceiveStream(fd, (void *)buf, amount, flags, timeout, kSTREAM_SEND)); } @@ -1105,72 +1105,72 @@ static PRInt32 SendReceiveDgram(PRFileDesc *fd, void *buf, PRInt32 amount, PRIntn flags, PRNetAddr *addr, PRUint32 *addrlen, PRIntervalTime timeout, SndRcvOpCode opCode) { - OSStatus err; - PRInt32 osfd = fd->secret->md.osfd; - EndpointRef endpoint = (EndpointRef) osfd; - PRThread *me = _PR_MD_CURRENT_THREAD(); - PRInt32 bytesLeft = amount; - TUnitData dgram; - - PR_ASSERT(flags == 0); - - if (endpoint == NULL) { - err = kEBADFErr; - goto ErrorExit; - } - - if (buf == NULL || addr == NULL) { - err = kEFAULTErr; - goto ErrorExit; - } - - if (opCode != kDGRAM_SEND && opCode != kDGRAM_RECEIVE) { - err = kEINVALErr; - goto ErrorExit; - } - - memset(&dgram, 0 , sizeof(dgram)); - dgram.addr.maxlen = *addrlen; - dgram.addr.len = *addrlen; - dgram.addr.buf = (UInt8*) addr; - dgram.udata.maxlen = amount; - dgram.udata.len = amount; - dgram.udata.buf = (UInt8*) buf; - - while (bytesLeft > 0) { - - PrepareThreadForAsyncIO(me, endpoint, osfd); - - if (opCode == kDGRAM_SEND) - err = OTSndUData(endpoint, &dgram); - else - err = OTRcvUData(endpoint, &dgram, NULL); - - if (err == kOTNoError) { - buf = (void *) ( (UInt32) buf + (UInt32)dgram.udata.len ); - bytesLeft -= dgram.udata.len; - dgram.udata.buf = (UInt8*) buf; - me->io_pending = PR_FALSE; - } - else { - PR_ASSERT(err == kOTNoDataErr || err == kOTOutStateErr); - WaitOnThisThread(me, timeout); - me->io_pending = PR_FALSE; - err = me->md.osErrCode; - if (err != kOTNoError) - goto ErrorExit; - - PR_ASSERT(me->md.cookie != NULL); - } - } - - if (opCode == kDGRAM_RECEIVE) - *addrlen = dgram.addr.len; - - return amount; + OSStatus err; + PRInt32 osfd = fd->secret->md.osfd; + EndpointRef endpoint = (EndpointRef) osfd; + PRThread *me = _PR_MD_CURRENT_THREAD(); + PRInt32 bytesLeft = amount; + TUnitData dgram; + + PR_ASSERT(flags == 0); + + if (endpoint == NULL) { + err = kEBADFErr; + goto ErrorExit; + } + + if (buf == NULL || addr == NULL) { + err = kEFAULTErr; + goto ErrorExit; + } + + if (opCode != kDGRAM_SEND && opCode != kDGRAM_RECEIVE) { + err = kEINVALErr; + goto ErrorExit; + } + + memset(&dgram, 0 , sizeof(dgram)); + dgram.addr.maxlen = *addrlen; + dgram.addr.len = *addrlen; + dgram.addr.buf = (UInt8*) addr; + dgram.udata.maxlen = amount; + dgram.udata.len = amount; + dgram.udata.buf = (UInt8*) buf; + + while (bytesLeft > 0) { + + PrepareThreadForAsyncIO(me, endpoint, osfd); + + if (opCode == kDGRAM_SEND) + err = OTSndUData(endpoint, &dgram); + else + err = OTRcvUData(endpoint, &dgram, NULL); + + if (err == kOTNoError) { + buf = (void *) ( (UInt32) buf + (UInt32)dgram.udata.len ); + bytesLeft -= dgram.udata.len; + dgram.udata.buf = (UInt8*) buf; + me->io_pending = PR_FALSE; + } + else { + PR_ASSERT(err == kOTNoDataErr || err == kOTOutStateErr); + WaitOnThisThread(me, timeout); + me->io_pending = PR_FALSE; + err = me->md.osErrCode; + if (err != kOTNoError) + goto ErrorExit; + + PR_ASSERT(me->md.cookie != NULL); + } + } + + if (opCode == kDGRAM_RECEIVE) + *addrlen = dgram.addr.len; + + return amount; ErrorExit: - macsock_map_error(err); + macsock_map_error(err); return -1; } @@ -1178,69 +1178,69 @@ PRInt32 _MD_recvfrom(PRFileDesc *fd, void *buf, PRInt32 amount, PRIntn flags, PRNetAddr *addr, PRUint32 *addrlen, PRIntervalTime timeout) { - return (SendReceiveDgram(fd, buf, amount, flags, addr, addrlen, - timeout, kDGRAM_RECEIVE)); + return (SendReceiveDgram(fd, buf, amount, flags, addr, addrlen, + timeout, kDGRAM_RECEIVE)); } PRInt32 _MD_sendto(PRFileDesc *fd,const void *buf, PRInt32 amount, PRIntn flags, PRNetAddr *addr, PRUint32 addrlen, PRIntervalTime timeout) { - return (SendReceiveDgram(fd, (void *)buf, amount, flags, addr, &addrlen, - timeout, kDGRAM_SEND)); + return (SendReceiveDgram(fd, (void *)buf, amount, flags, addr, &addrlen, + timeout, kDGRAM_SEND)); } PRInt32 _MD_closesocket(PRInt32 osfd) { - OSStatus err; - EndpointRef endpoint = (EndpointRef) osfd; - PRThread *me = _PR_MD_CURRENT_THREAD(); - - if (endpoint == NULL) { - err = kEBADFErr; - goto ErrorExit; - } - - if (me->io_pending && me->io_fd == osfd) - me->io_pending = PR_FALSE; + OSStatus err; + EndpointRef endpoint = (EndpointRef) osfd; + PRThread *me = _PR_MD_CURRENT_THREAD(); + + if (endpoint == NULL) { + err = kEBADFErr; + goto ErrorExit; + } + + if (me->io_pending && me->io_fd == osfd) + me->io_pending = PR_FALSE; #if 0 - { - OTResult state; - state = OTGetEndpointState(endpoint); - - err = OTSndOrderlyDisconnect(endpoint); - if (err != kOTNoError && err != kOTOutStateErr) - goto ErrorExit; - - state = OTGetEndpointState(endpoint); - - err = OTUnbind(endpoint); - if (err != kOTNoError && err != kOTOutStateErr) - goto ErrorExit; - - state = OTGetEndpointState(endpoint); - - err = OTSetSynchronous(endpoint); - if (err != kOTNoError) - goto ErrorExit; - - err = OTSetBlocking(endpoint); - if (err != kOTNoError) - goto ErrorExit; - } + { + OTResult state; + state = OTGetEndpointState(endpoint); + + err = OTSndOrderlyDisconnect(endpoint); + if (err != kOTNoError && err != kOTOutStateErr) + goto ErrorExit; + + state = OTGetEndpointState(endpoint); + + err = OTUnbind(endpoint); + if (err != kOTNoError && err != kOTOutStateErr) + goto ErrorExit; + + state = OTGetEndpointState(endpoint); + + err = OTSetSynchronous(endpoint); + if (err != kOTNoError) + goto ErrorExit; + + err = OTSetBlocking(endpoint); + if (err != kOTNoError) + goto ErrorExit; + } #endif - (void) OTSndOrderlyDisconnect(endpoint); + (void) OTSndOrderlyDisconnect(endpoint); - err = OTCloseProvider(endpoint); - if (err != kOTNoError) - goto ErrorExit; + err = OTCloseProvider(endpoint); + if (err != kOTNoError) + goto ErrorExit; - return kOTNoError; + return kOTNoError; ErrorExit: - macsock_map_error(err); + macsock_map_error(err); return -1; } @@ -1248,128 +1248,161 @@ PRInt32 _MD_writev(PRFileDesc *fd, struct PRIOVec *iov, PRInt32 iov_size, PRInte { #pragma unused (fd, iov, iov_size, timeout) - PR_ASSERT(0); - _PR_MD_CURRENT_THREAD()->md.osErrCode = unimpErr; + PR_ASSERT(0); + _PR_MD_CURRENT_THREAD()->md.osErrCode = unimpErr; return -1; } static PRBool GetState(EndpointRef endpoint, PRBool *readReady, PRBool *writeReady, PRBool *exceptReady) { - OSStatus err; - OTResult resultOT; - TDiscon discon; - PRBool result = PR_FALSE; - - *readReady = *writeReady = *exceptReady = PR_FALSE; - - resultOT = OTLook(endpoint); - switch (resultOT) { - case T_DATA: - case T_LISTEN: - *readReady = PR_TRUE; - break; - case T_CONNECT: - err = OTRcvConnect(endpoint, NULL); - PR_ASSERT(err == kOTNoError); - break; - case T_DISCONNECT: - memset(&discon, 0 , sizeof(discon)); - err = OTRcvDisconnect(endpoint, &discon); - PR_ASSERT(err == kOTNoError); - macsock_map_error(discon.reason); - *exceptReady = PR_TRUE; - break; - case T_ORDREL: - *readReady = PR_TRUE; - err = OTRcvOrderlyDisconnect(endpoint); - PR_ASSERT(err == kOTNoError); - break; - } - resultOT = OTGetEndpointState(endpoint); - switch (resultOT) { - case T_DATAXFER: - case T_INREL: - *writeReady = PR_TRUE; - break; - default: - *writeReady = PR_FALSE; - } - - if ((*readReady == PR_TRUE) || (*writeReady==PR_TRUE) || (*exceptReady==PR_TRUE)) - result = PR_TRUE; - - return result; + OSStatus err; + OTResult resultOT; + TDiscon discon; + PRBool result = PR_FALSE; + + *readReady = *writeReady = *exceptReady = PR_FALSE; + + resultOT = OTLook(endpoint); + switch (resultOT) { + case T_DATA: + case T_LISTEN: + *readReady = PR_TRUE; + break; + case T_CONNECT: + err = OTRcvConnect(endpoint, NULL); + PR_ASSERT(err == kOTNoError); + break; + case T_DISCONNECT: + memset(&discon, 0 , sizeof(discon)); + err = OTRcvDisconnect(endpoint, &discon); + PR_ASSERT(err == kOTNoError); + macsock_map_error(discon.reason); + *exceptReady = PR_TRUE; + break; + case T_ORDREL: + *readReady = PR_TRUE; + err = OTRcvOrderlyDisconnect(endpoint); + PR_ASSERT(err == kOTNoError); + break; + } + resultOT = OTGetEndpointState(endpoint); + switch (resultOT) { + case T_DATAXFER: + case T_INREL: + *writeReady = PR_TRUE; + break; + default: + *writeReady = PR_FALSE; + } + + if ((*readReady == PR_TRUE) || (*writeReady==PR_TRUE) || (*exceptReady==PR_TRUE)) + result = PR_TRUE; + + return result; } PRInt32 _MD_poll(PRPollDesc *pds, PRIntn npds, PRIntervalTime timeout) { + PRInt32 ready = 0; PRPollDesc *pd, *epd; - PRInt32 n = 0; - PRThread *me = _PR_MD_CURRENT_THREAD(); - PRIntervalTime sleepTime; - PRIntervalTime timein = PR_IntervalNow(); - - sleepTime = PR_MillisecondsToInterval(5UL); - if (sleepTime > timeout) - sleepTime = timeout; - - do { - - for (pd = pds, epd = pd + npds; pd < epd; pd++) { - PRInt32 osfd; - PRInt16 in_flags = pd->in_flags; - PRFileDesc *bottom = pd->fd; - EndpointRef endpoint; - PRInt16 out_flags = 0; - PRBool readReady, writeReady, exceptReady; - - pd->out_flags = 0; - if (NULL == bottom || in_flags == 0) { - continue; - } - while (bottom->lower != NULL) { - bottom = bottom->lower; - } - osfd = bottom->secret->md.osfd; - endpoint = (EndpointRef) osfd; - - if (GetState(endpoint, &readReady, &writeReady, &exceptReady)) { - - if ((in_flags & PR_POLL_READ) && (readReady)) { - out_flags |= PR_POLL_READ; - } - if ((in_flags & PR_POLL_WRITE) && (writeReady)) { - out_flags |= PR_POLL_WRITE; - } - if ((in_flags & PR_POLL_EXCEPT) && (exceptReady)) { - out_flags |= PR_POLL_EXCEPT; - } - pd->out_flags = out_flags; - if (out_flags) { - n++; - } - } + PRIntervalTime sleepTime, timein; + + sleepTime = PR_MillisecondsToInterval(5UL); + if (PR_INTERVAL_NO_TIMEOUT != timeout) + { + if (sleepTime > timeout) sleepTime = timeout; + timein = PR_IntervalNow(); } - if (n > 0) - return n; + do + { + for (pd = pds, epd = pd + npds; pd < epd; pd++) + { + PRInt16 in_flags_read = 0, in_flags_write = 0; + PRInt16 out_flags_read = 0, out_flags_write = 0; + + if (NULL == pd->fd || pd->in_flags == 0) continue; + + if (pd->in_flags & PR_POLL_READ) + { + in_flags_read = (pd->fd->methods->poll)( + pd->fd, pd->in_flags & ~PR_POLL_WRITE, &out_flags_read); + } + if (pd->in_flags & PR_POLL_WRITE) + { + in_flags_write = (pd->fd->methods->poll)( + pd->fd, pd->in_flags & ~PR_POLL_READ, &out_flags_write); + } + if ((0 != (in_flags_read & out_flags_read)) + || (0 != (in_flags_write & out_flags_write))) + { + ready += 1; /* some layer has buffer input */ + pd->out_flags = out_flags_read | out_flags_write; + } + else + { + PRFileDesc *bottom; + EndpointRef endpoint; + PRBool readReady, writeReady, exceptReady; + + pd->out_flags = 0; /* pre-condition */ + bottom = PR_GetIdentitiesLayer(pd->fd, PR_NSPR_IO_LAYER); + PR_ASSERT(NULL != bottom); + if ((NULL != bottom) + && (_PR_FILEDESC_OPEN == bottom->secret->state)) + { + endpoint = (EndpointRef)bottom->secret->md.osfd; + + if (GetState(endpoint, + &readReady, &writeReady, &exceptReady)) + { + if (readReady) + { + if (in_flags_read & PR_POLL_READ) + pd->out_flags |= PR_POLL_READ; + if (in_flags_write & PR_POLL_READ) + pd->out_flags |= PR_POLL_WRITE; + } + if (writeReady) + { + if (in_flags_read & PR_POLL_WRITE) + pd->out_flags |= PR_POLL_READ; + if (in_flags_write & PR_POLL_WRITE) + pd->out_flags |= PR_POLL_WRITE; + } + if (exceptReady && (pd->in_flags & PR_POLL_EXCEPT)) + { + pd->out_flags |= PR_POLL_EXCEPT; + } + if (0 != pd->out_flags) ready++; + } + } + else + { + ready += 1; /* this will cause an abrupt return */ + pd->out_flags = PR_POLL_NVAL; /* bogii */ + } + } + } - (void) PR_Sleep(sleepTime); + if (ready > 0) return ready; - } while ((timeout == PR_INTERVAL_NO_TIMEOUT) || - (((PRIntervalTime)(PR_IntervalNow() - timein)) < timeout)); + (void) PR_Sleep(sleepTime); - return 0; /* timed out */ + } while ((timeout == PR_INTERVAL_NO_TIMEOUT) || + (((PRIntervalTime)(PR_IntervalNow() - timein)) < timeout)); + + return 0; /* timed out */ } void _MD_makenonblock(PRFileDesc *fd) { - OSStatus err; - PRInt32 osfd = fd->secret->md.osfd; - EndpointRef endpoint = (EndpointRef) osfd; + OSStatus err; + PRInt32 osfd = fd->secret->md.osfd; + EndpointRef endpoint = (EndpointRef) osfd; err = OTSetNonBlocking(endpoint); - PR_ASSERT(err == kOTNoError || err == kOTOutStateErr); + PR_ASSERT(err == kOTNoError || err == kOTOutStateErr); } PR_IMPLEMENT(PRInt32) _MD_shutdown(PRFileDesc *fd, PRIntn how) @@ -1384,21 +1417,21 @@ PR_IMPLEMENT(PRStatus) _MD_getpeername(PRFileDesc *fd, PRNetAddr *addr, PRUint32 { #pragma unused (fd, addr, addrlen) - PR_ASSERT(0); - _PR_MD_CURRENT_THREAD()->md.osErrCode = unimpErr; - return PR_FAILURE; + PR_ASSERT(0); + _PR_MD_CURRENT_THREAD()->md.osErrCode = unimpErr; + return PR_FAILURE; } PR_IMPLEMENT(unsigned long) inet_addr(const char *cp) { - OSStatus err; - InetHost host; + OSStatus err; + InetHost host; - err = OTInetStringToHost((char*) cp, &host); - PR_ASSERT(err == kOTNoError); - - return host; + err = OTInetStringToHost((char*) cp, &host); + PR_ASSERT(err == kOTNoError); + + return host; } @@ -1409,31 +1442,31 @@ static InetHost *sAddresses[kMaxHostAddrs+1]; PR_IMPLEMENT(struct hostent *) gethostbyname(const char * name) { - OSStatus err; - PRUint32 index; - PRThread *me = _PR_MD_CURRENT_THREAD(); + OSStatus err; + PRUint32 index; + PRThread *me = _PR_MD_CURRENT_THREAD(); - PrepareThreadForAsyncIO(me, sSvcRef, NULL); + PrepareThreadForAsyncIO(me, sSvcRef, NULL); err = OTInetStringToAddress(sSvcRef, (char *)name, &sHostInfo); - if (err != kOTNoError) { - me->io_pending = PR_FALSE; - me->md.osErrCode = err; - goto ErrorExit; - } + if (err != kOTNoError) { + me->io_pending = PR_FALSE; + me->md.osErrCode = err; + goto ErrorExit; + } - WaitOnThisThread(me, PR_INTERVAL_NO_TIMEOUT); + WaitOnThisThread(me, PR_INTERVAL_NO_TIMEOUT); - if (me->md.osErrCode != kOTNoError) - goto ErrorExit; + if (me->md.osErrCode != kOTNoError) + goto ErrorExit; - sHostEnt.h_name = sHostInfo.name; - for (index=0; index<kMaxHostAddrs && sHostInfo.addrs[index] != NULL; index++) - sAddresses[index] = &sHostInfo.addrs[index]; - sAddresses[index] = NULL; - sHostEnt.h_addr_list = (char **)sAddresses; + sHostEnt.h_name = sHostInfo.name; + for (index=0; index<kMaxHostAddrs && sHostInfo.addrs[index] != NULL; index++) + sAddresses[index] = &sHostInfo.addrs[index]; + sAddresses[index] = NULL; + sHostEnt.h_addr_list = (char **)sAddresses; - return (&sHostEnt); + return (&sHostEnt); ErrorExit: return NULL; @@ -1442,57 +1475,57 @@ ErrorExit: PR_IMPLEMENT(struct hostent *) gethostbyaddr(const void *addr, int addrlen, int type) { - PR_ASSERT(type == AF_INET); - PR_ASSERT(addrlen == sizeof(struct in_addr)); + PR_ASSERT(type == AF_INET); + PR_ASSERT(addrlen == sizeof(struct in_addr)); - OTInetHostToString((InetHost)addr, sHostInfo.name); - - return (gethostbyname(sHostInfo.name)); + OTInetHostToString((InetHost)addr, sHostInfo.name); + + return (gethostbyname(sHostInfo.name)); } PR_IMPLEMENT(char *) inet_ntoa(struct in_addr addr) { - OTInetHostToString((InetHost)addr.s_addr, sHostInfo.name); - - return sHostInfo.name; + OTInetHostToString((InetHost)addr.s_addr, sHostInfo.name); + + return sHostInfo.name; } PRStatus _MD_gethostname(char *name, int namelen) { - OSStatus err; - InetInterfaceInfo info; - - /* - * On a Macintosh, we donÕt have the concept of a local host name. - * We do though have an IP address & everyone should be happy with - * a string version of that for a name. - * The alternative here is to ping a local DNS for our name, they - * will often know it. This is the cheap, easiest, and safest way out. - */ - - /* Make sure the string is as long as the longest possible address */ - if (namelen < strlen("123.123.123.123")) { - err = kEINVALErr; - goto ErrorExit; - } - - err = OTInetGetInterfaceInfo(&info, kDefaultInetInterface); - if (err != kOTNoError) - goto ErrorExit; - - OTInetHostToString(info.fAddress, name); - - return PR_SUCCESS; + OSStatus err; + InetInterfaceInfo info; + + /* + * On a Macintosh, we donÕt have the concept of a local host name. + * We do though have an IP address & everyone should be happy with + * a string version of that for a name. + * The alternative here is to ping a local DNS for our name, they + * will often know it. This is the cheap, easiest, and safest way out. + */ + + /* Make sure the string is as long as the longest possible address */ + if (namelen < strlen("123.123.123.123")) { + err = kEINVALErr; + goto ErrorExit; + } + + err = OTInetGetInterfaceInfo(&info, kDefaultInetInterface); + if (err != kOTNoError) + goto ErrorExit; + + OTInetHostToString(info.fAddress, name); + + return PR_SUCCESS; ErrorExit: - macsock_map_error(err); + macsock_map_error(err); return PR_FAILURE; } -#define kIPName "ip" +#define kIPName "ip" static struct protoent sIPProto = {kIPName, NULL, INET_IP}; static struct protoent sTCPProto = {kTCPName, NULL, INET_TCP}; static struct protoent sUDPProto = {kUDPName, NULL, INET_UDP}; @@ -1500,16 +1533,16 @@ static struct protoent sUDPProto = {kUDPName, NULL, INET_UDP}; PR_IMPLEMENT(struct protoent *) getprotobyname(const char * name) { if (strcmp(name, kIPName) == 0) - return (&sIPProto); - + return (&sIPProto); + if (strcmp(name, kTCPName) == 0) - return (&sTCPProto); - + return (&sTCPProto); + if (strcmp(name, kUDPName) == 0) - return (&sUDPProto); - + return (&sUDPProto); + ErrorExit: - macsock_map_error(kEINVALErr); + macsock_map_error(kEINVALErr); return NULL; } @@ -1517,36 +1550,36 @@ ErrorExit: PR_IMPLEMENT(struct protoent *) getprotobynumber(int number) { if (number == INET_IP) - return (&sIPProto); - + return (&sIPProto); + if (number == INET_TCP) - return (&sTCPProto); - + return (&sTCPProto); + if (number == INET_UDP) - return (&sUDPProto); - + return (&sUDPProto); + ErrorExit: - macsock_map_error(kEINVALErr); + macsock_map_error(kEINVALErr); return NULL; } int _MD_mac_get_nonblocking_connect_error(PRInt32 osfd) { - OTResult resultOT; - EndpointRef endpoint = (EndpointRef) osfd; - - resultOT = OTGetEndpointState(endpoint); - switch (resultOT) { - case T_OUTCON: - macsock_map_error(kEINPROGRESSErr); - return -1; - case T_DATAXFER: - return 0; - case T_IDLE: - return -1; - default: - PR_ASSERT(0); - return -1; - } + OTResult resultOT; + EndpointRef endpoint = (EndpointRef) osfd; + + resultOT = OTGetEndpointState(endpoint); + switch (resultOT) { + case T_OUTCON: + macsock_map_error(kEINPROGRESSErr); + return -1; + case T_DATAXFER: + return 0; + case T_IDLE: + return -1; + default: + PR_ASSERT(0); + return -1; + } } diff --git a/pr/src/md/mac/macthr.c b/pr/src/md/mac/macthr.c index fa5a4637..26008768 100644 --- a/pr/src/md/mac/macthr.c +++ b/pr/src/md/mac/macthr.c @@ -71,7 +71,6 @@ PRStatus _MD_AllocSegment(PRSegment *seg, PRUint32 size, void *vaddr) return PR_FAILURE; } - seg->access = PR_SEGMENT_RDWR; seg->size = size; return PR_SUCCESS; @@ -163,7 +162,7 @@ pascal void TimerCallback(TMTaskPtr tmTaskPtr) PrimeTime((QElemPtr)tmTaskPtr, kMacTimerInMiliSecs); return; } - _PR_SET_INTSOFF(1); + _PR_MD_SET_INTSOFF(1); // And tell nspr that a clock interrupt occured. _PR_ClockInterrupt(); @@ -171,7 +170,7 @@ pascal void TimerCallback(TMTaskPtr tmTaskPtr) if ((_PR_RUNQREADYMASK(cpu)) >> ((_PR_MD_CURRENT_THREAD()->priority))) _PR_SET_RESCHED_FLAG(); - _PR_SET_INTSOFF(0); + _PR_MD_SET_INTSOFF(0); // Reset the clock timer so that we fire again. PrimeTime((QElemPtr)tmTaskPtr, kMacTimerInMiliSecs); diff --git a/pr/src/md/os2/os2poll.c b/pr/src/md/os2/os2poll.c index b3353aa7..90195c64 100644 --- a/pr/src/md/os2/os2poll.c +++ b/pr/src/md/os2/os2poll.c @@ -22,144 +22,237 @@ #include "primpl.h" -PRInt32 -_PR_MD_PR_POLL(PRPollDesc *pds, PRIntn npds, - PRIntervalTime timeout) +PRInt32 _PR_MD_PR_POLL( + PRPollDesc *pds, PRIntn npds, PRIntervalTime timeout) { + PRInt32 osfd; + int maxfd = -1; + fd_set rd, wt, ex; + PRFileDesc *bottom; PRPollDesc *pd, *epd; - PRInt32 n, err, pdcnt; - PRThread *me = _PR_MD_CURRENT_THREAD(); + PRInt32 ready, err; + PRThread *me = _PR_MD_CURRENT_THREAD(); + struct timeval tv, *tvp = NULL; - fd_set rd, wt, ex; - struct timeval tv, *tvp = NULL; - int maxfd = -1; + /* + * For restarting _MD_SELECT() if it is interrupted by a signal. + * We use these variables to figure out how much time has elapsed + * and how much of the timeout still remains. + */ + PRIntervalTime start, elapsed, remaining; + + if (_PR_PENDING_INTERRUPT(me)) + { + me->flags &= ~_PR_INTERRUPT; + PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); + return -1; + } /* - * For restarting _MD_SELECT() if it is interrupted by a signal. - * We use these variables to figure out how much time has elapsed - * and how much of the timeout still remains. - */ - PRIntervalTime start, elapsed, remaining; - - FD_ZERO(&rd); - FD_ZERO(&wt); - FD_ZERO(&ex); - - for (pd = pds, epd = pd + npds; pd < epd; pd++) { - PRInt32 osfd; - PRInt16 in_flags = pd->in_flags; - PRFileDesc *bottom = pd->fd; - - if ((NULL == bottom) || (in_flags == 0)) { - continue; - } - while (bottom->lower != NULL) { - bottom = bottom->lower; - } - osfd = bottom->secret->md.osfd; - - if (osfd > maxfd) { - maxfd = osfd; - } - if (in_flags & PR_POLL_READ) { - FD_SET(osfd, &rd); - } - if (in_flags & PR_POLL_WRITE) { - FD_SET(osfd, &wt); - } - if (in_flags & PR_POLL_EXCEPT) { - FD_SET(osfd, &ex); - } - } - if (timeout != PR_INTERVAL_NO_TIMEOUT) { - tv.tv_sec = PR_IntervalToSeconds(timeout); - tv.tv_usec = PR_IntervalToMicroseconds(timeout) % PR_USEC_PER_SEC; - tvp = &tv; - start = PR_IntervalNow(); - } + ** Is it an empty set? If so, just sleep for the timeout and return + */ + if (0 == npds) + { + PR_Sleep(timeout); + return 0; + } + + FD_ZERO(&rd); + FD_ZERO(&wt); + FD_ZERO(&ex); + + ready = 0; + for (pd = pds, epd = pd + npds; pd < epd; pd++) + { + PRInt16 in_flags_read = 0, in_flags_write = 0; + PRInt16 out_flags_read = 0, out_flags_write = 0; + + if ((NULL != pd->fd) && (0 != pd->in_flags)) + { + if (pd->in_flags & PR_POLL_READ) + { + in_flags_read = (pd->fd->methods->poll)( + pd->fd, (PRInt16)(pd->in_flags & ~PR_POLL_WRITE), + &out_flags_read); + } + if (pd->in_flags & PR_POLL_WRITE) + { + in_flags_write = (pd->fd->methods->poll)( + pd->fd, (PRInt16)(pd->in_flags & ~PR_POLL_READ), + &out_flags_write); + } + if ((0 != (in_flags_read & out_flags_read)) + || (0 != (in_flags_write & out_flags_write))) + { + /* this one's ready right now (buffered input) */ + if (0 == ready) + { + /* + * We will have to return without calling the + * system poll/select function. So zero the + * out_flags fields of all the poll descriptors + * before this one. + */ + PRPollDesc *prev; + for (prev = pds; prev < pd; prev++) + { + prev->out_flags = 0; + } + } + ready += 1; + pd->out_flags = out_flags_read | out_flags_write; + } + else + { + pd->out_flags = 0; /* pre-condition */ + /* make sure this is an NSPR supported stack */ + bottom = PR_GetIdentitiesLayer(pd->fd, PR_NSPR_IO_LAYER); + PR_ASSERT(NULL != bottom); /* what to do about that? */ + if ((NULL != bottom) + && (_PR_FILEDESC_OPEN == bottom->secret->state)) + { + if (0 == ready) + { + osfd = bottom->secret->md.osfd; + if (osfd > maxfd) maxfd = osfd; + if (in_flags_read & PR_POLL_READ) + { + pd->out_flags |= _PR_POLL_READ_SYS_READ; + FD_SET(osfd, &rd); + } + if (in_flags_read & PR_POLL_WRITE) + { + pd->out_flags |= _PR_POLL_READ_SYS_WRITE; + FD_SET(osfd, &wt); + } + if (in_flags_write & PR_POLL_READ) + { + pd->out_flags |= _PR_POLL_WRITE_SYS_READ; + FD_SET(osfd, &rd); + } + if (in_flags_write & PR_POLL_WRITE) + { + pd->out_flags |= _PR_POLL_WRITE_SYS_WRITE; + FD_SET(osfd, &wt); + } + if (pd->in_flags & PR_POLL_EXCEPT) FD_SET(osfd, &ex); + } + } + else + { + if (0 == ready) + { + PRPollDesc *prev; + for (prev = pds; prev < pd; prev++) + { + prev->out_flags = 0; + } + } + ready += 1; /* this will cause an abrupt return */ + pd->out_flags = PR_POLL_NVAL; /* bogii */ + } + } + } + } + + if (0 != ready) return ready; /* no need to block */ + + remaining = timeout; + start = PR_IntervalNow(); retry: - n = _MD_SELECT(maxfd + 1, &rd, &wt, &ex, tvp); - if (n == -1 && errno == EINTR) { - if (timeout == PR_INTERVAL_NO_TIMEOUT) { - goto retry; - } else { + if (timeout != PR_INTERVAL_NO_TIMEOUT) + { + PRInt32 ticksPerSecond = PR_TicksPerSecond(); + tv.tv_sec = remaining / ticksPerSecond; + tv.tv_usec = remaining - (ticksPerSecond * tv.tv_sec); + tv.tv_usec = (PR_USEC_PER_SEC * tv.tv_usec) / ticksPerSecond; + tvp = &tv; + } + + ready = _MD_SELECT(maxfd + 1, &rd, &wt, &ex, tvp); + if (ready == -1 && errno == EINTR) + { + if (timeout == PR_INTERVAL_NO_TIMEOUT) goto retry; + else + { elapsed = (PRIntervalTime) (PR_IntervalNow() - start); - if (elapsed > timeout) { - n = 0; /* timed out */ - } else { + if (elapsed > timeout) ready = 0; /* timed out */ + else + { remaining = timeout - elapsed; - tv.tv_sec = PR_IntervalToSeconds(remaining); - tv.tv_usec = PR_IntervalToMicroseconds( - remaining - PR_SecondsToInterval(tv.tv_sec)); - goto retry; - } - } - } + goto retry; + } + } + } + + if (ready > 0) + { + ready = 0; + for (pd = pds, epd = pd + npds; pd < epd; pd++) + { + PRInt16 out_flags = 0; + if ((NULL != pd->fd) && (0 != pd->in_flags)) + { + bottom = PR_GetIdentitiesLayer(pd->fd, PR_NSPR_IO_LAYER); + PR_ASSERT(NULL != bottom); + + osfd = bottom->secret->md.osfd; - if (n > 0) { - n = 0; - for (pd = pds, epd = pd + npds; pd < epd; pd++) { - PRInt32 osfd; - PRInt16 in_flags = pd->in_flags; - PRInt16 out_flags = 0; - PRFileDesc *bottom = pd->fd; - - if ((NULL == bottom) || (in_flags == 0)) { - pd->out_flags = 0; - continue; - } - while (bottom->lower != NULL) { - bottom = bottom->lower; - } - osfd = bottom->secret->md.osfd; - - if ((in_flags & PR_POLL_READ) && FD_ISSET(osfd, &rd)) { - out_flags |= PR_POLL_READ; - } - if ((in_flags & PR_POLL_WRITE) && FD_ISSET(osfd, &wt)) { - out_flags |= PR_POLL_WRITE; - } - if ((in_flags & PR_POLL_EXCEPT) && FD_ISSET(osfd, &ex)) { - out_flags |= PR_POLL_EXCEPT; - } - pd->out_flags = out_flags; - if (out_flags) { - n++; - } - } - PR_ASSERT(n > 0); - } else if (n < 0) { - err = _MD_ERRNO(); - if (err == EBADF) { - /* Find the bad fds */ - n = 0; - for (pd = pds, epd = pd + npds; pd < epd; pd++) { - int optval; - int optlen = sizeof(optval); - PRFileDesc *bottom = pd->fd; - pd->out_flags = 0; - if ((NULL == bottom) || (pd->in_flags == 0)) { - continue; - } - while (bottom->lower != NULL) { - bottom = bottom->lower; - } - if (getsockopt(bottom->secret->md.osfd, SOL_SOCKET, - SO_TYPE, (char *) &optval, &optlen) == -1) { - PR_ASSERT(_MD_ERRNO() == ENOTSOCK); - if (_MD_ERRNO() == ENOTSOCK) { - pd->out_flags = PR_POLL_NVAL; - n++; + if (FD_ISSET(osfd, &rd)) + { + if (pd->out_flags & _PR_POLL_READ_SYS_READ) + out_flags |= PR_POLL_READ; + if (pd->out_flags & _PR_POLL_WRITE_SYS_READ) + out_flags |= PR_POLL_WRITE; } + if (FD_ISSET(osfd, &wt)) + { + if (pd->out_flags & _PR_POLL_READ_SYS_WRITE) + out_flags |= PR_POLL_READ; + if (pd->out_flags & _PR_POLL_WRITE_SYS_WRITE) + out_flags |= PR_POLL_WRITE; + } + if (FD_ISSET(osfd, &ex)) out_flags |= PR_POLL_EXCEPT; } - } - PR_ASSERT(n > 0); - } else { - PR_ASSERT(err != EINTR); /* should have been handled above */ - _PR_MD_MAP_SELECT_ERROR(err); - } + pd->out_flags = out_flags; + if (out_flags) ready++; + } + PR_ASSERT(ready > 0); + } + else if (ready < 0) + { + err = _MD_ERRNO(); + if (err == EBADF) + { + /* Find the bad fds */ + ready = 0; + for (pd = pds, epd = pd + npds; pd < epd; pd++) + { + int optval; + int optlen = sizeof(optval); + pd->out_flags = 0; + if ((NULL == pd->fd) || (pd->in_flags == 0)) continue; + bottom = PR_GetIdentitiesLayer(pd->fd, PR_NSPR_IO_LAYER); + if (getsockopt(bottom->secret->md.osfd, SOL_SOCKET, + SO_TYPE, (char *) &optval, &optlen) == -1) + { + PR_ASSERT(_MD_ERRNO() == ENOTSOCK); + if (_MD_ERRNO() == ENOTSOCK) + { + pd->out_flags = PR_POLL_NVAL; + ready++; + } + } + } + PR_ASSERT(ready > 0); + } + else + { + PR_ASSERT(err != EINTR); /* should have been handled above */ + _PR_MD_MAP_SELECT_ERROR(err); + } } - return n; + return ready; } diff --git a/pr/src/md/prosdep.c b/pr/src/md/prosdep.c index 62b2b62f..326b3536 100644 --- a/pr/src/md/prosdep.c +++ b/pr/src/md/prosdep.c @@ -19,15 +19,15 @@ #include "prbit.h" #include "prsystem.h" -#if defined(XP_MAC) -#include "prosdep.h" -#else -#include "md/prosdep.h" -#endif - #ifdef XP_UNIX #include <unistd.h> #endif +#ifdef SUNOS4 +#include "md/sunos4.h" +#endif +#ifdef _WIN32 +#include <windows.h> +#endif PRInt32 _pr_pageShift; PRInt32 _pr_pageSize; @@ -42,7 +42,7 @@ static void GetPageSize(void) /* Get page size */ #ifdef XP_UNIX #if defined SUNOS4 || defined LINUX || defined BSDI || defined AIX \ - || defined FREEBSD || defined NETBSD || defined RHAPSODY + || defined FREEBSD || defined NETBSD || defined OPENBSD || defined RHAPSODY _pr_pageSize = getpagesize(); #elif defined(HPUX) /* I have no idea. Don't get me started. --Rob */ diff --git a/pr/src/md/unix/Makefile b/pr/src/md/unix/Makefile index 3615aabd..7d36371c 100644 --- a/pr/src/md/unix/Makefile +++ b/pr/src/md/unix/Makefile @@ -31,6 +31,7 @@ CSRCS = \ unix_errors.c \ uxproces.c \ uxwrap.c \ + uxpoll.c \ $(NULL) PTH_USER_CSRCS = \ @@ -61,6 +62,10 @@ NETBSD_CSRCS = \ netbsd.c \ $(NULL) +OPENBSD_CSRCS = \ + openbsd.c \ + $(NULL) + BSDI_CSRCS = \ bsdi.c \ $(NULL) @@ -134,6 +139,9 @@ endif ifeq ($(OS_ARCH),NetBSD) CSRCS += $(NETBSD_CSRCS) endif +ifeq ($(OS_ARCH),OpenBSD) +CSRCS += $(OPENBSD_CSRCS) +endif ifeq ($(OS_ARCH),BSD_OS) CSRCS += $(BSDI_CSRCS) endif @@ -186,8 +194,10 @@ ifeq ($(OS_ARCH),SunOS) ASFILES = os_$(OS_ARCH)_x86.s else ifneq ($(OS_RELEASE),4.1.3_U1) + ifneq ($(LOCAL_THREADS_ONLY),1) ASFILES = os_$(OS_ARCH).s endif + endif endif endif @@ -199,6 +209,10 @@ ifeq ($(OS_ARCH)$(OS_RELEASE),BSD_OS2.1) ASFILES = os_BSD_386_2.s endif +ifeq ($(OS_ARCH), IRIX) + ASFILES = os_Irix.s +endif + TARGETS = $(OBJS) ifeq ($(OS_ARCH),AIX) @@ -217,6 +231,7 @@ ifeq ($(OS_ARCH),SunOS) ULTRASPARC_ASFILES = os_$(OS_ARCH)_ultrasparc.s ULTRASPARC_ASOBJS = $(addprefix $(OBJDIR)/,$(ULTRASPARC_ASFILES:.s=.$(OBJ_SUFFIX))) TARGETS += $(ULTRASPARC_ASOBJS) $(SHARED_LIBRARY) + RELEASE_LIBS = $(SHARED_LIBRARY) endif endif endif diff --git a/pr/src/md/unix/aix.c b/pr/src/md/unix/aix.c index 879c6adc..524346e8 100644 --- a/pr/src/md/unix/aix.c +++ b/pr/src/md/unix/aix.c @@ -18,81 +18,6 @@ #include "primpl.h" -/* - * NSPR 2.0 overrides the system select() and poll() functions. - * On AIX 4.2, we use dlopen("/unix", RTLD_NOW) and dlsym() to get - * at the original system select() and poll() functions. - */ - -#ifndef AIX4_1 - -#include <sys/select.h> -#include <sys/poll.h> -#include <dlfcn.h> - -static void *aix_handle = NULL; -static int (*aix_select_fcn)() = NULL; -static int (*aix_poll_fcn)() = NULL; - -int _MD_SELECT(int width, fd_set *r, fd_set *w, fd_set *e, struct timeval *t) -{ - int rv; - - if (!aix_select_fcn) { - if (!aix_handle) { - aix_handle = dlopen("/unix", RTLD_NOW); - if (!aix_handle) { - PR_SetError(PR_UNKNOWN_ERROR, 0); - return -1; - } - } - aix_select_fcn = (int(*)())dlsym(aix_handle,"select"); - if (!aix_select_fcn) { - PR_SetError(PR_UNKNOWN_ERROR, 0); - return -1; - } - } - rv = (*aix_select_fcn)(width, r, w, e, t); - return rv; -} - -int _MD_POLL(void *listptr, unsigned long nfds, long timeout) -{ - int rv; - - if (!aix_poll_fcn) { - if (!aix_handle) { - aix_handle = dlopen("/unix", RTLD_NOW); - if (!aix_handle) { - PR_SetError(PR_UNKNOWN_ERROR, 0); - return -1; - } - } - aix_poll_fcn = (int(*)())dlsym(aix_handle,"poll"); - if (!aix_poll_fcn) { - PR_SetError(PR_UNKNOWN_ERROR, 0); - return -1; - } - } - rv = (*aix_poll_fcn)(listptr, nfds, timeout); - return rv; -} - -#else - -/* - * In AIX versions prior to 4.2, we use the two-step rename/link trick. - * The binary must contain at least one "poll" symbol for linker's rename - * to work. So we must have this dummy function that references poll(). - */ -#include <sys/poll.h> -void _pr_aix_dummy() -{ - poll(0,0,0); -} - -#endif /* !AIX4_1 */ - #include <sys/atomic_op.h> PRInt32 _AIX_AtomicSet(PRInt32 *val, PRInt32 newval) @@ -107,20 +32,57 @@ PRInt32 _AIX_AtomicSet(PRInt32 *val, PRInt32 newval) return oldval; } /* _AIX_AtomicSet */ +#if defined(AIX_TIMERS) + +#include <sys/time.h> + +static PRUint32 _aix_baseline_epoch; + +static void _MD_AixIntervalInit(void) +{ + timebasestruct_t real_time; + read_real_time(&real_time, TIMEBASE_SZ); + (void)time_base_to_time(&real_time, TIMEBASE_SZ); + _aix_baseline_epoch = real_time.tb_high; +} /* _MD_AixIntervalInit */ + +PRIntervalTime _MD_AixGetInterval(void) +{ + PRIntn rv; + PRUint64 temp; + timebasestruct_t real_time; + read_real_time(&real_time, TIMEBASE_SZ); + (void)time_base_to_time(&real_time, TIMEBASE_SZ); + /* tb_high is in seconds, tb_low in 10(-9)seconds */ + temp = 1000000000ULL * (PRUint64)(real_time.tb_high - _aix_baseline_epoch); + temp += (PRUint64)real_time.tb_low; /* everything's 10(-9) seconds */ + temp >>= 16; /* now it's something way different */ + return (PRIntervalTime)temp; +} /* _MD_AixGetInterval */ + +PRIntervalTime _MD_AixIntervalPerSec(void) +{ + return 1000000000ULL >> 16; /* that's 15258, I think */ +} /* _MD_AixIntervalPerSec */ + +#endif /* defined(AIX_TIMERS) */ + #if !defined(PTHREADS_USER) -#ifdef _PR_PTHREADS +#if defined(_PR_PTHREADS) /* * AIX 4.3 has sched_yield(). AIX 4.2 has pthread_yield(). * So we look up the appropriate function pointer at run time. */ +#include <dlfcn.h> + int (*_PT_aix_yield_fcn)() = NULL; void _MD_EarlyInit(void) { - void *main_app_handle = NULL; + void *main_app_handle; main_app_handle = dlopen(NULL, RTLD_NOW); PR_ASSERT(NULL != main_app_handle); @@ -131,12 +93,19 @@ void _MD_EarlyInit(void) PR_ASSERT(NULL != _PT_aix_yield_fcn); } dlclose(main_app_handle); + +#if defined(AIX_TIMERS) + _MD_AixIntervalInit(); +#endif } #else /* _PR_PTHREADS */ void _MD_EarlyInit(void) { +#if defined(AIX_TIMERS) + _MD_AixIntervalInit(); +#endif } #endif /* _PR_PTHREADS */ @@ -205,3 +174,128 @@ _MD_CREATE_THREAD( } #endif /* _PR_PTHREADS */ #endif /* PTHREADS_USER */ + +/* + * NSPR 2.0 overrides the system select() and poll() functions. + * On AIX 4.2, we use dlopen("/unix", RTLD_NOW) and dlsym() to get + * at the original system select() and poll() functions. + */ + +#if !defined(AIX4_1) + +#include <sys/select.h> +#include <sys/poll.h> +#include <dlfcn.h> + +static int (*aix_select_fcn)() = NULL; +static int (*aix_poll_fcn)() = NULL; + +int _MD_SELECT(int width, fd_set *r, fd_set *w, fd_set *e, struct timeval *t) +{ + int rv; + + if (!aix_select_fcn) { + void *aix_handle; + + aix_handle = dlopen("/unix", RTLD_NOW); + if (!aix_handle) { + PR_SetError(PR_UNKNOWN_ERROR, 0); + return -1; + } + aix_select_fcn = (int(*)())dlsym(aix_handle,"select"); + dlclose(aix_handle); + if (!aix_select_fcn) { + PR_SetError(PR_UNKNOWN_ERROR, 0); + return -1; + } + } + rv = (*aix_select_fcn)(width, r, w, e, t); + return rv; +} + +int _MD_POLL(void *listptr, unsigned long nfds, long timeout) +{ + int rv; + + if (!aix_poll_fcn) { + void *aix_handle; + + aix_handle = dlopen("/unix", RTLD_NOW); + if (!aix_handle) { + PR_SetError(PR_UNKNOWN_ERROR, 0); + return -1; + } + aix_poll_fcn = (int(*)())dlsym(aix_handle,"poll"); + dlclose(aix_handle); + if (!aix_poll_fcn) { + PR_SetError(PR_UNKNOWN_ERROR, 0); + return -1; + } + } + rv = (*aix_poll_fcn)(listptr, nfds, timeout); + return rv; +} + +#else + +/* + * In AIX versions prior to 4.2, we use the two-step rename/link trick. + * The binary must contain at least one "poll" symbol for linker's rename + * to work. So we must have this dummy function that references poll(). + */ +#include <sys/poll.h> +void _pr_aix_dummy() +{ + poll(0,0,0); +} + +#endif /* !defined(AIX4_1) */ + +#ifdef _PR_HAVE_ATOMIC_CAS + +#include "pratom.h" + +#define _PR_AIX_ATOMIC_LOCK -1 + +PR_IMPLEMENT(void) +PR_StackPush(PRStack *stack, PRStackElem *stack_elem) +{ +PRStackElem *addr; +boolean_t locked = TRUE; + + do { + while ((addr = stack->prstk_head.prstk_elem_next) == + (PRStackElem *)_PR_AIX_ATOMIC_LOCK) + ; + locked = _check_lock((atomic_p) &stack->prstk_head.prstk_elem_next, + (int) addr, _PR_AIX_ATOMIC_LOCK); + } while (locked == TRUE); + stack_elem->prstk_elem_next = addr; + _clear_lock((atomic_p)&stack->prstk_head.prstk_elem_next, (int)stack_elem); + return; +} + +PR_IMPLEMENT(PRStackElem *) +PR_StackPop(PRStack *stack) +{ +PRStackElem *element; +boolean_t locked = TRUE; + + do { + while ((element = stack->prstk_head.prstk_elem_next) == + (PRStackElem *) _PR_AIX_ATOMIC_LOCK) + ; + locked = _check_lock((atomic_p) &stack->prstk_head.prstk_elem_next, + (int)element, _PR_AIX_ATOMIC_LOCK); + } while (locked == TRUE); + + if (element == NULL) { + _clear_lock((atomic_p) &stack->prstk_head.prstk_elem_next, NULL); + } else { + _clear_lock((atomic_p) &stack->prstk_head.prstk_elem_next, + (int) element->prstk_elem_next); + } + return element; +} + +#endif /* _PR_HAVE_ATOMIC_CAS */ diff --git a/pr/src/md/unix/darwin.c b/pr/src/md/unix/darwin.c index a68f8667..01a73650 100644 --- a/pr/src/md/unix/darwin.c +++ b/pr/src/md/unix/darwin.c @@ -18,25 +18,13 @@ #include "primpl.h" -#include <signal.h> - void _MD_EarlyInit(void) { - /* - * Ignore FPE because coercion of a NaN to an int causes SIGFPE - * to be raised. - */ - struct sigaction act; - - act.sa_handler = SIG_IGN; - sigemptyset(&act.sa_mask); - act.sa_flags = SA_RESTART; - sigaction(SIGFPE, &act, 0); } PRWord *_MD_HomeGCRegisters(PRThread *t, int isCurrent, int *np) { -#ifndef _PR_PTHREADS +#if !defined(_PR_PTHREADS) if (isCurrent) { (void) setjmp(CONTEXT(t)); } @@ -48,7 +36,7 @@ PRWord *_MD_HomeGCRegisters(PRThread *t, int isCurrent, int *np) #endif } -#ifndef _PR_PTHREADS +#if !defined(_PR_PTHREADS) void _MD_SET_PRIORITY(_MDThread *thread, PRUintn newPri) { @@ -98,3 +86,14 @@ _MD_CREATE_THREAD( return PR_FAILURE; } #endif /* ! _PR_PTHREADS */ + +/* +** Whoops, we don't have a syscall stub for this +*/ +int mprotect (caddr_t addr, size_t size, int prot) +{ + return -1; +} + +/* rhapsody.c */ + diff --git a/pr/src/md/unix/hpux.c b/pr/src/md/unix/hpux.c index 79e244c1..e0328bb9 100644 --- a/pr/src/md/unix/hpux.c +++ b/pr/src/md/unix/hpux.c @@ -17,124 +17,51 @@ */ #include "primpl.h" -#if defined(HPUX10_30) || defined(HPUX11) -/* for fesettrapenable */ -#include <fenv.h> -#else -/* for fpsetmask */ -#include <math.h> -#endif #include <setjmp.h> -#include <signal.h> -#include <values.h> -/* -** On HP-UX we need to define a SIGFPE handler because coercion of a -** NaN to an int causes SIGFPE to be raised. Thanks to Marianne -** Mueller and Doug Priest at SunSoft for this fix. -** -** Under DCE threads, sigaction() installs a per-thread signal handler, -** so we use the sigvector() interface to install a process-wide -** handler. -** -** On HP-UX 9, struct sigaction doesn't have the sa_sigaction field, -** so we also need to use the sigvector() interface. -*/ +#if defined(HPUX_LW_TIMER) -#if defined(_PR_DCETHREADS) || defined(HPUX9) -static void -CatchFPE(int sig, int code, struct sigcontext *scp) -{ - unsigned i, e; - int r, t; - int *source, *destination; +#include <machine/inline.h> +#include <machine/clock.h> +#include <unistd.h> +#include <sys/time.h> +#include <sys/pstat.h> - /* check excepting instructions */ - for ( i = 0; i < 7; i++ ) { - e = *(i+&(scp->sc_sl.sl_ss.ss_frexcp1)); - if ( e & 0xfc000000 != 0 ) { - if ((e & 0xf4017720) == 0x24010200) { - r = ((e >> 20) & 0x3e); - t = (e & 0x1f) << 1; - if (e & 0x08000000) { - r |= (e >> 7) & 1; - t |= (e >> 6) & 1; - } - source = (int *)(&scp->sc_sl.sl_ss.ss_frstat + r); - destination = (int *)(&scp->sc_sl.sl_ss.ss_frstat + t); - *destination = *source < 0 ? -MAXINT-1 : MAXINT; - } - } - *(i+&(scp->sc_sl.sl_ss.ss_frexcp1)) = 0; - } +int __lw_get_thread_times(int which, int64_t *sample, int64_t *time); - /* clear T-bit */ - scp->sc_sl.sl_ss.ss_frstat &= ~0x40; -} -#else /* _PR_DCETHREADS || HPUX9 */ -static void -CatchFPE(int sig, siginfo_t *info, void *context) +static double msecond_per_itick; + +void _PR_HPUX_LW_IntervalInit(void) { - ucontext_t *ucp = (ucontext_t *) context; - unsigned i, e; - int r, t; - int *source, *destination; + struct pst_processor psp; + int iticksperclktick, clk_tck; + int rv; - /* check excepting instructions */ - for ( i = 0; i < 7; i++ ) { - e = *(i+&(ucp->uc_mcontext.ss_frexcp1)); - if ( e & 0xfc000000 != 0 ) { - if ((e & 0xf4017720) == 0x24010200) { - r = ((e >> 20) & 0x3e); - t = (e & 0x1f) << 1; - if (e & 0x08000000) { - r |= (e >> 7) & 1; - t |= (e >> 6) & 1; - } - source = (int *)(&ucp->uc_mcontext.ss_frstat + r); - destination = (int *)(&ucp->uc_mcontext.ss_frstat + t); - *destination = *source < 0 ? -MAXINT-1 : MAXINT; - } - } - *(i+&(ucp->uc_mcontext.ss_frexcp1)) = 0; - } + rv = pstat_getprocessor(&psp, sizeof(psp), 1, 0); + PR_ASSERT(rv != -1); - /* clear T-bit */ - ucp->uc_mcontext.ss_frstat &= ~0x40; + iticksperclktick = psp.psp_iticksperclktick; + clk_tck = sysconf(_SC_CLK_TCK); + msecond_per_itick = (1000.0)/(double)(iticksperclktick * clk_tck); } -#endif /* _PR_DCETHREADS || HPUX9 */ -void _MD_hpux_install_sigfpe_handler(void) +PRIntervalTime _PR_HPUX_LW_GetInterval(void) { -#if defined(_PR_DCETHREADS) || defined(HPUX9) - struct sigvec v; - - v.sv_handler = CatchFPE; - v.sv_mask = 0; - v.sv_flags = 0; - sigvector(SIGFPE, &v, NULL); -#else - struct sigaction act; - - sigaction(SIGFPE, NULL, &act); - act.sa_flags |= SA_SIGINFO; - act.sa_sigaction = CatchFPE; - sigaction(SIGFPE, &act, NULL); -#endif /* _PR_DCETHREADS || HPUX9 */ + int64_t time, sample; -#if defined(HPUX10_30) || defined(HPUX11) - fesettrapenable(FE_INVALID); -#else - fpsetmask(FP_X_INV); -#endif + __lw_get_thread_times(1, &sample, &time); + /* + * Division is slower than float multiplication. + * return (time / iticks_per_msecond); + */ + return (time * msecond_per_itick); } +#endif /* HPUX_LW_TIMER */ #if !defined(PTHREADS_USER) void _MD_EarlyInit(void) { - _MD_hpux_install_sigfpe_handler(); - #ifndef _PR_PTHREADS /* * The following piece of code is taken from ns/nspr/src/md_HP-UX.c. @@ -260,28 +187,6 @@ _MD_resume_thread(PRThread *thread) #endif /* PTHREADS_USER */ /* - * See if we have the privilege to set the scheduling policy and - * priority of threads. Returns 0 if privilege is available. - * Returns EPERM otherwise. - */ - -#if defined(_PR_PTHREADS) && !defined(_PR_DCETHREADS) -PRIntn pt_hpux_privcheck() -{ - PRIntn policy; - struct sched_param schedule; - PRIntn rv; - pthread_t me = pthread_self(); - - rv = pthread_getschedparam(me, &policy, &schedule); - PR_ASSERT(0 == rv); - rv = pthread_setschedparam(me, policy, &schedule); - PR_ASSERT(0 == rv || EPERM == rv); - return rv; -} -#endif - -/* * The HP version of strchr is buggy. It looks past the end of the * string and causes a segmentation fault when our (NSPR) version * of malloc is used. diff --git a/pr/src/md/unix/irix.c b/pr/src/md/unix/irix.c index ca49378d..9e1963b5 100644 --- a/pr/src/md/unix/irix.c +++ b/pr/src/md/unix/irix.c @@ -36,12 +36,20 @@ #include <sys/resource.h> #include <sys/procfs.h> #include <task.h> +#include <dlfcn.h> -static void _MD_IntervalInit(void); +static void _MD_IrixIntervalInit(void); #if defined(_PR_PTHREADS) +/* + * for compatibility with classic nspr + */ +void _PR_IRIX_CHILD_PROCESS() +{ +} #else /* defined(_PR_PTHREADS) */ +static void irix_detach_sproc(void); char *_nspr_sproc_private; /* ptr. to private region in every sproc */ extern PRUintn _pr_numCPU; @@ -61,6 +69,27 @@ ulock_t arena_list_lock; nspr_arena first_arena; int _nspr_irix_arena_cnt = 1; +PRCList sproc_list = PR_INIT_STATIC_CLIST(&sproc_list); +ulock_t sproc_list_lock; + +typedef struct sproc_data { + void (*entry) (void *, size_t); + unsigned inh; + void *arg; + caddr_t sp; + size_t len; + int *pid; + int creator_pid; +} sproc_data; + +typedef struct sproc_params { + PRCList links; + sproc_data sd; +} sproc_params; + +#define SPROC_PARAMS_PTR(qp) \ + ((sproc_params *) ((char*) (qp) - offsetof(sproc_params , links))) + long _nspr_irix_lock_cnt = 0; long _nspr_irix_sem_cnt = 0; long _nspr_irix_pollsem_cnt = 0; @@ -70,7 +99,12 @@ ulock_t _pr_heapLock; usema_t *_pr_irix_exit_sem; PRInt32 _pr_irix_exit_now = 0; +PRInt32 _pr_irix_process_exit_code = 0; /* exit code for PR_ProcessExit */ +PRInt32 _pr_irix_process_exit = 0; /* process exiting due to call to + PR_ProcessExit */ +int _pr_irix_primoridal_cpu_fd[2] = { -1, -1 }; +static void (*libc_exit)(int) = NULL; #define _NSPR_DEF_INITUSERS 100 /* default value of CONF_INITUSERS */ #define _NSPR_DEF_INITSIZE (4 * 1024 * 1024) /* 4 MB */ @@ -118,7 +152,7 @@ usema_t *sem = NULL; PRCList *qp; nspr_arena *arena; usptr_t *irix_arena; -PRThread *me = _PR_MD_CURRENT_THREAD(); +PRThread *me = _MD_GET_ATTACHED_THREAD(); if (me && !_PR_IS_NATIVE_THREAD(me)) _PR_INTSOFF(_is); @@ -171,7 +205,7 @@ PRThread *me = _PR_MD_CURRENT_THREAD(); static void free_poll_sem(struct _MDThread *mdthr) { PRIntn _is; -PRThread *me = _PR_MD_CURRENT_THREAD(); +PRThread *me = _MD_GET_ATTACHED_THREAD(); if (me && !_PR_IS_NATIVE_THREAD(me)) _PR_INTSOFF(_is); @@ -189,7 +223,7 @@ ulock_t lock = NULL; PRCList *qp; nspr_arena *arena; usptr_t *irix_arena; -PRThread *me = _PR_MD_CURRENT_THREAD(); +PRThread *me = _MD_GET_ATTACHED_THREAD(); if (me && !_PR_IS_NATIVE_THREAD(me)) _PR_INTSOFF(_is); @@ -242,7 +276,7 @@ PRThread *me = _PR_MD_CURRENT_THREAD(); static void free_lock(struct _MDLock *lockp) { PRIntn _is; -PRThread *me = _PR_MD_CURRENT_THREAD(); +PRThread *me = _MD_GET_ATTACHED_THREAD(); if (me && !_PR_IS_NATIVE_THREAD(me)) _PR_INTSOFF(_is); @@ -255,7 +289,7 @@ PRThread *me = _PR_MD_CURRENT_THREAD(); void _MD_FREE_LOCK(struct _MDLock *lockp) { PRIntn _is; - PRThread *me = _PR_MD_CURRENT_THREAD(); + PRThread *me = _MD_GET_ATTACHED_THREAD(); if (me && !_PR_IS_NATIVE_THREAD(me)) _PR_INTSOFF(_is); @@ -274,17 +308,51 @@ void _MD_FREE_LOCK(struct _MDLock *lockp) */ PRThread *_MD_get_attached_thread(void) { - if (_MD_GET_SPROC_PID() == getpid()) - return _PR_MD_CURRENT_THREAD(); + + if (_MD_GET_SPROC_PID() == get_pid()) + return _MD_THIS_THREAD(); else return 0; } +/* + * _MD_get_current_thread + * Return the thread pointer of the current thread (attaching it if + * necessary) + */ +PRThread *_MD_get_current_thread(void) +{ +PRThread *me; + + me = _MD_GET_ATTACHED_THREAD(); + if (NULL == me) { + me = _PRI_AttachThread( + PR_USER_THREAD, PR_PRIORITY_NORMAL, NULL, 0); + } + PR_ASSERT(me != NULL); + return(me); +} + +/* + * irix_detach_sproc + * auto-detach a sproc when it exits + */ +void irix_detach_sproc(void) +{ +PRThread *me; + + me = _MD_GET_ATTACHED_THREAD(); + if ((me != NULL) && (me->flags & _PR_ATTACHED)) { + _PRI_DetachThread(); + } +} + + PRStatus _MD_NEW_LOCK(struct _MDLock *lockp) { PRStatus rv; PRIntn is; - PRThread *me = _PR_MD_CURRENT_THREAD(); + PRThread *me = _MD_GET_ATTACHED_THREAD(); if (me && !_PR_IS_NATIVE_THREAD(me)) _PR_INTSOFF(is); @@ -311,7 +379,7 @@ sigchld_handler(int sig) (WTERMSIG(status) == SIGILL))) { prctl(PR_SETEXITSIG, SIGKILL); - exit(status); + _exit(status); } } } @@ -412,9 +480,13 @@ void _MD_InitLocks() exit(-1); } _pr_heapLock = usnewlock(_pr_usArena); + _nspr_irix_lock_cnt++; arena_list_lock = usnewlock(_pr_usArena); - _nspr_irix_lock_cnt = 3; + _nspr_irix_lock_cnt++; + + sproc_list_lock = usnewlock(_pr_usArena); + _nspr_irix_lock_cnt++; _pr_irix_exit_sem = usnewsema(_pr_usArena, 0); _nspr_irix_sem_cnt = 1; @@ -427,13 +499,16 @@ void _MD_InitLocks() /* _PR_IRIX_CHILD_PROCESS is a private API for Server group */ void _PR_IRIX_CHILD_PROCESS() { +extern PRUint32 _pr_global_threads; + PR_ASSERT(_PR_MD_CURRENT_CPU() == _pr_primordialCPU); PR_ASSERT(_pr_numCPU == 1); - PR_ASSERT((_pr_userActive + _pr_systemActive) == 2); + PR_ASSERT(_pr_global_threads == 0); /* * save the new pid */ _pr_primordialCPU->md.id = getpid(); + _MD_SET_SPROC_PID(getpid()); } static PRStatus pr_cvar_wait_sem(PRThread *thread, PRIntervalTime timeout) @@ -544,7 +619,6 @@ PRStatus _MD_wait(PRThread *thread, PRIntervalTime ticks) PRStatus _MD_WakeupWaiter(PRThread *thread) { PRThread *me = _PR_MD_CURRENT_THREAD(); - PRInt32 pid, rv; PRIntn is; PR_ASSERT(_pr_md_idle_cpus >= 0); @@ -565,6 +639,80 @@ PRStatus _MD_WakeupWaiter(PRThread *thread) return PR_SUCCESS; } +void create_sproc (void (*entry) (void *, size_t), unsigned inh, + void *arg, caddr_t sp, size_t len, int *pid) +{ +sproc_params sparams; +char data; +int rv; +PRThread *me = _PR_MD_CURRENT_THREAD(); + + if (!_PR_IS_NATIVE_THREAD(me) && (_PR_MD_CURRENT_CPU()->id == 0)) { + *pid = sprocsp(entry, /* startup func */ + inh, /* attribute flags */ + arg, /* thread param */ + sp, /* stack address */ + len); /* stack size */ + } else { + sparams.sd.entry = entry; + sparams.sd.inh = inh; + sparams.sd.arg = arg; + sparams.sd.sp = sp; + sparams.sd.len = len; + sparams.sd.pid = pid; + sparams.sd.creator_pid = getpid(); + _PR_LOCK(sproc_list_lock); + PR_APPEND_LINK(&sparams.links, &sproc_list); + rv = write(_pr_irix_primoridal_cpu_fd[1], &data, 1); + PR_ASSERT(rv == 1); + _PR_UNLOCK(sproc_list_lock); + blockproc(getpid()); + } +} + +/* + * _PR_MD_WAKEUP_PRIMORDIAL_CPU + * + * wakeup cpu 0 + */ + +void _PR_MD_WAKEUP_PRIMORDIAL_CPU() +{ +char data = '0'; +int rv; + + rv = write(_pr_irix_primoridal_cpu_fd[1], &data, 1); + PR_ASSERT(rv == 1); +} + +/* + * _PR_MD_primordial_cpu + * + * process events that need to executed by the primordial cpu on each + * iteration through the idle loop + */ + +void _PR_MD_primordial_cpu() +{ +PRCList *qp; +sproc_params *sp; +int pid; + + _PR_LOCK(sproc_list_lock); + while ((qp = sproc_list.next) != &sproc_list) { + sp = SPROC_PARAMS_PTR(qp); + PR_REMOVE_LINK(&sp->links); + pid = sp->sd.creator_pid; + (*(sp->sd.pid)) = sprocsp(sp->sd.entry, /* startup func */ + sp->sd.inh, /* attribute flags */ + sp->sd.arg, /* thread param */ + sp->sd.sp, /* stack address */ + sp->sd.len); /* stack size */ + unblockproc(pid); + } + _PR_UNLOCK(sproc_list_lock); +} + PRStatus _MD_CreateThread(PRThread *thread, void (*start)(void *), PRThreadPriority priority, @@ -578,43 +726,44 @@ PRUint32 stackSize) PRThread *me = _PR_MD_CURRENT_THREAD(); PRInt32 pid; PRStatus rv; - PRStatus creation_status; if (!_PR_IS_NATIVE_THREAD(me)) _PR_INTSOFF(is); thread->md.cvar_pollsem_select = 0; - thread->md.creation_status = &creation_status; thread->flags |= _PR_GLOBAL_SCOPE; - pid = sprocsp( - spentry, /* startup func */ - PR_SALL, /* attribute flags */ - (void *)thread, /* thread param */ - NULL, /* stack address */ - stackSize); /* stack size */ + + thread->md.cvar_pollsemfd = -1; + if (new_poll_sem(&thread->md,0) == PR_FAILURE) { + if (!_PR_IS_NATIVE_THREAD(me)) + _PR_FAST_INTSON(is); + return PR_FAILURE; + } + thread->md.cvar_pollsemfd = + _PR_OPEN_POLL_SEM(thread->md.cvar_pollsem); + if ((thread->md.cvar_pollsemfd < 0)) { + free_poll_sem(&thread->md); + if (!_PR_IS_NATIVE_THREAD(me)) + _PR_FAST_INTSON(is); + return PR_FAILURE; + } + + create_sproc(spentry, /* startup func */ + PR_SALL, /* attribute flags */ + (void *)thread, /* thread param */ + NULL, /* stack address */ + stackSize, &pid); /* stack size */ if (pid > 0) { - /* - * Wait for the sproc to signal me after it has initialized - * itself - */ - if (!_PR_IS_NATIVE_THREAD(me)) - blockproc(me->cpu->md.id); - else - blockproc(me->md.id); - if (creation_status == PR_FAILURE) { - /* - * the sproc failed to create a polled semaphore and exited - */ - _MD_ATOMIC_INCREMENT(&_pr_md_irix_sprocs_failed); - rv = PR_FAILURE; - } else { - _MD_ATOMIC_INCREMENT(&_pr_md_irix_sprocs_created); - _MD_ATOMIC_INCREMENT(&_pr_md_irix_sprocs); - rv = PR_SUCCESS; - } + _MD_ATOMIC_INCREMENT(&_pr_md_irix_sprocs_created); + _MD_ATOMIC_INCREMENT(&_pr_md_irix_sprocs); + rv = PR_SUCCESS; if (!_PR_IS_NATIVE_THREAD(me)) _PR_FAST_INTSON(is); return rv; } else { + close(thread->md.cvar_pollsemfd); + thread->md.cvar_pollsemfd = -1; + free_poll_sem(&thread->md); + thread->md.cvar_pollsem = NULL; _MD_ATOMIC_INCREMENT(&_pr_md_irix_sprocs_failed); if (!_PR_IS_NATIVE_THREAD(me)) _PR_FAST_INTSON(is); @@ -686,38 +835,39 @@ extern void __sgi_prda_procmask(int); #endif PRStatus -_MD_InitThread(PRThread *thread, PRBool wakeup_parent) +_MD_InitAttachedThread(PRThread *thread, PRBool wakeup_parent) { - struct sigaction sigact; PRStatus rv = PR_SUCCESS; if (thread->flags & _PR_GLOBAL_SCOPE) { - /* - * create a polled semaphore - * - * NOTE: On Irix there is a bug which requires the sproc that - * created a polled semaphore to not exit for that semaphore - * to be useable by other sprocs. - */ - thread->md.id = getpid(); - thread->md.cvar_pollsemfd = -1; if (new_poll_sem(&thread->md,0) == PR_FAILURE) { - if (wakeup_parent == PR_TRUE) { - *thread->md.creation_status = PR_FAILURE; - unblockproc(getppid()); - } return PR_FAILURE; } thread->md.cvar_pollsemfd = _PR_OPEN_POLL_SEM(thread->md.cvar_pollsem); if ((thread->md.cvar_pollsemfd < 0)) { free_poll_sem(&thread->md); - if (wakeup_parent == PR_TRUE) { - *thread->md.creation_status = PR_FAILURE; - unblockproc(getppid()); - } return PR_FAILURE; } + if (_MD_InitThread(thread, PR_FALSE) == PR_FAILURE) { + close(thread->md.cvar_pollsemfd); + thread->md.cvar_pollsemfd = -1; + free_poll_sem(&thread->md); + thread->md.cvar_pollsem = NULL; + return PR_FAILURE; + } + } + return rv; +} + +PRStatus +_MD_InitThread(PRThread *thread, PRBool wakeup_parent) +{ + struct sigaction sigact; + PRStatus rv = PR_SUCCESS; + + if (thread->flags & _PR_GLOBAL_SCOPE) { + thread->md.id = getpid(); setblockproccnt(thread->md.id, 0); _MD_SET_SPROC_PID(getpid()); #ifndef IRIX5_3 @@ -729,7 +879,6 @@ _MD_InitThread(PRThread *thread, PRBool wakeup_parent) #endif /* * set up SIGUSR1 handler; this is used to save state - * during PR_SuspendAll */ sigact.sa_handler = save_context_and_block; sigact.sa_flags = SA_RESTART; @@ -740,52 +889,199 @@ _MD_InitThread(PRThread *thread, PRBool wakeup_parent) sigaction(SIGUSR1, &sigact, 0); - if (_nspr_terminate_on_error) { + /* + * PR_SETABORTSIG is a new command implemented in a patch to + * Irix 6.2, 6.3 and 6.4. This causes a signal to be sent to all + * sprocs in the process when one of them terminates abnormally + * + */ + if (prctl(PR_SETABORTSIG, SIGKILL) < 0) { /* - * PR_SETABORTSIG is a new command implemented in a patch to - * Irix 6.2, 6.3 and 6.4. This causes a signal to be sent to all - * sprocs in the process when one of them terminates abnormally + * if (errno == EINVAL) * + * PR_SETABORTSIG not supported under this OS. + * You may want to get a recent kernel rollup patch that + * supports this feature. */ - - if (prctl(PR_SETABORTSIG, SIGKILL) < 0) { - /* - * if (errno == EINVAL) - * - * PR_SETABORTSIG not supported under this OS. - * You may want to get a recent kernel rollup patch that - * supports this feature. - */ - /* - * SIGCLD handler for detecting abormally-terminating - * sprocs - */ - sigact.sa_handler = sigchld_handler; - sigact.sa_flags = SA_RESTART; - sigact.sa_mask = ints_off; - sigaction(SIGCLD, &sigact, NULL); - } } /* - * unblock the parent sproc + * SIGCLD handler for detecting abormally-terminating + * sprocs and for reaping sprocs */ - if (wakeup_parent == PR_TRUE) { - *thread->md.creation_status = PR_SUCCESS; - unblockproc(getppid()); - } + sigact.sa_handler = sigchld_handler; + sigact.sa_flags = SA_RESTART; + sigact.sa_mask = ints_off; + sigaction(SIGCLD, &sigact, NULL); } return rv; } +/* + * PR_Cleanup should be executed on the primordial sproc; migrate the thread + * to the primordial cpu + */ + +void _PR_MD_PRE_CLEANUP(PRThread *me) +{ +PRIntn is; +_PRCPU *cpu = _pr_primordialCPU; + + PR_ASSERT(cpu); + + me->flags |= _PR_BOUND_THREAD; + + if (me->cpu->id != 0) { + _PR_INTSOFF(is); + _PR_RUNQ_LOCK(cpu); + me->cpu = cpu; + me->state = _PR_RUNNABLE; + _PR_ADD_RUNQ(me, cpu, me->priority); + _PR_RUNQ_UNLOCK(cpu); + _MD_Wakeup_CPUs(); + + _PR_MD_SWITCH_CONTEXT(me); + + _PR_FAST_INTSON(is); + PR_ASSERT(me->cpu->id == 0); + } +} + +/* + * process exiting + */ PR_EXTERN(void ) _MD_exit(PRIntn status) { +PRThread *me = _PR_MD_CURRENT_THREAD(); + /* - * Cause SIGKILL to be sent to other sprocs, if any, in the application + * the exit code of the process is the exit code of the primordial + * sproc */ - prctl(PR_SETEXITSIG, SIGKILL); - exit(status); + if (!_PR_IS_NATIVE_THREAD(me) && (_PR_MD_CURRENT_CPU()->id == 0)) { + /* + * primordial sproc case: call _exit directly + * Cause SIGKILL to be sent to other sprocs + */ + prctl(PR_SETEXITSIG, SIGKILL); + _exit(status); + } else { + int rv; + char data; + sigset_t set; + + /* + * non-primordial sproc case: cause the primordial sproc, cpu 0, + * to wakeup and call _exit + */ + _pr_irix_process_exit = 1; + _pr_irix_process_exit_code = status; + rv = write(_pr_irix_primoridal_cpu_fd[1], &data, 1); + PR_ASSERT(rv == 1); + /* + * block all signals and wait for SIGKILL to terminate this sproc + */ + sigfillset(&set); + sigsuspend(&set); + /* + * this code doesn't (shouldn't) execute + */ + prctl(PR_SETEXITSIG, SIGKILL); + _exit(status); + } +} + +/* + * Override the exit() function in libc to cause the process to exit + * when the primodial/main nspr thread calls exit. Calls to exit by any + * other thread simply result in a call to the exit function in libc. + * The exit code of the process is the exit code of the primordial + * sproc. + */ + +void exit(int status) +{ +PRThread *me, *thr; +PRCList *qp; +void __exit(int status); + + if (!_pr_initialized) + __exit(status); + + me = _PR_MD_CURRENT_THREAD(); + + if (me == NULL) /* detached thread */ + (*libc_exit)(status); + + PR_ASSERT(_PR_IS_NATIVE_THREAD(me) || + (_PR_MD_CURRENT_CPU())->id == me->cpu->id); + + if (me->flags & _PR_PRIMORDIAL) { + + me->flags |= _PR_BOUND_THREAD; + + PR_ASSERT((_PR_MD_CURRENT_CPU())->id == me->cpu->id); + if (me->cpu->id != 0) { + _PRCPU *cpu = _pr_primordialCPU; + PRIntn is; + + _PR_INTSOFF(is); + _PR_RUNQ_LOCK(cpu); + me->cpu = cpu; + me->state = _PR_RUNNABLE; + _PR_ADD_RUNQ(me, cpu, me->priority); + _PR_RUNQ_UNLOCK(cpu); + _MD_Wakeup_CPUs(); + + _PR_MD_SWITCH_CONTEXT(me); + + _PR_FAST_INTSON(is); + } + + PR_ASSERT((_PR_MD_CURRENT_CPU())->id == 0); + + if (prctl(PR_GETNSHARE) > 1) { +#define SPROC_EXIT_WAIT_TIME 5 + int sleep_cnt = SPROC_EXIT_WAIT_TIME; + + /* + * sprocs still running; caue cpus and recycled global threads + * to exit + */ + _pr_irix_exit_now = 1; + if (_pr_numCPU > 1) { + _MD_Wakeup_CPUs(); + } + _PR_DEADQ_LOCK; + if (_PR_NUM_DEADNATIVE != 0) { + PRThread *thread; + PRCList *ptr; + + ptr = _PR_DEADNATIVEQ.next; + while( ptr != &_PR_DEADNATIVEQ ) { + thread = _PR_THREAD_PTR(ptr); + _MD_CVAR_POST_SEM(thread); + ptr = ptr->next; + } + } + + while (sleep_cnt-- > 0) { + if (waitpid(0, NULL, WNOHANG) >= 0) + sleep(1); + else + break; + } + prctl(PR_SETEXITSIG, SIGKILL); + } + (*libc_exit)(status); + } else { + /* + * non-primordial thread; simply call exit in libc. + */ + (*libc_exit)(status); + } } + void _MD_InitRunningCPU(_PRCPU *cpu) { @@ -882,11 +1178,9 @@ _MD_SuspendThread(PRThread *thread) void _MD_ResumeThread(PRThread *thread) { - PRInt32 rv; - PR_ASSERT((thread->flags & _PR_GLOBAL_SCOPE) && (thread->flags & _PR_GCABLE_THREAD)); - rv = unblockproc(thread->md.id); + (void)unblockproc(thread->md.id); } /* @@ -902,7 +1196,7 @@ PRInt32 _MD_GetThreadAffinityMask(PRThread *unused, PRUint32 *mask) nprocs = sysmp(MP_NPROCS); if (nprocs < 0) return(-1); - pstat = PR_MALLOC(sizeof(struct pda_stat) * nprocs); + pstat = (struct pda_stat*)PR_MALLOC(sizeof(struct pda_stat) * nprocs); if (pstat == NULL) return(-1); rv = sysmp(MP_STAT, pstat); @@ -938,13 +1232,13 @@ static char *_thr_state[] = { "DEAD" }; -_PR_List_Threads() +void _PR_List_Threads() { PRThread *thr; void *handle; struct _PRCPU *cpu; PRCList *qp; - int len, status, rv, fd; + int len, fd; char pidstr[24]; char path[24]; prpsinfo_t pinfo; @@ -1097,6 +1391,7 @@ void _MD_EarlyInit(void) #if !defined(_PR_PTHREADS) char *eval; int fd; + extern int __ateachexit(void (*func)(void)); sigemptyset(&ints_off); sigaddset(&ints_off, SIGALRM); @@ -1116,23 +1411,26 @@ void _MD_EarlyInit(void) * This region exists at the same address, _nspr_sproc_private, for * every sproc, but each sproc gets a private copy of the region. */ - _nspr_sproc_private = mmap(0, _pr_pageSize, PROT_READ | PROT_WRITE, + _nspr_sproc_private = (char*)mmap(0, _pr_pageSize, PROT_READ | PROT_WRITE, MAP_PRIVATE| MAP_LOCAL, fd, 0); if (_nspr_sproc_private == (void*)-1) { perror("mmap /dev/zero failed"); exit(1); } + _MD_SET_SPROC_PID(getpid()); close(fd); + __ateachexit(irix_detach_sproc); #endif - _MD_IntervalInit(); + _MD_IrixIntervalInit(); } /* _MD_EarlyInit */ void _MD_IrixInit() { #if !defined(_PR_PTHREADS) struct sigaction sigact; - rlim_t stack_max_limit; PRThread *me = _PR_MD_CURRENT_THREAD(); + void *libc_handle; + int rv; #ifndef IRIX5_3 /* @@ -1161,48 +1459,60 @@ void _MD_IrixInit() /* * Irix-specific terminate on error processing */ - if (_nspr_terminate_on_error) { + /* + * PR_SETABORTSIG is a new command implemented in a patch to + * Irix 6.2, 6.3 and 6.4. This causes a signal to be sent to all + * sprocs in the process when one of them terminates abnormally + * + */ + if (prctl(PR_SETABORTSIG, SIGKILL) < 0) { /* - * PR_SETABORTSIG is a new command implemented in a patch to - * Irix 6.2, 6.3 and 6.4. This causes a signal to be sent to all - * sprocs in the process when one of them terminates abnormally + * if (errno == EINVAL) + * + * PR_SETABORTSIG not supported under this OS. + * You may want to get a recent kernel rollup patch that + * supports this feature. * */ - if (prctl(PR_SETABORTSIG, SIGKILL) < 0) { - /* - * if (errno == EINVAL) - * - * PR_SETABORTSIG not supported under this OS. - * You may want to get a recent kernel rollup patch that - * supports this feature. - * - */ - /* - * PR_SETEXITSIG - send the SIGCLD signal to the parent - * sproc when any sproc terminates - * - * This is used to cause the entire application to - * terminate when any sproc terminates abnormally by - * receipt of a SIGSEGV, SIGBUS or SIGABRT signal. - * If this is not done, the application may seem - * "hung" to the user because the other sprocs may be - * waiting for resources held by the - * abnormally-terminating sproc. - */ - prctl(PR_SETEXITSIG, 0); - - sigact.sa_handler = sigchld_handler; - sigact.sa_flags = SA_RESTART; - sigact.sa_mask = ints_off; - sigaction(SIGCLD, &sigact, NULL); - } } + /* + * PR_SETEXITSIG - send the SIGCLD signal to the parent + * sproc when any sproc terminates + * + * This is used to cause the entire application to + * terminate when any sproc terminates abnormally by + * receipt of a SIGSEGV, SIGBUS or SIGABRT signal. + * If this is not done, the application may seem + * "hung" to the user because the other sprocs may be + * waiting for resources held by the + * abnormally-terminating sproc. + */ + prctl(PR_SETEXITSIG, 0); + + sigact.sa_handler = sigchld_handler; + sigact.sa_flags = SA_RESTART; + sigact.sa_mask = ints_off; + sigaction(SIGCLD, &sigact, NULL); /* * setup stack fields for the primordial thread */ me->stack->stackSize = prctl(PR_GETSTACKSIZE); me->stack->stackBottom = me->stack->stackTop - me->stack->stackSize; + + rv = pipe(_pr_irix_primoridal_cpu_fd); + PR_ASSERT(rv == 0); +#ifndef _PR_USE_POLL + _PR_IOQ_MAX_OSFD(me->cpu) = _pr_irix_primoridal_cpu_fd[0]; + FD_SET(_pr_irix_primoridal_cpu_fd[0], &_PR_FD_READ_SET(me->cpu)); +#endif + + libc_handle = dlopen("libc.so",RTLD_NOW); + PR_ASSERT(libc_handle != NULL); + libc_exit = (void (*)(int)) dlsym(libc_handle, "exit"); + PR_ASSERT(libc_exit != NULL); + /* dlclose(libc_handle); */ + #endif /* _PR_PTHREADS */ _PR_UnixInit(); @@ -1218,7 +1528,7 @@ void _MD_IrixInit() #define SGI_CYCLECNTR_SIZE 165 /* Size user needs to use to read CC */ #endif -static PRUintn mmem_fd = -1; +static PRIntn mmem_fd = -1; static PRIntn clock_width = 0; static void *iotimer_addr = NULL; static PRUint32 pr_clock_mask = 0; @@ -1230,7 +1540,7 @@ static PRUint32 pr_previous = 0, pr_residual = 0; extern PRIntervalTime _PR_UNIX_GetInterval(void); extern PRIntervalTime _PR_UNIX_TicksPerSecond(void); -void _MD_IntervalInit(void) +static void _MD_IrixIntervalInit() { /* * As much as I would like, the service available through this @@ -1290,14 +1600,14 @@ void _MD_IntervalInit(void) ((__psunsigned_t)iotimer_addr + (phys_addr & poffmask)); } -} /* _PR_MD_INTERVAL_INIT */ +} /* _MD_IrixIntervalInit */ -PRIntervalTime _MD_IntervalPerSec() +PRIntervalTime _MD_IrixIntervalPerSec() { return pr_clock_granularity; } -PRIntervalTime _MD_GetInterval() +PRIntervalTime _MD_IrixGetInterval() { if (mmem_fd != -1) { @@ -1333,5 +1643,5 @@ PRIntervalTime _MD_GetInterval() pr_ticks *= (PR_CLOCK_GRANULARITY / _PR_UNIX_TicksPerSecond()); } return pr_ticks; -} /* _MD_GetInterval */ +} /* _MD_IrixGetInterval */ diff --git a/pr/src/md/unix/ncr.c b/pr/src/md/unix/ncr.c index 1560cc2c..a22a3b96 100644 --- a/pr/src/md/unix/ncr.c +++ b/pr/src/md/unix/ncr.c @@ -89,6 +89,15 @@ _MD_ATOMIC_INCREMENT(PRInt32 *val) } void +_MD_ATOMIC_ADD(PRInt32 *ptr, PRInt32 val) +{ + flockfile(_uw_semf); + (*ptr) += val; + unflockfile(_uw_semf); +} + + +void _MD_ATOMIC_DECREMENT(PRInt32 *val) { flockfile(_uw_semf); diff --git a/pr/src/md/unix/objs.mk b/pr/src/md/unix/objs.mk index 315a6e29..1d321324 100644 --- a/pr/src/md/unix/objs.mk +++ b/pr/src/md/unix/objs.mk @@ -23,6 +23,7 @@ CSRCS = \ unix_errors.c \ uxproces.c \ uxwrap.c \ + uxpoll.c \ $(NULL) PTH_USER_CSRCS = \ @@ -53,6 +54,10 @@ NETBSD_CSRCS = \ netbsd.c \ $(NULL) +OPENBSD_CSRCS = \ + openbsd.c \ + $(NULL) + BSDI_CSRCS = \ bsdi.c \ $(NULL) @@ -127,6 +132,9 @@ endif ifeq ($(OS_ARCH),NetBSD) CSRCS += $(NETBSD_CSRCS) endif +ifeq ($(OS_ARCH),OpenBSD) +CSRCS += $(OPENBSD_CSRCS) +endif ifeq ($(OS_ARCH),BSD_OS) CSRCS += $(BSDI_CSRCS) endif @@ -179,8 +187,10 @@ ifeq ($(OS_ARCH),SunOS) ASFILES = os_$(OS_ARCH)_x86.s else ifneq ($(OS_RELEASE),4.1.3_U1) + ifneq ($(LOCAL_THREADS_ONLY),1) ASFILES = os_$(OS_ARCH).s endif + endif endif endif @@ -188,6 +198,10 @@ ifeq ($(OS_ARCH), SINIX) ASFILES = os_ReliantUNIX.s endif +ifeq ($(OS_ARCH), IRIX) + ASFILES = os_Irix.s +endif + ifeq ($(OS_ARCH)$(OS_RELEASE),BSD_OS2.1) ASFILES = os_BSD_386_2.s endif diff --git a/pr/src/md/unix/openbsd.c b/pr/src/md/unix/openbsd.c new file mode 100644 index 00000000..1ad32d9f --- /dev/null +++ b/pr/src/md/unix/openbsd.c @@ -0,0 +1,102 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "NPL"); you may not use this file except in + * compliance with the NPL. You may obtain a copy of the NPL at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the NPL is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL + * for the specific language governing rights and limitations under the + * NPL. + * + * The Initial Developer of this code under the NPL is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All Rights + * Reserved. + */ + +#include "primpl.h" + +#include <signal.h> +#include <poll.h> +#include <sys/syscall.h> + +void _MD_EarlyInit(void) +{ + /* + * Ignore FPE because coercion of a NaN to an int causes SIGFPE + * to be raised. + */ + struct sigaction act; + + act.sa_handler = SIG_IGN; + sigemptyset(&act.sa_mask); + act.sa_flags = SA_RESTART; + sigaction(SIGFPE, &act, 0); +} + +PRWord *_MD_HomeGCRegisters(PRThread *t, int isCurrent, int *np) +{ +#ifndef _PR_PTHREADS + if (isCurrent) { + (void) sigsetjmp(CONTEXT(t), 1); + } + *np = sizeof(CONTEXT(t)) / sizeof(PRWord); + return (PRWord *) CONTEXT(t); +#else + *np = 0; + return NULL; +#endif +} + +#ifndef _PR_PTHREADS +void +_MD_SET_PRIORITY(_MDThread *thread, PRUintn newPri) +{ + return; +} + +PRStatus +_MD_InitializeThread(PRThread *thread) +{ + return PR_SUCCESS; +} + +PRStatus +_MD_WAIT(PRThread *thread, PRIntervalTime ticks) +{ + PR_ASSERT(!(thread->flags & _PR_GLOBAL_SCOPE)); + _PR_MD_SWITCH_CONTEXT(thread); + return PR_SUCCESS; +} + +PRStatus +_MD_WAKEUP_WAITER(PRThread *thread) +{ + if (thread) { + PR_ASSERT(!(thread->flags & _PR_GLOBAL_SCOPE)); + } + return PR_SUCCESS; +} + +/* These functions should not be called for OpenBSD */ +void +_MD_YIELD(void) +{ + PR_NOT_REACHED("_MD_YIELD should not be called for OpenBSD."); +} + +PRStatus +_MD_CREATE_THREAD( + PRThread *thread, + void (*start) (void *), + PRThreadPriority priority, + PRThreadScope scope, + PRThreadState state, + PRUint32 stackSize) +{ + PR_NOT_REACHED("_MD_CREATE_THREAD should not be called for OpenBSD."); + return PR_FAILURE; +} +#endif /* ! _PR_PTHREADS */ diff --git a/pr/src/md/unix/os_Irix.s b/pr/src/md/unix/os_Irix.s new file mode 100644 index 00000000..5d92fb67 --- /dev/null +++ b/pr/src/md/unix/os_Irix.s @@ -0,0 +1,89 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "NPL"); you may not use this file except in + * compliance with the NPL. You may obtain a copy of the NPL at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the NPL is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL + * for the specific language governing rights and limitations under the + * NPL. + * + * The Initial Developer of this code under the NPL is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All Rights + * Reserved. + */ + +/* + * Atomically add a new element to the top of the stack + * + * usage : PR_StackPush(listp, elementp); + * ----------------------- + */ + +#include "md/_irix.h" +#ifdef _PR_HAVE_ATOMIC_CAS + +#include <sys/asm.h> +#include <sys/regdef.h> + +LEAF(PR_StackPush) + +retry_push: +.set noreorder + lw v0,0(a0) + li t1,1 + beq v0,t1,retry_push + move t0,a1 + + ll v0,0(a0) + beq v0,t1,retry_push + nop + sc t1,0(a0) + beq t1,0,retry_push + nop + sw v0,0(a1) + sync + sw t0,0(a0) + jr ra + nop + +END(PR_StackPush) + +/* + * + * Atomically remove the element at the top of the stack + * + * usage : elemep = PR_StackPop(listp); + * + */ + +LEAF(PR_StackPop) +retry_pop: +.set noreorder + + + lw v0,0(a0) + li t1,1 + beq v0,0,done + beq v0,t1,retry_pop + nop + + ll v0,0(a0) + beq v0,0,done + beq v0,t1,retry_pop + nop + sc t1,0(a0) + beq t1,0,retry_pop + nop + lw t0,0(v0) + sw t0,0(a0) +done: + jr ra + nop + +END(PR_StackPop) + +#endif /* _PR_HAVE_ATOMIC_CAS */ diff --git a/pr/src/md/unix/os_SunOS.s b/pr/src/md/unix/os_SunOS.s index 2edf276f..bbad267c 100644 --- a/pr/src/md/unix/os_SunOS.s +++ b/pr/src/md/unix/os_SunOS.s @@ -49,3 +49,86 @@ _MD_FlushRegisterWindows: ret restore +! ====================================================================== +! +! Atomically add a new element to the top of the stack +! +! usage : PR_StackPush(listp, elementp); +! +! ----------------------- +! Note on REGISTER USAGE: +! as this is a LEAF procedure, a new stack frame is not created. +! +! So, the registers used are: +! %o0 [input] - the address of the stack +! %o1 [input] - the address of the element to be added to the stack +! ----------------------- + + .section ".text" + .global PR_StackPush + +PR_StackPush: + +pulock: ld [%o0],%o3 ! + cmp %o3,-1 ! check if stack is locked + be pulock ! loop, if locked + mov -1,%o3 ! use delay-slot + swap [%o0],%o3 ! atomically lock the stack and get + ! the pointer to stack head + cmp %o3,-1 ! check, if the stack is locked + be pulock ! loop, if so + nop + st %o3,[%o1] + retl ! return back to the caller + st %o1,[%o0] ! + + .size PR_StackPush,(.-PR_StackPush) + + +! end +! ====================================================================== + +! ====================================================================== +! +! Atomically remove the element at the top of the stack +! +! usage : elemep = PR_StackPop(listp); +! +! ----------------------- +! Note on REGISTER USAGE: +! as this is a LEAF procedure, a new stack frame is not created. +! +! So, the registers used are: +! %o0 [input] - the address of the stack +! %o1 [input] - work register (top element) +! ----------------------- + + .section ".text" + .global PR_StackPop + +PR_StackPop: + +polock: ld [%o0],%o1 ! + cmp %o1,-1 ! check if stack is locked + be polock ! loop, if locked + mov -1,%o1 ! use delay-slot + swap [%o0],%o1 ! atomically lock the stack and get + ! the pointer to stack head + cmp %o1,-1 ! check, if the stack is locked + be polock ! loop, if so + nop + tst %o1 ! test for empty stack + be,a empty ! is empty + st %g0,[%o0] + ld [%o1], %o2 ! load the second element + st %o2,[%o0] ! set stack head to second + st %g0,[%o1] ! reset the next pointer; for + ! debugging +empty: + retl ! return back to the caller + mov %o1, %o0 ! return the first element + + .size PR_StackPop,(.-PR_StackPop) + +! end +! ====================================================================== diff --git a/pr/src/md/unix/os_SunOS_ultrasparc.s b/pr/src/md/unix/os_SunOS_ultrasparc.s index 1391a9bc..8dd70636 100644 --- a/pr/src/md/unix/os_SunOS_ultrasparc.s +++ b/pr/src/md/unix/os_SunOS_ultrasparc.s @@ -155,3 +155,30 @@ retryAS: ! ! ====================================================================== ! + +! ====================================================================== +! +! Perform the sequence a = a + b atomically with respect to other +! fetch-and-adds to location a in a wait-free fashion. +! +! usage : newval = PR_AtomicAdd(address, val) +! return: the value after addition +! + ENTRY(PR_AtomicAdd) ! standard assembler/ELF prologue + +retryAA: + ld [%o0], %o2 ! set o2 to the current value + add %o2, %o1, %o3 ! calc the new value + mov %o3, %o4 ! save the return value + cas [%o0], %o2, %o3 ! atomically set if o0 hasn't changed + cmp %o2, %o3 ! see if we set the value + bne retryAA ! if not, try again + nop ! empty out the branch pipeline + retl ! return back to the caller + mov %o4, %o0 ! set the return code to the new value + + SET_SIZE(PR_AtomicAdd) ! standard assembler/ELF epilogue + +! +! end +! diff --git a/pr/src/md/unix/osf1.c b/pr/src/md/unix/osf1.c index e79e6607..5b02adb2 100644 --- a/pr/src/md/unix/osf1.c +++ b/pr/src/md/unix/osf1.c @@ -86,3 +86,60 @@ _MD_CREATE_THREAD( return PR_FAILURE; } #endif /* ! _PR_PTHREADS */ + +#ifdef _PR_HAVE_ATOMIC_CAS + +#include <c_asm.h> + +#define _PR_OSF_ATOMIC_LOCK 1 + +void +PR_StackPush(PRStack *stack, PRStackElem *stack_elem) +{ +long locked; + + do { + while ((long) stack->prstk_head.prstk_elem_next == + _PR_OSF_ATOMIC_LOCK) + ; + locked = __ATOMIC_EXCH_QUAD(&stack->prstk_head.prstk_elem_next, + _PR_OSF_ATOMIC_LOCK); + + } while (locked == _PR_OSF_ATOMIC_LOCK); + stack_elem->prstk_elem_next = (PRStackElem *) locked; + /* + * memory-barrier instruction + */ + asm("mb"); + stack->prstk_head.prstk_elem_next = stack_elem; +} + +PRStackElem * +PR_StackPop(PRStack *stack) +{ +PRStackElem *element; +long locked; + + do { + while ((long)stack->prstk_head.prstk_elem_next == _PR_OSF_ATOMIC_LOCK) + ; + locked = __ATOMIC_EXCH_QUAD(&stack->prstk_head.prstk_elem_next, + _PR_OSF_ATOMIC_LOCK); + + } while (locked == _PR_OSF_ATOMIC_LOCK); + + element = (PRStackElem *) locked; + + if (element == NULL) { + stack->prstk_head.prstk_elem_next = NULL; + } else { + stack->prstk_head.prstk_elem_next = + element->prstk_elem_next; + } + /* + * memory-barrier instruction + */ + asm("mb"); + return element; +} +#endif /* _PR_HAVE_ATOMIC_CAS */ diff --git a/pr/src/md/unix/pthreads_user.c b/pr/src/md/unix/pthreads_user.c index 63908b21..08fea163 100644 --- a/pr/src/md/unix/pthreads_user.c +++ b/pr/src/md/unix/pthreads_user.c @@ -38,10 +38,6 @@ void _MD_EarlyInit(void) { extern PRInt32 _nspr_noclock; -#ifdef HPUX - _MD_hpux_install_sigfpe_handler(); -#endif - if (pthread_key_create(¤t_thread_key, NULL) != 0) { perror("pthread_key_create failed"); exit(1); @@ -355,6 +351,7 @@ _MD_CreateThread( PRUint32 stackSize) { PRIntn is; + int rv; PRThread *me = _PR_MD_CURRENT_THREAD(); pthread_attr_t attr; @@ -386,8 +383,8 @@ _MD_CreateThread( } thread->md.wait = 0; - if (pthread_create(&thread->md.pthread, &attr, start, (void *)thread) - == 0) { + rv = pthread_create(&thread->md.pthread, &attr, start, (void *)thread); + if (0 == rv) { _MD_ATOMIC_INCREMENT(&_pr_md_pthreads_created); _MD_ATOMIC_INCREMENT(&_pr_md_pthreads); if (!_PR_IS_NATIVE_THREAD(me)) @@ -400,6 +397,7 @@ _MD_CreateThread( _MD_ATOMIC_INCREMENT(&_pr_md_pthreads_failed); if (!_PR_IS_NATIVE_THREAD(me)) _PR_FAST_INTSON(is); + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, rv); return PR_FAILURE; } } @@ -413,7 +411,9 @@ _MD_InitRunningCPU(struct _PRCPU *cpu) cpu->md.pthread = pthread_self(); if (_pr_md_pipefd[0] >= 0) { _PR_IOQ_MAX_OSFD(cpu) = _pr_md_pipefd[0]; +#ifndef _PR_USE_POLL FD_SET(_pr_md_pipefd[0], &_PR_FD_READ_SET(cpu)); +#endif } } diff --git a/pr/src/md/unix/rhapsody.c b/pr/src/md/unix/rhapsody.c index a68f8667..01a73650 100644 --- a/pr/src/md/unix/rhapsody.c +++ b/pr/src/md/unix/rhapsody.c @@ -18,25 +18,13 @@ #include "primpl.h" -#include <signal.h> - void _MD_EarlyInit(void) { - /* - * Ignore FPE because coercion of a NaN to an int causes SIGFPE - * to be raised. - */ - struct sigaction act; - - act.sa_handler = SIG_IGN; - sigemptyset(&act.sa_mask); - act.sa_flags = SA_RESTART; - sigaction(SIGFPE, &act, 0); } PRWord *_MD_HomeGCRegisters(PRThread *t, int isCurrent, int *np) { -#ifndef _PR_PTHREADS +#if !defined(_PR_PTHREADS) if (isCurrent) { (void) setjmp(CONTEXT(t)); } @@ -48,7 +36,7 @@ PRWord *_MD_HomeGCRegisters(PRThread *t, int isCurrent, int *np) #endif } -#ifndef _PR_PTHREADS +#if !defined(_PR_PTHREADS) void _MD_SET_PRIORITY(_MDThread *thread, PRUintn newPri) { @@ -98,3 +86,14 @@ _MD_CREATE_THREAD( return PR_FAILURE; } #endif /* ! _PR_PTHREADS */ + +/* +** Whoops, we don't have a syscall stub for this +*/ +int mprotect (caddr_t addr, size_t size, int prot) +{ + return -1; +} + +/* rhapsody.c */ + diff --git a/pr/src/md/unix/scoos.c b/pr/src/md/unix/scoos.c index 14365e8e..7b812aa0 100644 --- a/pr/src/md/unix/scoos.c +++ b/pr/src/md/unix/scoos.c @@ -89,6 +89,14 @@ _MD_ATOMIC_INCREMENT(PRInt32 *val) } void +_MD_ATOMIC_ADD(PRInt32 *ptr, PRInt32 val) +{ + flockfile(_uw_semf); + (*ptr) += val; + unflockfile(_uw_semf); +} + +void _MD_ATOMIC_DECREMENT(PRInt32 *val) { flockfile(_uw_semf); diff --git a/pr/src/md/unix/solaris.c b/pr/src/md/unix/solaris.c index b102aa36..882cbca4 100644 --- a/pr/src/md/unix/solaris.c +++ b/pr/src/md/unix/solaris.c @@ -16,6 +16,8 @@ * Reserved. */ +#undef _FILE_OFFSET_BITS + #include "primpl.h" @@ -100,6 +102,21 @@ _MD_AtomicIncrement(PRInt32 *val) } PRInt32 +_MD_AtomicAdd(PRInt32 *ptr, PRInt32 val) +{ + PRInt32 rv; + if (mutex_lock(&_solaris_atomic) != 0) + PR_ASSERT(0); + + rv = ((*ptr) += val); + + if (mutex_unlock(&_solaris_atomic) != 0)\ + PR_ASSERT(0); + + return rv; +} + +PRInt32 _MD_AtomicDecrement(PRInt32 *val) { PRInt32 rv; @@ -171,8 +188,18 @@ PRStatus _MD_CreateThread(PRThread *thread, /* mask out SIGALRM for native thread creation */ thr_sigsetmask(SIG_BLOCK, &set, &oldset); - flags = (state == PR_JOINABLE_THREAD) ? - THR_SUSPENDED : THR_SUSPENDED|THR_DETACHED; + /* + * Note that we create joinable threads with the THR_DETACHED + * flag. The reasons why we don't use thr_join to implement + * PR_JoinThread are: + * - We use a termination condition variable in the PRThread + * structure to implement PR_JoinThread across all classic + * nspr implementation strategies. + * - The native threads may be recycled by NSPR to run other + * new NSPR threads, so the native threads may not terminate + * when the corresponding NSPR threads terminate. + */ + flags = THR_SUSPENDED|THR_DETACHED; if (thread->flags & (_PR_GCABLE_THREAD|_PR_BOUND_THREAD)) flags |= THR_BOUND; diff --git a/pr/src/md/unix/unix.c b/pr/src/md/unix/unix.c index c3abd131..dd7e6d91 100644 --- a/pr/src/md/unix/unix.c +++ b/pr/src/md/unix/unix.c @@ -18,6 +18,7 @@ #include "primpl.h" +#include <string.h> #include <signal.h> #include <unistd.h> #include <memory.h> @@ -29,7 +30,7 @@ #include <sys/mman.h> #ifdef _PR_POLL_AVAILABLE -#include <poll.h> +#include <sys/poll.h> #endif /* To get FIONREAD */ @@ -48,7 +49,7 @@ || defined(SUNOS4) || defined(NCR) || defined(RHAPSODY) #define _PRSockLen_t int #elif (defined(AIX) && !defined(AIX4_1)) || defined(FREEBSD) \ - || defined(NETBSD) || defined(UNIXWARE) || defined(DGUX) + || defined(NETBSD) || defined(OPENBSD) || defined(UNIXWARE) || defined(DGUX) #define _PRSockLen_t size_t #else #error "Cannot determine architecture" @@ -69,6 +70,7 @@ static PRMonitor *_pr_Xfe_mon = NULL; * to be a global variable for now. */ PRInt32 _pr_zero_fd = -1; +static PRInt64 minus_one; static PRLock *_pr_md_lock = NULL; sigset_t timer_set; @@ -108,46 +110,48 @@ extern PRInt32 _nspr_terminate_on_error; int _pr_md_pipefd[2] = { -1, -1 }; static char _pr_md_pipebuf[PIPE_BUF]; +static PRInt32 local_io_wait(PRInt32 osfd, PRInt32 wait_flag, + PRIntervalTime timeout); _PRInterruptTable _pr_interruptTable[] = { - { - "clock", _PR_MISSED_CLOCK, _PR_ClockInterrupt, }, - { - 0 } + { + "clock", _PR_MISSED_CLOCK, _PR_ClockInterrupt, }, + { + 0 } }; PR_IMPLEMENT(void) _MD_unix_init_running_cpu(_PRCPU *cpu) { - PR_INIT_CLIST(&(cpu->md.md_unix.ioQ)); - cpu->md.md_unix.ioq_max_osfd = -1; - cpu->md.md_unix.ioq_timeout = PR_INTERVAL_NO_TIMEOUT; + PR_INIT_CLIST(&(cpu->md.md_unix.ioQ)); + cpu->md.md_unix.ioq_max_osfd = -1; + cpu->md.md_unix.ioq_timeout = PR_INTERVAL_NO_TIMEOUT; } PRStatus _MD_open_dir(_MDDir *d, const char *name) { int err; - d->d = opendir(name); - if (!d->d) { - err = _MD_ERRNO(); - _PR_MD_MAP_OPENDIR_ERROR(err); - return PR_FAILURE; - } - return PR_SUCCESS; + d->d = opendir(name); + if (!d->d) { + err = _MD_ERRNO(); + _PR_MD_MAP_OPENDIR_ERROR(err); + return PR_FAILURE; + } + return PR_SUCCESS; } PRInt32 _MD_close_dir(_MDDir *d) { int rv = 0, err; - if (d->d) { - rv = closedir(d->d); - if (rv == -1) { - err = _MD_ERRNO(); - _PR_MD_MAP_CLOSEDIR_ERROR(err); - } - } - return rv; + if (d->d) { + rv = closedir(d->d); + if (rv == -1) { + err = _MD_ERRNO(); + _PR_MD_MAP_CLOSEDIR_ERROR(err); + } + } + return rv; } char * _MD_read_dir(_MDDir *d, PRIntn flags) @@ -155,144 +159,56 @@ char * _MD_read_dir(_MDDir *d, PRIntn flags) struct dirent *de; int err; - for (;;) { - /* - * XXX: readdir() is not MT-safe. There is an MT-safe version - * readdir_r() on some systems. - */ - de = readdir(d->d); - if (!de) { - err = _MD_ERRNO(); - _PR_MD_MAP_READDIR_ERROR(err); - return 0; - } - if ((flags & PR_SKIP_DOT) && - (de->d_name[0] == '.') && (de->d_name[1] == 0)) - continue; - if ((flags & PR_SKIP_DOT_DOT) && - (de->d_name[0] == '.') && (de->d_name[1] == '.') && - (de->d_name[2] == 0)) - continue; - if ((flags & PR_SKIP_HIDDEN) && (de->d_name[0] == '.')) - continue; - break; - } - return de->d_name; + for (;;) { + /* + * XXX: readdir() is not MT-safe. There is an MT-safe version + * readdir_r() on some systems. + */ + de = readdir(d->d); + if (!de) { + err = _MD_ERRNO(); + _PR_MD_MAP_READDIR_ERROR(err); + return 0; + } + if ((flags & PR_SKIP_DOT) && + (de->d_name[0] == '.') && (de->d_name[1] == 0)) + continue; + if ((flags & PR_SKIP_DOT_DOT) && + (de->d_name[0] == '.') && (de->d_name[1] == '.') && + (de->d_name[2] == 0)) + continue; + if ((flags & PR_SKIP_HIDDEN) && (de->d_name[0] == '.')) + continue; + break; + } + return de->d_name; } PRInt32 _MD_delete(const char *name) { PRInt32 rv, err; #ifdef UNIXWARE - sigset_t set, oset; + sigset_t set, oset; #endif #ifdef UNIXWARE - sigfillset(&set); - sigprocmask(SIG_SETMASK, &set, &oset); + sigfillset(&set); + sigprocmask(SIG_SETMASK, &set, &oset); #endif - rv = unlink(name); + rv = unlink(name); #ifdef UNIXWARE - sigprocmask(SIG_SETMASK, &oset, NULL); + sigprocmask(SIG_SETMASK, &oset, NULL); #endif - if (rv == -1) { - err = _MD_ERRNO(); - _PR_MD_MAP_UNLINK_ERROR(err); - } - return(rv); -} - -PRInt32 _MD_getfileinfo(const char *fn, PRFileInfo *info) -{ - struct stat sb; - PRInt64 s, s2us; - PRInt32 rv, err; - - rv = stat(fn, &sb); - if (rv < 0) { - err = _MD_ERRNO(); - _PR_MD_MAP_STAT_ERROR(err); - } else if (info) { - if (S_IFREG & sb.st_mode) - info->type = PR_FILE_FILE ; - else if (S_IFDIR & sb.st_mode) - info->type = PR_FILE_DIRECTORY; - else - info->type = PR_FILE_OTHER; - info->size = sb.st_size; - LL_I2L(s, sb.st_mtime); - LL_I2L(s2us, PR_USEC_PER_SEC); - LL_MUL(s, s, s2us); - info->modifyTime = s; - LL_I2L(s, sb.st_ctime); - LL_MUL(s, s, s2us); - info->creationTime = s; - } - return rv; -} - -PRInt32 _MD_getfileinfo64(const char *fn, PRFileInfo64 *info) -{ - PRFileInfo info32; - PRInt32 rv = _MD_getfileinfo(fn, &info32); - if (rv >= 0) - { - info->type = info32.type; - LL_I2L(info->size, info32.size); - info->modifyTime = info32.modifyTime; - info->creationTime = info32.creationTime; - } - return rv; -} - -PRInt32 _MD_getopenfileinfo(const PRFileDesc *fd, PRFileInfo *info) -{ - struct stat sb; - PRInt64 s, s2us; - PRInt32 rv, err; - - rv = fstat(fd->secret->md.osfd, &sb); - if (rv < 0) { - err = _MD_ERRNO(); - _PR_MD_MAP_FSTAT_ERROR(err); - } else if (info) { - if (info) { - if (S_IFREG & sb.st_mode) - info->type = PR_FILE_FILE ; - else if (S_IFDIR & sb.st_mode) - info->type = PR_FILE_DIRECTORY; - else - info->type = PR_FILE_OTHER; - info->size = sb.st_size; - LL_I2L(s, sb.st_mtime); - LL_I2L(s2us, PR_USEC_PER_SEC); - LL_MUL(s, s, s2us); - info->modifyTime = s; - LL_I2L(s, sb.st_ctime); - LL_MUL(s, s, s2us); - info->creationTime = s; - } - } - return rv; -} - -PRInt32 _MD_getopenfileinfo64(const PRFileDesc *fd, PRFileInfo64 *info) -{ - PRFileInfo info32; - PRInt32 rv = _MD_getopenfileinfo(fd, &info32); - if (rv >= 0) - { - info->type = info32.type; - LL_I2L(info->size, info32.size); - info->modifyTime = info32.modifyTime; - info->creationTime = info32.creationTime; + if (rv == -1) { + err = _MD_ERRNO(); + _PR_MD_MAP_UNLINK_ERROR(err); } - return rv; + return(rv); } PRInt32 _MD_rename(const char *from, const char *to) { - PRInt32 rv = -1, err; + PRInt32 rv = -1, err; /* ** This is trying to enforce the semantics of WINDOZE' rename @@ -306,46 +222,46 @@ PRInt32 _MD_rename(const char *from, const char *to) PR_SetError(PR_FILE_EXISTS_ERROR, 0); else { - rv = rename(from, to); - if (rv < 0) { - err = _MD_ERRNO(); - _PR_MD_MAP_RENAME_ERROR(err); - } + rv = rename(from, to); + if (rv < 0) { + err = _MD_ERRNO(); + _PR_MD_MAP_RENAME_ERROR(err); + } } if (NULL != _pr_rename_lock) PR_Unlock(_pr_rename_lock); - return rv; + return rv; } -PRInt32 _MD_access(const char *name, PRIntn how) +PRInt32 _MD_access(const char *name, PRAccessHow how) { PRInt32 rv, err; int amode; - switch (how) { - case PR_ACCESS_WRITE_OK: - amode = W_OK; - break; - case PR_ACCESS_READ_OK: - amode = R_OK; - break; - case PR_ACCESS_EXISTS: - amode = F_OK; - break; - default: - PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); - rv = -1; - goto done; - } - rv = access(name, amode); + switch (how) { + case PR_ACCESS_WRITE_OK: + amode = W_OK; + break; + case PR_ACCESS_READ_OK: + amode = R_OK; + break; + case PR_ACCESS_EXISTS: + amode = F_OK; + break; + default: + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + rv = -1; + goto done; + } + rv = access(name, amode); - if (rv < 0) { - err = _MD_ERRNO(); - _PR_MD_MAP_ACCESS_ERROR(err); - } + if (rv < 0) { + err = _MD_ERRNO(); + _PR_MD_MAP_ACCESS_ERROR(err); + } done: - return(rv); + return(rv); } PRInt32 _MD_mkdir(const char *name, PRIntn mode) @@ -358,26 +274,26 @@ int rv, err; */ if (NULL !=_pr_rename_lock) PR_Lock(_pr_rename_lock); - rv = mkdir(name, mode); - if (rv < 0) { - err = _MD_ERRNO(); - _PR_MD_MAP_MKDIR_ERROR(err); - } + rv = mkdir(name, mode); + if (rv < 0) { + err = _MD_ERRNO(); + _PR_MD_MAP_MKDIR_ERROR(err); + } if (NULL !=_pr_rename_lock) PR_Unlock(_pr_rename_lock); - return rv; + return rv; } PRInt32 _MD_rmdir(const char *name) { int rv, err; - rv = rmdir(name); - if (rv == -1) { - err = _MD_ERRNO(); - _PR_MD_MAP_RMDIR_ERROR(err); - } - return rv; + rv = rmdir(name); + if (rv == -1) { + err = _MD_ERRNO(); + _PR_MD_MAP_RMDIR_ERROR(err); + } + return rv; } PRInt32 _MD_read(PRFileDesc *fd, void *buf, PRInt32 amount) @@ -392,53 +308,56 @@ struct pollfd pfd; PRInt32 osfd = fd->secret->md.osfd; #ifndef _PR_USE_POLL - FD_ZERO(&rd); - FD_SET(osfd, &rd); + FD_ZERO(&rd); + FD_SET(osfd, &rd); #else - pfd.fd = osfd; - pfd.events = POLLIN; + pfd.fd = osfd; + pfd.events = POLLIN; #endif /* _PR_USE_POLL */ - while ((rv = read(osfd,buf,amount)) == -1) { - err = _MD_ERRNO(); - if ((err == EAGAIN) || (err == EWOULDBLOCK)) { - if (fd->secret->nonblocking) { - break; - } - if (!_PR_IS_NATIVE_THREAD(me)) { - _PR_WaitForFD(osfd, PR_POLL_READ, PR_INTERVAL_NO_TIMEOUT); - } else { + while ((rv = read(osfd,buf,amount)) == -1) { + err = _MD_ERRNO(); + if ((err == EAGAIN) || (err == EWOULDBLOCK)) { + if (fd->secret->nonblocking) { + break; + } + if (!_PR_IS_NATIVE_THREAD(me)) { + if ((rv = local_io_wait(osfd, _PR_UNIX_POLL_READ, + PR_INTERVAL_NO_TIMEOUT)) < 0) + goto done; + } else { #ifndef _PR_USE_POLL - while ((rv = _MD_SELECT(osfd + 1, &rd, NULL, NULL, NULL)) - == -1 && (err = _MD_ERRNO()) == EINTR) { - /* retry _MD_SELECT() if it is interrupted */ - } + while ((rv = _MD_SELECT(osfd + 1, &rd, NULL, NULL, NULL)) + == -1 && (err = _MD_ERRNO()) == EINTR) { + /* retry _MD_SELECT() if it is interrupted */ + } #else /* _PR_USE_POLL */ - while ((rv = _MD_POLL(&pfd, 1, -1)) - == -1 && (err = _MD_ERRNO()) == EINTR) { - /* retry _MD_POLL() if it is interrupted */ - } + while ((rv = _MD_POLL(&pfd, 1, -1)) + == -1 && (err = _MD_ERRNO()) == EINTR) { + /* retry _MD_POLL() if it is interrupted */ + } #endif /* _PR_USE_POLL */ - if (rv == -1) { - break; - } - } - if (_PR_PENDING_INTERRUPT(me)) - break; - } else if ((err == EINTR) && (!_PR_PENDING_INTERRUPT(me))){ - continue; - } else { - break; - } - } - if (rv < 0) { - if (_PR_PENDING_INTERRUPT(me)) { - me->flags &= ~_PR_INTERRUPT; - PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); - } else { - _PR_MD_MAP_READ_ERROR(err); - } - } - return(rv); + if (rv == -1) { + break; + } + } + if (_PR_PENDING_INTERRUPT(me)) + break; + } else if ((err == EINTR) && (!_PR_PENDING_INTERRUPT(me))){ + continue; + } else { + break; + } + } + if (rv < 0) { + if (_PR_PENDING_INTERRUPT(me)) { + me->flags &= ~_PR_INTERRUPT; + PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); + } else { + _PR_MD_MAP_READ_ERROR(err); + } + } +done: + return(rv); } PRInt32 _MD_write(PRFileDesc *fd, const void *buf, PRInt32 amount) @@ -453,146 +372,106 @@ struct pollfd pfd; PRInt32 osfd = fd->secret->md.osfd; #ifndef _PR_USE_POLL - FD_ZERO(&wd); - FD_SET(osfd, &wd); + FD_ZERO(&wd); + FD_SET(osfd, &wd); #else - pfd.fd = osfd; - pfd.events = POLLOUT; + pfd.fd = osfd; + pfd.events = POLLOUT; #endif /* _PR_USE_POLL */ - while ((rv = write(osfd,buf,amount)) == -1) { - err = _MD_ERRNO(); - if ((err == EAGAIN) || (err == EWOULDBLOCK)) { - if (fd->secret->nonblocking) { - break; - } - if (!_PR_IS_NATIVE_THREAD(me)) { - _PR_WaitForFD(osfd, PR_POLL_WRITE, PR_INTERVAL_NO_TIMEOUT); - } else { + while ((rv = write(osfd,buf,amount)) == -1) { + err = _MD_ERRNO(); + if ((err == EAGAIN) || (err == EWOULDBLOCK)) { + if (fd->secret->nonblocking) { + break; + } + if (!_PR_IS_NATIVE_THREAD(me)) { + if ((rv = local_io_wait(osfd, _PR_UNIX_POLL_WRITE, + PR_INTERVAL_NO_TIMEOUT)) < 0) + goto done; + } else { #ifndef _PR_USE_POLL - while ((rv = _MD_SELECT(osfd + 1, NULL, &wd, NULL, NULL)) - == -1 && (err = _MD_ERRNO()) == EINTR) { - /* retry _MD_SELECT() if it is interrupted */ - } + while ((rv = _MD_SELECT(osfd + 1, NULL, &wd, NULL, NULL)) + == -1 && (err = _MD_ERRNO()) == EINTR) { + /* retry _MD_SELECT() if it is interrupted */ + } #else /* _PR_USE_POLL */ - while ((rv = _MD_POLL(&pfd, 1, -1)) - == -1 && (err = _MD_ERRNO()) == EINTR) { - /* retry _MD_POLL() if it is interrupted */ - } + while ((rv = _MD_POLL(&pfd, 1, -1)) + == -1 && (err = _MD_ERRNO()) == EINTR) { + /* retry _MD_POLL() if it is interrupted */ + } #endif /* _PR_USE_POLL */ - if (rv == -1) { - break; - } - } - if (_PR_PENDING_INTERRUPT(me)) - break; - } else if ((err == EINTR) && (!_PR_PENDING_INTERRUPT(me))){ - continue; - } else { - break; - } - } - if (rv < 0) { - if (_PR_PENDING_INTERRUPT(me)) { - me->flags &= ~_PR_INTERRUPT; - PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); - } else { - _PR_MD_MAP_WRITE_ERROR(err); - } - } - return(rv); -} - -PRInt32 _MD_lseek(PRFileDesc *fd, PRInt32 offset, PRSeekWhence whence) -{ -PRInt32 rv, where, err; - - switch (whence) { - case PR_SEEK_SET: - where = SEEK_SET; - break; - case PR_SEEK_CUR: - where = SEEK_CUR; - break; - case PR_SEEK_END: - where = SEEK_END; - break; - default: - PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); - rv = -1; - goto done; - } - rv = lseek(fd->secret->md.osfd,offset,where); - if (rv == -1) { - err = _MD_ERRNO(); - _PR_MD_MAP_LSEEK_ERROR(err); - } + if (rv == -1) { + break; + } + } + if (_PR_PENDING_INTERRUPT(me)) + break; + } else if ((err == EINTR) && (!_PR_PENDING_INTERRUPT(me))){ + continue; + } else { + break; + } + } + if (rv < 0) { + if (_PR_PENDING_INTERRUPT(me)) { + me->flags &= ~_PR_INTERRUPT; + PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); + } else { + _PR_MD_MAP_WRITE_ERROR(err); + } + } done: - return(rv); + return(rv); } -PRInt64 _MD_lseek64(PRFileDesc *fd, PRInt64 offset, PRSeekWhence whence) -{ - PRInt32 off, rv; - PRInt64 on, result = LL_MININT; - LL_L2I(off, offset); - LL_I2L(on, off); - if (LL_EQ(offset, on)) - { - rv = _MD_lseek(fd, off, whence); - if (rv >= 0) LL_I2L(result, rv); - } - else PR_SetError(PR_FILE_TOO_BIG_ERROR, 0); /* overflow */ - return result; -} /* _MD_lseek64 */ - PRInt32 _MD_fsync(PRFileDesc *fd) { PRInt32 rv, err; - rv = fsync(fd->secret->md.osfd); - if (rv == -1) { - err = _MD_ERRNO(); - _PR_MD_MAP_FSYNC_ERROR(err); - } - return(rv); + rv = fsync(fd->secret->md.osfd); + if (rv == -1) { + err = _MD_ERRNO(); + _PR_MD_MAP_FSYNC_ERROR(err); + } + return(rv); } PRInt32 _MD_close(PRInt32 osfd) { PRInt32 rv, err; - rv = close(osfd); - if (rv == -1) { - err = _MD_ERRNO(); - _PR_MD_MAP_CLOSE_ERROR(err); - } - return(rv); + rv = close(osfd); + if (rv == -1) { + err = _MD_ERRNO(); + _PR_MD_MAP_CLOSE_ERROR(err); + } + return(rv); } PRInt32 _MD_socket(PRInt32 domain, PRInt32 type, PRInt32 proto) { - PRInt32 osfd, err; + PRInt32 osfd, err; - osfd = socket(domain, type, proto); + osfd = socket(domain, type, proto); - if (osfd == -1) { - err = _MD_ERRNO(); - _PR_MD_MAP_SOCKET_ERROR(err); - return(osfd); - } + if (osfd == -1) { + err = _MD_ERRNO(); + _PR_MD_MAP_SOCKET_ERROR(err); + return(osfd); + } - return(osfd); + return(osfd); } PRInt32 _MD_socketavailable(PRFileDesc *fd) { - PRInt32 result; + PRInt32 result; - if (ioctl(fd->secret->md.osfd, FIONREAD, &result) < 0) { - _PR_MD_MAP_SOCKETAVAILABLE_ERROR(_MD_ERRNO()); - return -1; - } - return result; + if (ioctl(fd->secret->md.osfd, FIONREAD, &result) < 0) { + _PR_MD_MAP_SOCKETAVAILABLE_ERROR(_MD_ERRNO()); + return -1; + } + return result; } PRInt64 _MD_socketavailable64(PRFileDesc *fd) @@ -602,8 +481,8 @@ PRInt64 _MD_socketavailable64(PRFileDesc *fd) return result; } /* _MD_socketavailable64 */ -#define READ_FD 1 -#define WRITE_FD 2 +#define READ_FD 1 +#define WRITE_FD 2 /* * socket_io_wait -- @@ -619,120 +498,110 @@ PRInt64 _MD_socketavailable64(PRFileDesc *fd) static PRInt32 socket_io_wait(PRInt32 osfd, PRInt32 fd_type, PRIntervalTime timeout) { - PRInt32 rv = -1; - struct timeval tv, *tvp; - PRThread *me = _PR_MD_CURRENT_THREAD(); - PRIntervalTime epoch, now, elapsed, remaining; - PRInt32 syserror; - fd_set rd_wr; - - switch (timeout) { - case PR_INTERVAL_NO_WAIT: - PR_SetError(PR_IO_TIMEOUT_ERROR, 0); - break; - case PR_INTERVAL_NO_TIMEOUT: - /* - * This is a special case of the 'default' case below. - * Please see the comments there. - */ - tv.tv_sec = _PR_INTERRUPT_CHECK_INTERVAL_SECS; - tv.tv_usec = 0; - tvp = &tv; - FD_ZERO(&rd_wr); - do { - FD_SET(osfd, &rd_wr); - if (fd_type == READ_FD) - rv = _MD_SELECT(osfd + 1, &rd_wr, NULL, NULL, tvp); - else - rv = _MD_SELECT(osfd + 1, NULL, &rd_wr, NULL, tvp); - if (rv == -1 && (syserror = _MD_ERRNO()) != EINTR) { - if (syserror == EBADF) { - PR_SetError(PR_BAD_DESCRIPTOR_ERROR, EBADF); - } else { - PR_SetError(PR_UNKNOWN_ERROR, syserror); - } - break; - } - if (_PR_PENDING_INTERRUPT(me)) { - me->flags &= ~_PR_INTERRUPT; - PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); - rv = -1; - break; - } - } while (rv == 0 || (rv == -1 && syserror == EINTR)); - break; - default: - now = epoch = PR_IntervalNow(); - remaining = timeout; - tvp = &tv; - FD_ZERO(&rd_wr); - do { - /* - * We block in _MD_SELECT for at most - * _PR_INTERRUPT_CHECK_INTERVAL_SECS seconds, - * so that there is an upper limit on the delay - * before the interrupt bit is checked. - */ - tv.tv_sec = PR_IntervalToSeconds(remaining); - if (tv.tv_sec > _PR_INTERRUPT_CHECK_INTERVAL_SECS) { - tv.tv_sec = _PR_INTERRUPT_CHECK_INTERVAL_SECS; - tv.tv_usec = 0; - } else { - tv.tv_usec = PR_IntervalToMicroseconds( - remaining - - PR_SecondsToInterval(tv.tv_sec)); - } - FD_SET(osfd, &rd_wr); - if (fd_type == READ_FD) - rv = _MD_SELECT(osfd + 1, &rd_wr, NULL, NULL, tvp); - else - rv = _MD_SELECT(osfd + 1, NULL, &rd_wr, NULL, tvp); - /* - * we don't consider EINTR a real error - */ - if (rv == -1 && (syserror = _MD_ERRNO()) != EINTR) { - if (syserror == EBADF) { - PR_SetError(PR_BAD_DESCRIPTOR_ERROR, EBADF); - } else { - PR_SetError(PR_UNKNOWN_ERROR, syserror); - } - break; - } - if (_PR_PENDING_INTERRUPT(me)) { - me->flags &= ~_PR_INTERRUPT; - PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); - rv = -1; - break; - } - /* - * We loop again if _MD_SELECT timed out or got interrupted - * by a signal, and the timeout deadline has not passed yet. - */ - if (rv == 0 || (rv == -1 && syserror == EINTR)) { - /* - * If _MD_SELECT timed out, we know how much time - * we spent in blocking, so we can avoid a - * PR_IntervalNow() call. - */ - if (rv == 0) { - now += PR_SecondsToInterval(tv.tv_sec) - + PR_MicrosecondsToInterval(tv.tv_usec); - } else { - now = PR_IntervalNow(); - } - elapsed = (PRIntervalTime) (now - epoch); - if (elapsed >= timeout) { - PR_SetError(PR_IO_TIMEOUT_ERROR, 0); - rv = -1; - break; - } else { - remaining = timeout - elapsed; - } - } - } while (rv == 0 || (rv == -1 && syserror == EINTR)); - break; - } - return(rv); + PRInt32 rv = -1; + struct timeval tv; + PRThread *me = _PR_MD_CURRENT_THREAD(); + PRIntervalTime epoch, now, elapsed, remaining; + PRInt32 syserror; + fd_set rd_wr; + + switch (timeout) { + case PR_INTERVAL_NO_WAIT: + PR_SetError(PR_IO_TIMEOUT_ERROR, 0); + break; + case PR_INTERVAL_NO_TIMEOUT: + /* + * This is a special case of the 'default' case below. + * Please see the comments there. + */ + tv.tv_sec = _PR_INTERRUPT_CHECK_INTERVAL_SECS; + tv.tv_usec = 0; + FD_ZERO(&rd_wr); + do { + FD_SET(osfd, &rd_wr); + if (fd_type == READ_FD) + rv = _MD_SELECT(osfd + 1, &rd_wr, NULL, NULL, &tv); + else + rv = _MD_SELECT(osfd + 1, NULL, &rd_wr, NULL, &tv); + if (rv == -1 && (syserror = _MD_ERRNO()) != EINTR) { + _PR_MD_MAP_SELECT_ERROR(syserror); + break; + } + if (_PR_PENDING_INTERRUPT(me)) { + me->flags &= ~_PR_INTERRUPT; + PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); + rv = -1; + break; + } + } while (rv == 0 || (rv == -1 && syserror == EINTR)); + break; + default: + now = epoch = PR_IntervalNow(); + remaining = timeout; + FD_ZERO(&rd_wr); + do { + /* + * We block in _MD_SELECT for at most + * _PR_INTERRUPT_CHECK_INTERVAL_SECS seconds, + * so that there is an upper limit on the delay + * before the interrupt bit is checked. + */ + tv.tv_sec = PR_IntervalToSeconds(remaining); + if (tv.tv_sec > _PR_INTERRUPT_CHECK_INTERVAL_SECS) { + tv.tv_sec = _PR_INTERRUPT_CHECK_INTERVAL_SECS; + tv.tv_usec = 0; + } else { + tv.tv_usec = PR_IntervalToMicroseconds( + remaining - + PR_SecondsToInterval(tv.tv_sec)); + } + FD_SET(osfd, &rd_wr); + if (fd_type == READ_FD) + rv = _MD_SELECT(osfd + 1, &rd_wr, NULL, NULL, &tv); + else + rv = _MD_SELECT(osfd + 1, NULL, &rd_wr, NULL, &tv); + /* + * we don't consider EINTR a real error + */ + if (rv == -1 && (syserror = _MD_ERRNO()) != EINTR) { + _PR_MD_MAP_SELECT_ERROR(syserror); + break; + } + if (_PR_PENDING_INTERRUPT(me)) { + me->flags &= ~_PR_INTERRUPT; + PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); + rv = -1; + break; + } + /* + * We loop again if _MD_SELECT timed out or got interrupted + * by a signal, and the timeout deadline has not passed yet. + */ + if (rv == 0 || (rv == -1 && syserror == EINTR)) { + /* + * If _MD_SELECT timed out, we know how much time + * we spent in blocking, so we can avoid a + * PR_IntervalNow() call. + */ + if (rv == 0) { + now += PR_SecondsToInterval(tv.tv_sec) + + PR_MicrosecondsToInterval(tv.tv_usec); + } else { + now = PR_IntervalNow(); + } + elapsed = (PRIntervalTime) (now - epoch); + if (elapsed >= timeout) { + PR_SetError(PR_IO_TIMEOUT_ERROR, 0); + rv = -1; + break; + } else { + remaining = timeout - elapsed; + } + } + } while (rv == 0 || (rv == -1 && syserror == EINTR)); + break; + } + return(rv); } #else /* _PR_USE_POLL */ @@ -740,115 +609,160 @@ static PRInt32 socket_io_wait(PRInt32 osfd, PRInt32 fd_type, static PRInt32 socket_io_wait(PRInt32 osfd, PRInt32 fd_type, PRIntervalTime timeout) { - PRInt32 rv = -1; - int msecs; - PRThread *me = _PR_MD_CURRENT_THREAD(); - PRIntervalTime epoch, now, elapsed, remaining; - PRInt32 syserror; - struct pollfd pfd; - - switch (timeout) { - case PR_INTERVAL_NO_WAIT: - PR_SetError(PR_IO_TIMEOUT_ERROR, 0); - break; - case PR_INTERVAL_NO_TIMEOUT: - /* - * This is a special case of the 'default' case below. - * Please see the comments there. - */ - msecs = _PR_INTERRUPT_CHECK_INTERVAL_SECS * 1000; - pfd.fd = osfd; - if (fd_type == READ_FD) { - pfd.events = POLLIN; - } else { - pfd.events = POLLOUT; - } - do { - rv = _MD_POLL(&pfd, 1, msecs); - if (rv == -1 && (syserror = _MD_ERRNO()) != EINTR) { - _PR_MD_MAP_POLL_ERROR(syserror); - break; - } - if (_PR_PENDING_INTERRUPT(me)) { - me->flags &= ~_PR_INTERRUPT; - PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); - rv = -1; - break; - } - } while (rv == 0 || (rv == -1 && syserror == EINTR)); - break; - default: - now = epoch = PR_IntervalNow(); - remaining = timeout; - pfd.fd = osfd; - if (fd_type == READ_FD) { - pfd.events = POLLIN; - } else { - pfd.events = POLLOUT; - } - do { - /* - * We block in _MD_POLL for at most - * _PR_INTERRUPT_CHECK_INTERVAL_SECS seconds, - * so that there is an upper limit on the delay - * before the interrupt bit is checked. - */ - msecs = PR_IntervalToMilliseconds(remaining); - if (msecs > _PR_INTERRUPT_CHECK_INTERVAL_SECS * 1000) { - msecs = _PR_INTERRUPT_CHECK_INTERVAL_SECS * 1000; - } - rv = _MD_POLL(&pfd, 1, msecs); + PRInt32 rv = -1; + int msecs; + PRThread *me = _PR_MD_CURRENT_THREAD(); + PRIntervalTime epoch, now, elapsed, remaining; + PRInt32 syserror; + struct pollfd pfd; + + switch (timeout) { + case PR_INTERVAL_NO_WAIT: + PR_SetError(PR_IO_TIMEOUT_ERROR, 0); + break; + case PR_INTERVAL_NO_TIMEOUT: + /* + * This is a special case of the 'default' case below. + * Please see the comments there. + */ + msecs = _PR_INTERRUPT_CHECK_INTERVAL_SECS * 1000; + pfd.fd = osfd; + if (fd_type == READ_FD) { + pfd.events = POLLIN; + } else { + pfd.events = POLLOUT; + } + do { + rv = _MD_POLL(&pfd, 1, msecs); + if (rv == -1 && (syserror = _MD_ERRNO()) != EINTR) { + _PR_MD_MAP_POLL_ERROR(syserror); + break; + } /* - * we don't consider EINTR a real error + * If POLLERR is set, don't process it; retry the operation */ - if (rv == -1 && (syserror = _MD_ERRNO()) != EINTR) { - _PR_MD_MAP_POLL_ERROR(syserror); - break; - } - if (_PR_PENDING_INTERRUPT(me)) { - me->flags &= ~_PR_INTERRUPT; - PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); + if ((rv == 1) && (pfd.revents & (POLLHUP | POLLNVAL))) { rv = -1; - break; - } + _PR_MD_MAP_POLL_REVENTS_ERROR(pfd.revents); + break; + } + if (_PR_PENDING_INTERRUPT(me)) { + me->flags &= ~_PR_INTERRUPT; + PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); + rv = -1; + break; + } + } while (rv == 0 || (rv == -1 && syserror == EINTR)); + break; + default: + now = epoch = PR_IntervalNow(); + remaining = timeout; + pfd.fd = osfd; + if (fd_type == READ_FD) { + pfd.events = POLLIN; + } else { + pfd.events = POLLOUT; + } + do { + /* + * We block in _MD_POLL for at most + * _PR_INTERRUPT_CHECK_INTERVAL_SECS seconds, + * so that there is an upper limit on the delay + * before the interrupt bit is checked. + */ + msecs = PR_IntervalToMilliseconds(remaining); + if (msecs > _PR_INTERRUPT_CHECK_INTERVAL_SECS * 1000) { + msecs = _PR_INTERRUPT_CHECK_INTERVAL_SECS * 1000; + } + rv = _MD_POLL(&pfd, 1, msecs); + /* + * we don't consider EINTR a real error + */ + if (rv == -1 && (syserror = _MD_ERRNO()) != EINTR) { + _PR_MD_MAP_POLL_ERROR(syserror); + break; + } + if (_PR_PENDING_INTERRUPT(me)) { + me->flags &= ~_PR_INTERRUPT; + PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); + rv = -1; + break; + } /* - * We loop again if _MD_POLL timed out or got interrupted - * by a signal, and the timeout deadline has not passed yet. + * If POLLERR is set, don't process it; retry the operation */ - if (rv == 0 || (rv == -1 && syserror == EINTR)) { - /* - * If _MD_POLL timed out, we know how much time - * we spent in blocking, so we can avoid a - * PR_IntervalNow() call. - */ - if (rv == 0) { - now += PR_MillisecondsToInterval(msecs); - } else { - now = PR_IntervalNow(); - } - elapsed = (PRIntervalTime) (now - epoch); - if (elapsed >= timeout) { - PR_SetError(PR_IO_TIMEOUT_ERROR, 0); - rv = -1; - break; - } else { - remaining = timeout - elapsed; - } - } - } while (rv == 0 || (rv == -1 && syserror == EINTR)); - break; - } - return(rv); + if ((rv == 1) && (pfd.revents & (POLLHUP | POLLNVAL))) { + rv = -1; + _PR_MD_MAP_POLL_REVENTS_ERROR(pfd.revents); + break; + } + /* + * We loop again if _MD_POLL timed out or got interrupted + * by a signal, and the timeout deadline has not passed yet. + */ + if (rv == 0 || (rv == -1 && syserror == EINTR)) { + /* + * If _MD_POLL timed out, we know how much time + * we spent in blocking, so we can avoid a + * PR_IntervalNow() call. + */ + if (rv == 0) { + now += PR_MillisecondsToInterval(msecs); + } else { + now = PR_IntervalNow(); + } + elapsed = (PRIntervalTime) (now - epoch); + if (elapsed >= timeout) { + PR_SetError(PR_IO_TIMEOUT_ERROR, 0); + rv = -1; + break; + } else { + remaining = timeout - elapsed; + } + } + } while (rv == 0 || (rv == -1 && syserror == EINTR)); + break; + } + return(rv); } #endif /* _PR_USE_POLL */ +static PRInt32 local_io_wait( + PRInt32 osfd, + PRInt32 wait_flag, + PRIntervalTime timeout) +{ + _PRUnixPollDesc pd; + PRInt32 rv; + + PR_LOG(_pr_io_lm, PR_LOG_MIN, + ("waiting to %s on osfd=%d", + (wait_flag == _PR_UNIX_POLL_READ) ? "read" : "write", + osfd)); + + if (timeout == PR_INTERVAL_NO_WAIT) return 0; + + pd.osfd = osfd; + pd.in_flags = wait_flag; + pd.out_flags = 0; + + rv = _PR_WaitForMultipleFDs(&pd, 1, timeout); + + if (rv == 0) { + PR_SetError(PR_IO_TIMEOUT_ERROR, 0); + rv = -1; + } + return rv; +} + + PRInt32 _MD_recv(PRFileDesc *fd, void *buf, PRInt32 amount, - PRInt32 flags, PRIntervalTime timeout) + PRInt32 flags, PRIntervalTime timeout) { - PRInt32 osfd = fd->secret->md.osfd; - PRInt32 rv, err; - PRThread *me = _PR_MD_CURRENT_THREAD(); + PRInt32 osfd = fd->secret->md.osfd; + PRInt32 rv, err; + PRThread *me = _PR_MD_CURRENT_THREAD(); /* * Many OS's (Solaris, Unixware) have a broken recv which won't read @@ -856,94 +770,67 @@ PRInt32 _MD_recv(PRFileDesc *fd, void *buf, PRInt32 amount, * is a decent fix. - mikep */ #if defined(UNIXWARE) || defined(SOLARIS) || defined(NCR) - while ((rv = read(osfd,buf,amount)) == -1) { -/* - while ((rv = recv(osfd,buf,amount,flags)) == -1) { -*/ + while ((rv = read(osfd,buf,amount)) == -1) { #else - while ((rv = recv(osfd,buf,amount,flags)) == -1) { + while ((rv = recv(osfd,buf,amount,flags)) == -1) { #endif - err = _MD_ERRNO(); - if ((err == EAGAIN) || (err == EWOULDBLOCK)) { - if (fd->secret->nonblocking) { - break; - } - if (!_PR_IS_NATIVE_THREAD(me)) { - if (_PR_WaitForFD(osfd, PR_POLL_READ, timeout) == 0) { - rv = -1; - if (_PR_PENDING_INTERRUPT(me)) { - me->flags &= ~_PR_INTERRUPT; - PR_SetError( PR_PENDING_INTERRUPT_ERROR, 0); - } else - PR_SetError(PR_IO_TIMEOUT_ERROR, 0); - goto done; - } else if (_PR_PENDING_INTERRUPT(me)) { - me->flags &= ~_PR_INTERRUPT; - PR_SetError( PR_PENDING_INTERRUPT_ERROR, 0); - rv = -1; - goto done; - } - } else { - if ((rv = socket_io_wait(osfd, READ_FD, timeout)) < 0) + err = _MD_ERRNO(); + if ((err == EAGAIN) || (err == EWOULDBLOCK)) { + if (fd->secret->nonblocking) { + break; + } + if (!_PR_IS_NATIVE_THREAD(me)) { + if ((rv = local_io_wait(osfd,_PR_UNIX_POLL_READ,timeout)) < 0) goto done; - } - } else if ((err == EINTR) && (!_PR_PENDING_INTERRUPT(me))){ - continue; - } else { - break; - } - } - if (rv < 0) { - _PR_MD_MAP_RECV_ERROR(err); - } + } else { + if ((rv = socket_io_wait(osfd, READ_FD, timeout)) < 0) + goto done; + } + } else if ((err == EINTR) && (!_PR_PENDING_INTERRUPT(me))){ + continue; + } else { + break; + } + } + if (rv < 0) { + _PR_MD_MAP_RECV_ERROR(err); + } done: - return(rv); + return(rv); } PRInt32 _MD_recvfrom(PRFileDesc *fd, void *buf, PRInt32 amount, - PRIntn flags, PRNetAddr *addr, PRUint32 *addrlen, - PRIntervalTime timeout) -{ - PRInt32 osfd = fd->secret->md.osfd; - PRInt32 rv, err; - PRThread *me = _PR_MD_CURRENT_THREAD(); - - while ((*addrlen = PR_NETADDR_SIZE(addr)), - ((rv = recvfrom(osfd, buf, amount, flags, - (struct sockaddr *) addr, (_PRSockLen_t *)addrlen)) == -1)) { - err = _MD_ERRNO(); - if ((err == EAGAIN) || (err == EWOULDBLOCK)) { - if (fd->secret->nonblocking) { - break; - } - if (!_PR_IS_NATIVE_THREAD(me)) { - if (_PR_WaitForFD(osfd, PR_POLL_READ, timeout) == 0) { - rv = -1; - if (_PR_PENDING_INTERRUPT(me)) { - me->flags &= ~_PR_INTERRUPT; - PR_SetError( PR_PENDING_INTERRUPT_ERROR, 0); - } else - PR_SetError(PR_IO_TIMEOUT_ERROR, 0); - goto done; - } else if (_PR_PENDING_INTERRUPT(me)) { - me->flags &= ~_PR_INTERRUPT; - PR_SetError( PR_PENDING_INTERRUPT_ERROR, 0); - rv = -1; - goto done; - } - } else { - if ((rv = socket_io_wait(osfd, READ_FD, timeout)) < 0) - goto done; - } - } else if ((err == EINTR) && (!_PR_PENDING_INTERRUPT(me))){ - continue; - } else { - break; - } - } - if (rv < 0) { - _PR_MD_MAP_RECVFROM_ERROR(err); - } + PRIntn flags, PRNetAddr *addr, PRUint32 *addrlen, + PRIntervalTime timeout) +{ + PRInt32 osfd = fd->secret->md.osfd; + PRInt32 rv, err; + PRThread *me = _PR_MD_CURRENT_THREAD(); + + while ((*addrlen = PR_NETADDR_SIZE(addr)), + ((rv = recvfrom(osfd, buf, amount, flags, + (struct sockaddr *) addr, (_PRSockLen_t *)addrlen)) == -1)) { + err = _MD_ERRNO(); + if ((err == EAGAIN) || (err == EWOULDBLOCK)) { + if (fd->secret->nonblocking) { + break; + } + if (!_PR_IS_NATIVE_THREAD(me)) { + if ((rv = local_io_wait(osfd, _PR_UNIX_POLL_READ, timeout)) < 0) + goto done; + } else { + if ((rv = socket_io_wait(osfd, READ_FD, timeout)) < 0) + goto done; + } + } else if ((err == EINTR) && (!_PR_PENDING_INTERRUPT(me))){ + continue; + } else { + break; + } + } + if (rv < 0) { + _PR_MD_MAP_RECVFROM_ERROR(err); + } done: #ifdef _PR_HAVE_SOCKADDR_LEN if (rv != -1) { @@ -956,246 +843,203 @@ done: } } #endif /* _PR_HAVE_SOCKADDR_LEN */ - return(rv); + return(rv); } PRInt32 _MD_send(PRFileDesc *fd, const void *buf, PRInt32 amount, - PRInt32 flags, PRIntervalTime timeout) + PRInt32 flags, PRIntervalTime timeout) { - PRInt32 osfd = fd->secret->md.osfd; - PRInt32 rv, err; - PRThread *me = _PR_MD_CURRENT_THREAD(); + PRInt32 osfd = fd->secret->md.osfd; + PRInt32 rv, err; + PRThread *me = _PR_MD_CURRENT_THREAD(); - while ((rv = send(osfd,buf,amount,flags)) == -1) { - err = _MD_ERRNO(); - if ((err == EAGAIN) || (err == EWOULDBLOCK)) { - if (fd->secret->nonblocking) { - break; - } - if (!_PR_IS_NATIVE_THREAD(me)) { - if (_PR_WaitForFD(osfd, PR_POLL_WRITE, timeout) == 0) { - rv = -1; - if (_PR_PENDING_INTERRUPT(me)) { - me->flags &= ~_PR_INTERRUPT; - PR_SetError( PR_PENDING_INTERRUPT_ERROR, 0); - } else - PR_SetError(PR_IO_TIMEOUT_ERROR, 0); - goto done; - } else if (_PR_PENDING_INTERRUPT(me)) { - me->flags &= ~_PR_INTERRUPT; - PR_SetError( PR_PENDING_INTERRUPT_ERROR, 0); - rv = -1; - goto done; - } - } else { - if ((rv = socket_io_wait(osfd, WRITE_FD, timeout))< 0) - goto done; + /* + * On pre-2.6 Solaris, send() is much slower than write(). + * On 2.6 and beyond, with in-kernel sockets, send() and + * write() are fairly equivalent in performance. + */ +#if defined(SOLARIS) + PR_ASSERT(0 == flags); + while ((rv = write(osfd,buf,amount)) == -1) { +#else + while ((rv = send(osfd,buf,amount,flags)) == -1) { +#endif + err = _MD_ERRNO(); + if ((err == EAGAIN) || (err == EWOULDBLOCK)) { + if (fd->secret->nonblocking) { + break; + } + if (!_PR_IS_NATIVE_THREAD(me)) { + if ((rv = local_io_wait(osfd, _PR_UNIX_POLL_WRITE, timeout)) < 0) + goto done; + } else { + if ((rv = socket_io_wait(osfd, WRITE_FD, timeout))< 0) + goto done; + } + } else if ((err == EINTR) && (!_PR_PENDING_INTERRUPT(me))){ + continue; + } else { + break; + } + } + /* + * optimization; if bytes sent is less than "amount" call + * select before returning. This is because it is likely that + * the next send() call will return EWOULDBLOCK. + */ + if ((!fd->secret->nonblocking) && (rv > 0) && (rv < amount) + && (timeout != PR_INTERVAL_NO_WAIT)) { + if (_PR_IS_NATIVE_THREAD(me)) { + if (socket_io_wait(osfd, WRITE_FD, timeout)< 0) { + rv = -1; + goto done; } - } else if ((err == EINTR) && (!_PR_PENDING_INTERRUPT(me))){ - continue; - } else { - break; - } - } - /* - * optimization; if bytes sent is less than "amount" call - * select before returning. This is because it is likely that - * the next send() call will return EWOULDBLOCK. - */ - if ((!fd->secret->nonblocking) && (rv > 0) && (rv < amount) - && (timeout != PR_INTERVAL_NO_WAIT)) { - if (_PR_IS_NATIVE_THREAD(me)) { - if (socket_io_wait(osfd, WRITE_FD, timeout)< 0) - goto done; - } else { - if (_PR_WaitForFD(osfd, PR_POLL_WRITE, timeout) == 0) { - rv = -1; - if (_PR_PENDING_INTERRUPT(me)) { - me->flags &= ~_PR_INTERRUPT; - PR_SetError( PR_PENDING_INTERRUPT_ERROR, 0); - } else - PR_SetError(PR_IO_TIMEOUT_ERROR, 0); - goto done; + } else { + if (local_io_wait(osfd, _PR_UNIX_POLL_WRITE, timeout) < 0) { + rv = -1; + goto done; } - } - } - if (rv < 0) { - _PR_MD_MAP_SEND_ERROR(err); - } + } + } + if (rv < 0) { + _PR_MD_MAP_SEND_ERROR(err); + } done: - return(rv); + return(rv); } PRInt32 _MD_sendto( PRFileDesc *fd, const void *buf, PRInt32 amount, PRIntn flags, const PRNetAddr *addr, PRUint32 addrlen, PRIntervalTime timeout) { - PRInt32 osfd = fd->secret->md.osfd; - PRInt32 rv, err; - PRThread *me = _PR_MD_CURRENT_THREAD(); + PRInt32 osfd = fd->secret->md.osfd; + PRInt32 rv, err; + PRThread *me = _PR_MD_CURRENT_THREAD(); - while ((rv = sendto(osfd, buf, amount, flags, - (struct sockaddr *) addr, addrlen)) == -1) { - err = _MD_ERRNO(); - if ((err == EAGAIN) || (err == EWOULDBLOCK)) { - if (fd->secret->nonblocking) { - break; - } - if (!_PR_IS_NATIVE_THREAD(me)) { - if (_PR_WaitForFD(osfd, PR_POLL_WRITE, timeout) == 0) { - rv = -1; - if (_PR_PENDING_INTERRUPT(me)) { - me->flags &= ~_PR_INTERRUPT; - PR_SetError( PR_PENDING_INTERRUPT_ERROR, 0); - } else - PR_SetError(PR_IO_TIMEOUT_ERROR, 0); - goto done; - } else if (_PR_PENDING_INTERRUPT(me)) { - me->flags &= ~_PR_INTERRUPT; - PR_SetError( PR_PENDING_INTERRUPT_ERROR, 0); - rv = -1; - goto done; - } - } else { - if ((rv = socket_io_wait(osfd, WRITE_FD, timeout))< 0) + while ((rv = sendto(osfd, buf, amount, flags, + (struct sockaddr *) addr, addrlen)) == -1) { + err = _MD_ERRNO(); + if ((err == EAGAIN) || (err == EWOULDBLOCK)) { + if (fd->secret->nonblocking) { + break; + } + if (!_PR_IS_NATIVE_THREAD(me)) { + if ((rv = local_io_wait(osfd, _PR_UNIX_POLL_WRITE, timeout)) < 0) goto done; - } - } else if ((err == EINTR) && (!_PR_PENDING_INTERRUPT(me))){ - continue; - } else { - break; - } - } - if (rv < 0) { - _PR_MD_MAP_SENDTO_ERROR(err); - } + } else { + if ((rv = socket_io_wait(osfd, WRITE_FD, timeout))< 0) + goto done; + } + } else if ((err == EINTR) && (!_PR_PENDING_INTERRUPT(me))){ + continue; + } else { + break; + } + } + if (rv < 0) { + _PR_MD_MAP_SENDTO_ERROR(err); + } done: return(rv); } -PRInt32 _MD_writev(PRFileDesc *fd, PRIOVec *iov, - PRInt32 iov_size, PRIntervalTime timeout) -{ - PRInt32 rv, err; - PRThread *me = _PR_MD_CURRENT_THREAD(); - PRInt32 index, amount = 0; - PRInt32 osfd = fd->secret->md.osfd; - - /* - * Calculate the total number of bytes to be sent; needed for - * optimization later. - * We could avoid this if this number was passed in; but it is - * probably not a big deal because iov_size is usually small (less than - * 3) - */ - if (!fd->secret->nonblocking) { - for (index=0; index<iov_size; index++) { - amount += iov[index].iov_len; - } - } +PRInt32 _MD_writev( + PRFileDesc *fd, PRIOVec *iov, + PRInt32 iov_size, PRIntervalTime timeout) +{ + PRInt32 rv, err; + PRThread *me = _PR_MD_CURRENT_THREAD(); + PRInt32 index, amount = 0; + PRInt32 osfd = fd->secret->md.osfd; - while ((rv = writev(osfd, (const struct iovec*)iov, iov_size)) == -1) { - err = _MD_ERRNO(); - if ((err == EAGAIN) || (err == EWOULDBLOCK)) { - if (fd->secret->nonblocking) { - break; - } - if (!_PR_IS_NATIVE_THREAD(me)) { - if (_PR_WaitForFD(osfd, PR_POLL_WRITE, timeout) == 0) { - rv = -1; - if (_PR_PENDING_INTERRUPT(me)) { - me->flags &= ~_PR_INTERRUPT; - PR_SetError( PR_PENDING_INTERRUPT_ERROR, 0); - } else - PR_SetError(PR_IO_TIMEOUT_ERROR, 0); - goto done; - } else if (_PR_PENDING_INTERRUPT(me)) { - me->flags &= ~_PR_INTERRUPT; - PR_SetError( PR_PENDING_INTERRUPT_ERROR, 0); - rv = -1; - goto done; - } - } else { - if ((rv = socket_io_wait(osfd, WRITE_FD, timeout))<0) + /* + * Calculate the total number of bytes to be sent; needed for + * optimization later. + * We could avoid this if this number was passed in; but it is + * probably not a big deal because iov_size is usually small (less than + * 3) + */ + if (!fd->secret->nonblocking) { + for (index=0; index<iov_size; index++) { + amount += iov[index].iov_len; + } + } + + while ((rv = writev(osfd, (const struct iovec*)iov, iov_size)) == -1) { + err = _MD_ERRNO(); + if ((err == EAGAIN) || (err == EWOULDBLOCK)) { + if (fd->secret->nonblocking) { + break; + } + if (!_PR_IS_NATIVE_THREAD(me)) { + if ((rv = local_io_wait(osfd, _PR_UNIX_POLL_WRITE, timeout)) < 0) goto done; + } else { + if ((rv = socket_io_wait(osfd, WRITE_FD, timeout))<0) + goto done; + } + } else if ((err == EINTR) && (!_PR_PENDING_INTERRUPT(me))){ + continue; + } else { + break; + } + } + /* + * optimization; if bytes sent is less than "amount" call + * select before returning. This is because it is likely that + * the next writev() call will return EWOULDBLOCK. + */ + if ((!fd->secret->nonblocking) && (rv > 0) && (rv < amount) + && (timeout != PR_INTERVAL_NO_WAIT)) { + if (_PR_IS_NATIVE_THREAD(me)) { + if (socket_io_wait(osfd, WRITE_FD, timeout) < 0) { + rv = -1; + goto done; } - } else if ((err == EINTR) && (!_PR_PENDING_INTERRUPT(me))){ - continue; - } else { - break; - } - } - /* - * optimization; if bytes sent is less than "amount" call - * select before returning. This is because it is likely that - * the next writev() call will return EWOULDBLOCK. - */ - if ((!fd->secret->nonblocking) && (rv > 0) && (rv < amount) - && (timeout != PR_INTERVAL_NO_WAIT)) { - if (_PR_IS_NATIVE_THREAD(me)) { - if (socket_io_wait(osfd, WRITE_FD, timeout) < 0) - goto done; - } else { - if (_PR_WaitForFD(osfd, PR_POLL_WRITE, timeout) == 0) { - rv = -1; - if (_PR_PENDING_INTERRUPT(me)) { - me->flags &= ~_PR_INTERRUPT; - PR_SetError( PR_PENDING_INTERRUPT_ERROR, 0); - } else - PR_SetError(PR_IO_TIMEOUT_ERROR, 0); - goto done; + } else { + if (local_io_wait(osfd, _PR_UNIX_POLL_WRITE, timeout) < 0) { + rv = -1; + goto done; } - } - } - if (rv < 0) { - _PR_MD_MAP_WRITEV_ERROR(err); - } + } + } + if (rv < 0) { + _PR_MD_MAP_WRITEV_ERROR(err); + } done: return(rv); } PRInt32 _MD_accept(PRFileDesc *fd, PRNetAddr *addr, - PRUint32 *addrlen, PRIntervalTime timeout) + PRUint32 *addrlen, PRIntervalTime timeout) { PRInt32 osfd = fd->secret->md.osfd; PRInt32 rv, err; - PRThread *me = _PR_MD_CURRENT_THREAD(); - - while ((rv = accept(osfd, (struct sockaddr *) addr, - (_PRSockLen_t *)addrlen)) == -1) { - err = _MD_ERRNO(); - if ((err == EAGAIN) || (err == EWOULDBLOCK)) { - if (fd->secret->nonblocking) { - break; - } - if (!_PR_IS_NATIVE_THREAD(me)) { - if (_PR_WaitForFD(osfd, PR_POLL_READ, timeout) == 0) { - rv = -1; - if (_PR_PENDING_INTERRUPT(me)) { - me->flags &= ~_PR_INTERRUPT; - PR_SetError( PR_PENDING_INTERRUPT_ERROR, 0); - } else - PR_SetError(PR_IO_TIMEOUT_ERROR, 0); - goto done; - } else if (_PR_PENDING_INTERRUPT(me)) { - me->flags &= ~_PR_INTERRUPT; - PR_SetError( PR_PENDING_INTERRUPT_ERROR, 0); - rv = -1; - goto done; - } - } else { - if ((rv = socket_io_wait(osfd, READ_FD, timeout)) < 0) + PRThread *me = _PR_MD_CURRENT_THREAD(); + + while ((rv = accept(osfd, (struct sockaddr *) addr, + (_PRSockLen_t *)addrlen)) == -1) { + err = _MD_ERRNO(); + if ((err == EAGAIN) || (err == EWOULDBLOCK)) { + if (fd->secret->nonblocking) { + break; + } + if (!_PR_IS_NATIVE_THREAD(me)) { + if ((rv = local_io_wait(osfd, _PR_UNIX_POLL_READ, timeout)) < 0) goto done; - } - } else if ((err == EINTR) && (!_PR_PENDING_INTERRUPT(me))){ - continue; - } else { - break; - } - } - if (rv < 0) { - _PR_MD_MAP_ACCEPT_ERROR(err); - } + } else { + if ((rv = socket_io_wait(osfd, READ_FD, timeout)) < 0) + goto done; + } + } else if ((err == EINTR) && (!_PR_PENDING_INTERRUPT(me))){ + continue; + } else { + break; + } + } + if (rv < 0) { + _PR_MD_MAP_ACCEPT_ERROR(err); + } done: #ifdef _PR_HAVE_SOCKADDR_LEN if (rv != -1) { @@ -1208,7 +1052,7 @@ done: } } #endif /* _PR_HAVE_SOCKADDR_LEN */ - return(rv); + return(rv); } extern int _connect (int s, const struct sockaddr *name, int namelen); @@ -1216,11 +1060,11 @@ PRInt32 _MD_connect( PRFileDesc *fd, const PRNetAddr *addr, PRUint32 addrlen, PRIntervalTime timeout) { PRInt32 rv, err; - PRThread *me = _PR_MD_CURRENT_THREAD(); + PRThread *me = _PR_MD_CURRENT_THREAD(); PRInt32 osfd = fd->secret->md.osfd; #ifdef IRIX extern PRInt32 _MD_irix_connect( - PRInt32 osfd, const PRNetAddr *addr, PRInt32 addrlen, PRIntervalTime timeout); + PRInt32 osfd, const PRNetAddr *addr, PRInt32 addrlen, PRIntervalTime timeout); #endif /* @@ -1254,20 +1098,9 @@ retry: if (!fd->secret->nonblocking && (err == EINPROGRESS)) { if (!_PR_IS_NATIVE_THREAD(me)) { - /* - * _PR_WaitForFD() may return 0 (timeout or interrupt) or 1. - */ - rv = _PR_WaitForFD(osfd, PR_POLL_WRITE, timeout); - if (rv == 0) { - if (_PR_PENDING_INTERRUPT(me)) { - me->flags &= ~_PR_INTERRUPT; - PR_SetError( PR_PENDING_INTERRUPT_ERROR, 0); - } else { - PR_SetError(PR_IO_TIMEOUT_ERROR, 0); - } + if ((rv = local_io_wait(osfd, _PR_UNIX_POLL_WRITE, timeout)) < 0) return -1; - } } else { /* * socket_io_wait() may return -1 or 1. @@ -1303,53 +1136,53 @@ PRInt32 _MD_bind(PRFileDesc *fd, const PRNetAddr *addr, PRUint32 addrlen) { PRInt32 rv, err; - rv = bind(fd->secret->md.osfd, (struct sockaddr *) addr, (int )addrlen); - if (rv < 0) { - err = _MD_ERRNO(); - _PR_MD_MAP_BIND_ERROR(err); - } - return(rv); + rv = bind(fd->secret->md.osfd, (struct sockaddr *) addr, (int )addrlen); + if (rv < 0) { + err = _MD_ERRNO(); + _PR_MD_MAP_BIND_ERROR(err); + } + return(rv); } PRInt32 _MD_listen(PRFileDesc *fd, PRIntn backlog) { PRInt32 rv, err; - rv = listen(fd->secret->md.osfd, backlog); - if (rv < 0) { - err = _MD_ERRNO(); - _PR_MD_MAP_LISTEN_ERROR(err); - } - return(rv); + rv = listen(fd->secret->md.osfd, backlog); + if (rv < 0) { + err = _MD_ERRNO(); + _PR_MD_MAP_LISTEN_ERROR(err); + } + return(rv); } PRInt32 _MD_shutdown(PRFileDesc *fd, PRIntn how) { PRInt32 rv, err; - rv = shutdown(fd->secret->md.osfd, how); - if (rv < 0) { - err = _MD_ERRNO(); - _PR_MD_MAP_SHUTDOWN_ERROR(err); - } - return(rv); + rv = shutdown(fd->secret->md.osfd, how); + if (rv < 0) { + err = _MD_ERRNO(); + _PR_MD_MAP_SHUTDOWN_ERROR(err); + } + return(rv); } PRInt32 _MD_socketpair(int af, int type, int flags, - PRInt32 *osfd) + PRInt32 *osfd) { PRInt32 rv, err; - rv = socketpair(af, type, flags, osfd); - if (rv < 0) { - err = _MD_ERRNO(); - _PR_MD_MAP_SOCKETPAIR_ERROR(err); - } - return rv; + rv = socketpair(af, type, flags, osfd); + if (rv < 0) { + err = _MD_ERRNO(); + _PR_MD_MAP_SOCKETPAIR_ERROR(err); + } + return rv; } PRStatus _MD_getsockname(PRFileDesc *fd, PRNetAddr *addr, - PRUint32 *addrlen) + PRUint32 *addrlen) { PRInt32 rv, err; @@ -1374,7 +1207,7 @@ PRStatus _MD_getsockname(PRFileDesc *fd, PRNetAddr *addr, } PRStatus _MD_getpeername(PRFileDesc *fd, PRNetAddr *addr, - PRUint32 *addrlen) + PRUint32 *addrlen) { PRInt32 rv, err; @@ -1399,565 +1232,131 @@ PRStatus _MD_getpeername(PRFileDesc *fd, PRNetAddr *addr, } PRStatus _MD_getsockopt(PRFileDesc *fd, PRInt32 level, - PRInt32 optname, char* optval, PRInt32* optlen) + PRInt32 optname, char* optval, PRInt32* optlen) { PRInt32 rv, err; - rv = getsockopt(fd->secret->md.osfd, level, optname, optval, (_PRSockLen_t *)optlen); - if (rv < 0) { - err = _MD_ERRNO(); - _PR_MD_MAP_GETSOCKOPT_ERROR(err); - } - return rv==0?PR_SUCCESS:PR_FAILURE; + rv = getsockopt(fd->secret->md.osfd, level, optname, optval, (_PRSockLen_t *)optlen); + if (rv < 0) { + err = _MD_ERRNO(); + _PR_MD_MAP_GETSOCKOPT_ERROR(err); + } + return rv==0?PR_SUCCESS:PR_FAILURE; } PRStatus _MD_setsockopt(PRFileDesc *fd, PRInt32 level, - PRInt32 optname, const char* optval, PRInt32 optlen) + PRInt32 optname, const char* optval, PRInt32 optlen) { PRInt32 rv, err; - rv = setsockopt(fd->secret->md.osfd, level, optname, optval, optlen); - if (rv < 0) { - err = _MD_ERRNO(); - _PR_MD_MAP_SETSOCKOPT_ERROR(err); - } - return rv==0?PR_SUCCESS:PR_FAILURE; -} - -PR_IMPLEMENT(PRInt32) _MD_pr_poll(PRPollDesc *pds, PRIntn npds, - PRIntervalTime timeout) -{ - PRPollDesc *pd, *epd; - PRPollQueue pq; - PRInt32 n, err, pdcnt; - PRIntn is; - _PRUnixPollDesc *unixpds, *unixpd; - _PRCPU *io_cpu; - PRThread *me = _PR_MD_CURRENT_THREAD(); - - if (0 == npds) { - PR_Sleep(timeout); - return 0; + rv = setsockopt(fd->secret->md.osfd, level, optname, optval, optlen); + if (rv < 0) { + err = _MD_ERRNO(); + _PR_MD_MAP_SETSOCKOPT_ERROR(err); } + return rv==0?PR_SUCCESS:PR_FAILURE; +} - if (_PR_IS_NATIVE_THREAD(me)) { -#ifndef _PR_USE_POLL - /* - * On platforms that don't have poll(), we call select(). - */ - fd_set rd, wt, ex; - struct timeval tv, *tvp = NULL; - int maxfd = -1; - /* - * For restarting _MD_SELECT() if it is interrupted by a signal. - * We use these variables to figure out how much time has elapsed - * and how much of the timeout still remains. - */ - PRIntervalTime start, elapsed, remaining; - - FD_ZERO(&rd); - FD_ZERO(&wt); - FD_ZERO(&ex); - - for (pd = pds, epd = pd + npds; pd < epd; pd++) { - PRInt32 osfd; - PRInt16 in_flags = pd->in_flags; - PRFileDesc *bottom = pd->fd; +/************************************************************************/ +#if !defined(_PR_USE_POLL) - if ((NULL == bottom) || (in_flags == 0)) { - continue; +/* +** Scan through io queue and find any bad fd's that triggered the error +** from _MD_SELECT +*/ +static void FindBadFDs(void) +{ + PRCList *q; + PRThread *me = _MD_CURRENT_THREAD(); + + PR_ASSERT(!_PR_IS_NATIVE_THREAD(me)); + q = (_PR_IOQ(me->cpu)).next; + _PR_IOQ_MAX_OSFD(me->cpu) = -1; + _PR_IOQ_TIMEOUT(me->cpu) = PR_INTERVAL_NO_TIMEOUT; + while (q != &_PR_IOQ(me->cpu)) { + PRPollQueue *pq = _PR_POLLQUEUE_PTR(q); + PRBool notify = PR_FALSE; + _PRUnixPollDesc *pds = pq->pds; + _PRUnixPollDesc *epds = pds + pq->npds; + PRInt32 pq_max_osfd = -1; + + q = q->next; + for (; pds < epds; pds++) { + PRInt32 osfd = pds->osfd; + pds->out_flags = 0; + PR_ASSERT(osfd >= 0 || pds->in_flags == 0); + if (pds->in_flags == 0) { + continue; /* skip this fd */ } - while (bottom->lower != NULL) { - bottom = bottom->lower; + if (fcntl(osfd, F_GETFL, 0) == -1) { + /* Found a bad descriptor, remove it from the fd_sets. */ + PR_LOG(_pr_io_lm, PR_LOG_MAX, + ("file descriptor %d is bad", osfd)); + pds->out_flags = _PR_UNIX_POLL_NVAL; + notify = PR_TRUE; + } + if (osfd > pq_max_osfd) { + pq_max_osfd = osfd; } - osfd = bottom->secret->md.osfd; - - if (osfd > maxfd) { - maxfd = osfd; - } - if (in_flags & PR_POLL_READ) { - FD_SET(osfd, &rd); - } - if (in_flags & PR_POLL_WRITE) { - FD_SET(osfd, &wt); - } - if (in_flags & PR_POLL_EXCEPT) { - FD_SET(osfd, &ex); - } } - if (timeout != PR_INTERVAL_NO_TIMEOUT) { - tv.tv_sec = PR_IntervalToSeconds(timeout); - tv.tv_usec = PR_IntervalToMicroseconds(timeout) % PR_USEC_PER_SEC; - tvp = &tv; - start = PR_IntervalNow(); - } - -retry: - n = _MD_SELECT(maxfd + 1, &rd, &wt, &ex, tvp); - if (n == -1 && errno == EINTR) { - if (timeout == PR_INTERVAL_NO_TIMEOUT) { - goto retry; - } else { - elapsed = (PRIntervalTime) (PR_IntervalNow() - start); - if (elapsed > timeout) { - n = 0; /* timed out */ - } else { - remaining = timeout - elapsed; - tv.tv_sec = PR_IntervalToSeconds(remaining); - tv.tv_usec = PR_IntervalToMicroseconds( - remaining - PR_SecondsToInterval(tv.tv_sec)); - goto retry; - } - } - } - - if (n > 0) { - n = 0; - for (pd = pds, epd = pd + npds; pd < epd; pd++) { - PRInt32 osfd; - PRInt16 in_flags = pd->in_flags; - PRInt16 out_flags = 0; - PRFileDesc *bottom = pd->fd; - - if ((NULL == bottom) || (in_flags == 0)) { - pd->out_flags = 0; - continue; - } - while (bottom->lower != NULL) { - bottom = bottom->lower; - } - osfd = bottom->secret->md.osfd; - if ((in_flags & PR_POLL_READ) && FD_ISSET(osfd, &rd)) { - out_flags |= PR_POLL_READ; - } - if ((in_flags & PR_POLL_WRITE) && FD_ISSET(osfd, &wt)) { - out_flags |= PR_POLL_WRITE; - } - if ((in_flags & PR_POLL_EXCEPT) && FD_ISSET(osfd, &ex)) { - out_flags |= PR_POLL_EXCEPT; - } - pd->out_flags = out_flags; - if (out_flags) { - n++; - } - } - PR_ASSERT(n > 0); - } else if (n < 0) { - err = _MD_ERRNO(); - if (err == EBADF) { - /* Find the bad fds */ - n = 0; - for (pd = pds, epd = pd + npds; pd < epd; pd++) { - PRFileDesc *bottom = pd->fd; - pd->out_flags = 0; - if ((NULL == bottom) || (pd->in_flags == 0)) { - continue; - } - while (bottom->lower != NULL) { - bottom = bottom->lower; - } - if (fcntl(bottom->secret->md.osfd, F_GETFL, 0) == -1) { - pd->out_flags = PR_POLL_NVAL; - n++; - } - } - PR_ASSERT(n > 0); - } else { - PR_ASSERT(err != EINTR); /* should have been handled above */ - _PR_MD_MAP_SELECT_ERROR(err); - } - } + if (notify) { + PRIntn pri; + PR_REMOVE_LINK(&pq->links); + pq->on_ioq = PR_FALSE; - return n; -#else /* _PR_USE_POLL */ - /* - * For restarting _MD_POLL() if it is interrupted by a signal. - * We use these variables to figure out how much time has elapsed - * and how much of the timeout still remains. + /* + * Decrement the count of descriptors for each desciptor/event + * because this I/O request is being removed from the + * ioq */ - PRIntervalTime start, elapsed, remaining; - int index, msecs; - struct pollfd *syspoll; - - syspoll = (struct pollfd *) PR_MALLOC(npds * sizeof(struct pollfd)); - if (NULL == syspoll) { - PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); - return -1; - } - for (index = 0; index < npds; index++) { - PRFileDesc *bottom = pds[index].fd; - - if (NULL == bottom) { - /* make poll() ignore this entry */ - syspoll[index].fd = -1; - continue; - } - - while (bottom->lower != NULL) { - bottom = bottom->lower; - } - syspoll[index].fd = bottom->secret->md.osfd; - - syspoll[index].events = 0; - if (pds[index].in_flags & PR_POLL_READ) { - syspoll[index].events |= POLLIN; - } - if (pds[index].in_flags & PR_POLL_WRITE) { - syspoll[index].events |= POLLOUT; - } - if (pds[index].in_flags & PR_POLL_EXCEPT) { - syspoll[index].events |= POLLPRI; - } - pds[index].out_flags = 0; /* init the result */ - } - if (timeout == PR_INTERVAL_NO_TIMEOUT) { - msecs = -1; - } else { - msecs = PR_IntervalToMilliseconds(timeout); - start = PR_IntervalNow(); - } - -retry: - n = _MD_POLL(syspoll, npds, msecs); - if (n == -1) { - err = _MD_ERRNO(); - if (err == EINTR) { - if (timeout == PR_INTERVAL_NO_TIMEOUT) { - goto retry; - } else if (timeout == PR_INTERVAL_NO_WAIT) { - n = 0; /* don't retry, just time out */ - } else { - elapsed = (PRIntervalTime) (PR_IntervalNow() - start); - if (elapsed > timeout) { - n = 0; /* timed out */ - } else { - remaining = timeout - elapsed; - msecs = PR_IntervalToMilliseconds(remaining); - goto retry; - } + pds = pq->pds; + for (; pds < epds; pds++) { + PRInt32 osfd = pds->osfd; + PRInt16 in_flags = pds->in_flags; + PR_ASSERT(osfd >= 0 || in_flags == 0); + if (in_flags & _PR_UNIX_POLL_READ) { + if (--(_PR_FD_READ_CNT(me->cpu))[osfd] == 0) + FD_CLR(osfd, &_PR_FD_READ_SET(me->cpu)); } - } else { - _PR_MD_MAP_POLL_ERROR(err); - } - } else if (n > 0) { - for (index = 0; index < npds; index++) { - if (NULL == pds[index].fd) { - continue; + if (in_flags & _PR_UNIX_POLL_WRITE) { + if (--(_PR_FD_WRITE_CNT(me->cpu))[osfd] == 0) + FD_CLR(osfd, &_PR_FD_WRITE_SET(me->cpu)); } - PR_ASSERT(0 == pds[index].out_flags); - if (0 != syspoll[index].revents) { - if (syspoll[index].revents & POLLIN) { - pds[index].out_flags |= PR_POLL_READ; - } - if (syspoll[index].revents & POLLOUT) { - pds[index].out_flags |= PR_POLL_WRITE; - } - if (syspoll[index].revents & POLLPRI) { - pds[index].out_flags |= PR_POLL_EXCEPT; - } - if (syspoll[index].revents & POLLERR) { - pds[index].out_flags |= PR_POLL_ERR; - } - if (syspoll[index].revents & POLLNVAL) { - pds[index].out_flags |= PR_POLL_NVAL; - } + if (in_flags & _PR_UNIX_POLL_EXCEPT) { + if (--(_PR_FD_EXCEPTION_CNT(me->cpu))[osfd] == 0) + FD_CLR(osfd, &_PR_FD_EXCEPTION_SET(me->cpu)); } } - } - - PR_DELETE(syspoll); - return n; -#endif /* _PR_USE_POLL */ - } - /* - * XXX - * PRPollDesc has a PRFileDesc field, fd, while the IOQ - * is a list of PRPollQueue structures, each of which contains - * a _PRUnixPollDesc. A _PRUnixPollDesc struct contains - * the OS file descriptor, osfd, and not a PRFileDesc. - * So, we have allocate memory for _PRUnixPollDesc structures, - * copy the flags information from the pds list and have pq - * point to this list of _PRUnixPollDesc structures. - * - * It would be better if the memory allocation can be avoided. - */ - - unixpds = (_PRUnixPollDesc*) PR_MALLOC(npds * sizeof(_PRUnixPollDesc)); - if (!unixpds) { - PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); - return -1; - } - unixpd = unixpds; + _PR_THREAD_LOCK(pq->thr); + if (pq->thr->flags & (_PR_ON_PAUSEQ|_PR_ON_SLEEPQ)) { + _PRCPU *cpu = pq->thr->cpu; + _PR_SLEEPQ_LOCK(pq->thr->cpu); + _PR_DEL_SLEEPQ(pq->thr, PR_TRUE); + _PR_SLEEPQ_UNLOCK(pq->thr->cpu); - _PR_INTSOFF(is); - _PR_MD_IOQ_LOCK(); - _PR_THREAD_LOCK(me); - - if (_PR_PENDING_INTERRUPT(me)) { - me->flags &= ~_PR_INTERRUPT; - PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); - _PR_THREAD_UNLOCK(me); - _PR_MD_IOQ_UNLOCK(); - _PR_FAST_INTSON(is); - PR_DELETE(unixpds); - return -1; - } - - pdcnt = 0; - for (pd = pds, epd = pd + npds; pd < epd; pd++) { - PRInt32 osfd; - PRInt16 in_flags = pd->in_flags; - PRFileDesc *bottom = pd->fd; + pri = pq->thr->priority; + pq->thr->state = _PR_RUNNABLE; - if ((NULL == bottom) || (in_flags == 0)) { - continue; - } - while (bottom->lower != NULL) { - bottom = bottom->lower; - } - osfd = bottom->secret->md.osfd; - - PR_ASSERT(osfd >= 0 || in_flags == 0); - - unixpd->osfd = osfd; - unixpd->in_flags = pd->in_flags; - unixpd++; - pdcnt++; - -#ifndef _PR_USE_POLL - if (in_flags & PR_POLL_READ) { - FD_SET(osfd, &_PR_FD_READ_SET(me->cpu)); - _PR_FD_READ_CNT(me->cpu)[osfd]++; - } - if (in_flags & PR_POLL_WRITE) { - FD_SET(osfd, &_PR_FD_WRITE_SET(me->cpu)); - (_PR_FD_WRITE_CNT(me->cpu))[osfd]++; - } - if (in_flags & PR_POLL_EXCEPT) { - FD_SET(osfd, &_PR_FD_EXCEPTION_SET(me->cpu)); - (_PR_FD_EXCEPTION_CNT(me->cpu))[osfd]++; - } -#endif /* _PR_USE_POLL */ - if (osfd > _PR_IOQ_MAX_OSFD(me->cpu)) - _PR_IOQ_MAX_OSFD(me->cpu) = osfd; - } - if (timeout < _PR_IOQ_TIMEOUT(me->cpu)) - _PR_IOQ_TIMEOUT(me->cpu) = timeout; - - _PR_IOQ_OSFD_CNT(me->cpu) += pdcnt; - - pq.pds = unixpds; - pq.npds = pdcnt; - - pq.thr = me; - io_cpu = me->cpu; - pq.on_ioq = PR_TRUE; - pq.timeout = timeout; - _PR_ADD_TO_IOQ(pq, me->cpu); - _PR_SLEEPQ_LOCK(me->cpu); - _PR_ADD_SLEEPQ(me, timeout); - me->state = _PR_IO_WAIT; - me->io_pending = PR_TRUE; - me->io_suspended = PR_FALSE; - _PR_SLEEPQ_UNLOCK(me->cpu); - _PR_THREAD_UNLOCK(me); - _PR_MD_IOQ_UNLOCK(); - - _PR_MD_WAIT(me, timeout); - - me->io_pending = PR_FALSE; - me->io_suspended = PR_FALSE; - - /* - * This thread should run on the same cpu on which it was blocked; when - * the IO request times out the fd sets and fd counts for the - * cpu are updated below. - */ - PR_ASSERT(me->cpu == io_cpu); - /* - * Copy the out_flags from the _PRUnixPollDesc structures to the - * user's PRPollDesc structures and free the allocated memory - */ - unixpd = unixpds; - for (pd = pds, epd = pd + npds; pd < epd; pd++) { - if ((NULL == pd->fd) || (pd->in_flags == 0)) { - pd->out_flags = 0; - continue; + _PR_RUNQ_LOCK(cpu); + _PR_ADD_RUNQ(pq->thr, cpu, pri); + _PR_RUNQ_UNLOCK(cpu); + } + _PR_THREAD_UNLOCK(pq->thr); + } else { + if (pq->timeout < _PR_IOQ_TIMEOUT(me->cpu)) + _PR_IOQ_TIMEOUT(me->cpu) = pq->timeout; + if (_PR_IOQ_MAX_OSFD(me->cpu) < pq_max_osfd) + _PR_IOQ_MAX_OSFD(me->cpu) = pq_max_osfd; } - pd->out_flags = unixpd->out_flags; - unixpd++; - } - PR_DELETE(unixpds); - - /* - ** If we timed out the pollq might still be on the ioq. Remove it - ** before continuing. - */ - if (pq.on_ioq) { - _PR_MD_IOQ_LOCK(); - /* - * Need to check pq.on_ioq again - */ - if (pq.on_ioq == PR_TRUE) { - PR_REMOVE_LINK(&pq.links); - for (pd = pds, epd = pd + npds; pd < epd; pd++) { - PRInt32 osfd; - PRInt16 in_flags = pd->in_flags; - PRFileDesc *bottom = pd->fd; - - if ((NULL == bottom) || (in_flags == 0)) { - continue; - } - while (bottom->lower != NULL) { - bottom = bottom->lower; - } - osfd = bottom->secret->md.osfd; - PR_ASSERT(osfd >= 0 || in_flags == 0); -#ifndef _PR_USE_POLL - if (in_flags & PR_POLL_READ) { - if (--(_PR_FD_READ_CNT(me->cpu))[osfd] == 0) - FD_CLR(osfd, &_PR_FD_READ_SET(me->cpu)); - } - if (in_flags & PR_POLL_WRITE) { - if (--(_PR_FD_WRITE_CNT(me->cpu))[osfd] == 0) - FD_CLR(osfd, &_PR_FD_WRITE_SET(me->cpu)); - } - if (in_flags & PR_POLL_EXCEPT) { - if (--(_PR_FD_EXCEPTION_CNT(me->cpu))[osfd] == 0) - FD_CLR(osfd, &_PR_FD_EXCEPTION_SET(me->cpu)); - } -#endif - } - _PR_IOQ_OSFD_CNT(me->cpu) -= pdcnt; - PR_ASSERT(_PR_IOQ_OSFD_CNT(me->cpu) >= 0); - } - _PR_MD_IOQ_UNLOCK(); } - _PR_INTSON(is); - if (_PR_PENDING_INTERRUPT(me)) { - me->flags &= ~_PR_INTERRUPT; - PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); - return -1; - } else { - n = 0; - if (pq.on_ioq == PR_FALSE) { - /* Count the number of ready descriptors */ - while (--npds >= 0) { - if (pds->out_flags) { - n++; - } - pds++; - } - } - return n; + if (_PR_IS_NATIVE_THREAD_SUPPORTED()) { + if (_PR_IOQ_MAX_OSFD(me->cpu) < _pr_md_pipefd[0]) + _PR_IOQ_MAX_OSFD(me->cpu) = _pr_md_pipefd[0]; } } - - - - -/************************************************************************/ - -/* -** Scan through io queue and find any bad fd's that triggered the error -** from _MD_SELECT -*/ -static void FindBadFDs(void) -{ - PRCList *q; - PRThread *me = _MD_CURRENT_THREAD(); - - PR_ASSERT(!_PR_IS_NATIVE_THREAD(me)); - q = (_PR_IOQ(me->cpu)).next; - _PR_IOQ_MAX_OSFD(me->cpu) = -1; - _PR_IOQ_TIMEOUT(me->cpu) = PR_INTERVAL_NO_TIMEOUT; - while (q != &_PR_IOQ(me->cpu)) { - PRPollQueue *pq = _PR_POLLQUEUE_PTR(q); - PRBool notify = PR_FALSE; - _PRUnixPollDesc *pds = pq->pds; - _PRUnixPollDesc *epds = pds + pq->npds; - PRInt32 pq_max_osfd = -1; - - q = q->next; - for (; pds < epds; pds++) { - PRInt32 osfd = pds->osfd; - pds->out_flags = 0; - PR_ASSERT(osfd >= 0 || pds->in_flags == 0); - if (pds->in_flags == 0) { - continue; /* skip this fd */ - } - if (fcntl(osfd, F_GETFL, 0) == -1) { - /* Found a bad descriptor, remove it from the fd_sets. */ - PR_LOG(_pr_io_lm, PR_LOG_MAX, - ("file descriptor %d is bad", osfd)); - pds->out_flags = PR_POLL_NVAL; - notify = PR_TRUE; - } - if (osfd > pq_max_osfd) { - pq_max_osfd = osfd; - } - } - - if (notify) { - PRIntn pri; - PR_REMOVE_LINK(&pq->links); - pq->on_ioq = PR_FALSE; - - /* - * Decrement the count of descriptors for each desciptor/event - * because this I/O request is being removed from the - * ioq - */ - pds = pq->pds; - for (; pds < epds; pds++) { - PRInt32 osfd = pds->osfd; - PRInt16 in_flags = pds->in_flags; - PR_ASSERT(osfd >= 0 || in_flags == 0); -#ifndef _PR_USE_POLL - if (in_flags & PR_POLL_READ) { - if (--(_PR_FD_READ_CNT(me->cpu))[osfd] == 0) - FD_CLR(osfd, &_PR_FD_READ_SET(me->cpu)); - } - if (in_flags & PR_POLL_WRITE) { - if (--(_PR_FD_WRITE_CNT(me->cpu))[osfd] == 0) - FD_CLR(osfd, &_PR_FD_WRITE_SET(me->cpu)); - } - if (in_flags & PR_POLL_EXCEPT) { - if (--(_PR_FD_EXCEPTION_CNT(me->cpu))[osfd] == 0) - FD_CLR(osfd, &_PR_FD_EXCEPTION_SET(me->cpu)); - } -#endif /* !_PR_USE_POLL */ - } - - _PR_THREAD_LOCK(pq->thr); - if (pq->thr->flags & (_PR_ON_PAUSEQ|_PR_ON_SLEEPQ)) { - _PRCPU *cpu = pq->thr->cpu; - _PR_SLEEPQ_LOCK(pq->thr->cpu); - _PR_DEL_SLEEPQ(pq->thr, PR_TRUE); - _PR_SLEEPQ_UNLOCK(pq->thr->cpu); - - pri = pq->thr->priority; - pq->thr->state = _PR_RUNNABLE; - - _PR_RUNQ_LOCK(cpu); - _PR_ADD_RUNQ(pq->thr, cpu, pri); - _PR_RUNQ_UNLOCK(cpu); - } - _PR_THREAD_UNLOCK(pq->thr); - } else { - if (pq->timeout < _PR_IOQ_TIMEOUT(me->cpu)) - _PR_IOQ_TIMEOUT(me->cpu) = pq->timeout; - if (_PR_IOQ_MAX_OSFD(me->cpu) < pq_max_osfd) - _PR_IOQ_MAX_OSFD(me->cpu) = pq_max_osfd; - } - } - if (_PR_IS_NATIVE_THREAD_SUPPORTED()) { - if (_PR_IOQ_MAX_OSFD(me->cpu) < _pr_md_pipefd[0]) - _PR_IOQ_MAX_OSFD(me->cpu) = _pr_md_pipefd[0]; - } -} +#endif /* !defined(_PR_USE_POLL) */ /************************************************************************/ @@ -1974,463 +1373,534 @@ static void FindBadFDs(void) */ void _MD_PauseCPU(PRIntervalTime ticks) { - PRThread *me = _MD_CURRENT_THREAD(); + PRThread *me = _MD_CURRENT_THREAD(); #ifdef _PR_USE_POLL - int timeout; - struct pollfd *pollfds; /* an array of pollfd structures */ - struct pollfd *pollfdPtr; /* a pointer that steps through the array */ - unsigned long npollfds; /* number of pollfd structures in array */ - unsigned long pollfds_size; - int nfd; /* to hold the return value of poll() */ + int timeout; + struct pollfd *pollfds; /* an array of pollfd structures */ + struct pollfd *pollfdPtr; /* a pointer that steps through the array */ + unsigned long npollfds; /* number of pollfd structures in array */ + unsigned long pollfds_size; + int nfd; /* to hold the return value of poll() */ #else - struct timeval timeout, *tvp; - fd_set r, w, e; - fd_set *rp, *wp, *ep; - PRInt32 max_osfd, nfd; + struct timeval timeout, *tvp; + fd_set r, w, e; + fd_set *rp, *wp, *ep; + PRInt32 max_osfd, nfd; #endif /* _PR_USE_POLL */ - PRInt32 rv; - PRCList *q; - PRUint32 min_timeout; - sigset_t oldset; + PRInt32 rv; + PRCList *q; + PRUint32 min_timeout; + sigset_t oldset; #ifdef IRIX extern sigset_t ints_off; #endif - PR_ASSERT(_PR_MD_GET_INTSOFF() != 0); + PR_ASSERT(_PR_MD_GET_INTSOFF() != 0); - _PR_MD_IOQ_LOCK(); + _PR_MD_IOQ_LOCK(); #ifdef _PR_USE_POLL - /* Build up the pollfd structure array to wait on */ + /* Build up the pollfd structure array to wait on */ - /* Find out how many pollfd structures are needed */ - npollfds = _PR_IOQ_OSFD_CNT(me->cpu); - PR_ASSERT(npollfds >= 0); + /* Find out how many pollfd structures are needed */ + npollfds = _PR_IOQ_OSFD_CNT(me->cpu); + PR_ASSERT(npollfds >= 0); - /* + /* * We use a pipe to wake up a native thread. An fd is needed * for the pipe and we poll it for reading. */ - if (_PR_IS_NATIVE_THREAD_SUPPORTED()) - npollfds++; - - /* - * if the cpu's pollfd array is not big enough, release it and allocate a new one - */ - if (npollfds > _PR_IOQ_POLLFDS_SIZE(me->cpu)) { - if (_PR_IOQ_POLLFDS(me->cpu) != NULL) - PR_DELETE(pollfds); - pollfds_size = PR_MAX(_PR_IOQ_MIN_POLLFDS_SIZE(me->cpu), npollfds); - pollfds = (struct pollfd *) PR_MALLOC(pollfds_size * sizeof(struct pollfd)); - _PR_IOQ_POLLFDS(me->cpu) = pollfds; - _PR_IOQ_POLLFDS_SIZE(me->cpu) = pollfds_size; - pollfdPtr = pollfds; - } else { - pollfds = _PR_IOQ_POLLFDS(me->cpu); - pollfdPtr = pollfds; + if (_PR_IS_NATIVE_THREAD_SUPPORTED()) { + npollfds++; +#ifdef IRIX + /* + * On Irix, a second pipe is used to cause the primordial cpu to + * wakeup and exit, when the process is exiting because of a call + * to exit/PR_ProcessExit. + */ + if (me->cpu->id == 0) { + npollfds++; + } +#endif } - /* + /* + * if the cpu's pollfd array is not big enough, release it and allocate a new one + */ + if (npollfds > _PR_IOQ_POLLFDS_SIZE(me->cpu)) { + if (_PR_IOQ_POLLFDS(me->cpu) != NULL) + PR_DELETE(pollfds); + pollfds_size = PR_MAX(_PR_IOQ_MIN_POLLFDS_SIZE(me->cpu), npollfds); + pollfds = (struct pollfd *) PR_MALLOC(pollfds_size * sizeof(struct pollfd)); + _PR_IOQ_POLLFDS(me->cpu) = pollfds; + _PR_IOQ_POLLFDS_SIZE(me->cpu) = pollfds_size; + pollfdPtr = pollfds; + } else { + pollfds = _PR_IOQ_POLLFDS(me->cpu); + pollfdPtr = pollfds; + } + + /* * If we need to poll the pipe for waking up a native thread, * the pipe's fd is the first element in the pollfds array. */ - if (_PR_IS_NATIVE_THREAD_SUPPORTED()) { - pollfdPtr->fd = _pr_md_pipefd[0]; - pollfdPtr->events = PR_POLL_READ; - pollfdPtr++; - } + if (_PR_IS_NATIVE_THREAD_SUPPORTED()) { + pollfdPtr->fd = _pr_md_pipefd[0]; + pollfdPtr->events = POLLIN; + pollfdPtr++; +#ifdef IRIX + /* + * On Irix, the second element is the exit pipe + */ + if (me->cpu->id == 0) { + pollfdPtr->fd = _pr_irix_primoridal_cpu_fd[0]; + pollfdPtr->events = POLLIN; + pollfdPtr++; + } +#endif + } - min_timeout = PR_INTERVAL_NO_TIMEOUT; - for (q = _PR_IOQ(me->cpu).next; q != &_PR_IOQ(me->cpu); q = q->next) { - PRPollQueue *pq = _PR_POLLQUEUE_PTR(q); - _PRUnixPollDesc *pds = pq->pds; - _PRUnixPollDesc *epds = pds + pq->npds; + min_timeout = PR_INTERVAL_NO_TIMEOUT; + for (q = _PR_IOQ(me->cpu).next; q != &_PR_IOQ(me->cpu); q = q->next) { + PRPollQueue *pq = _PR_POLLQUEUE_PTR(q); + _PRUnixPollDesc *pds = pq->pds; + _PRUnixPollDesc *epds = pds + pq->npds; - if (pq->timeout < min_timeout) { - min_timeout = pq->timeout; - } - for (; pds < epds; pds++, pollfdPtr++) { - /* - * Assert that the pollfdPtr pointer does not go - * beyond the end of the pollfds array - */ - PR_ASSERT(pollfdPtr < pollfds + npollfds); - pollfdPtr->fd = pds->osfd; - /* direct copy of poll flags */ - pollfdPtr->events = pds->in_flags; - } - } - _PR_IOQ_TIMEOUT(me->cpu) = min_timeout; + if (pq->timeout < min_timeout) { + min_timeout = pq->timeout; + } + for (; pds < epds; pds++, pollfdPtr++) { + /* + * Assert that the pollfdPtr pointer does not go + * beyond the end of the pollfds array + */ + PR_ASSERT(pollfdPtr < pollfds + npollfds); + pollfdPtr->fd = pds->osfd; + /* direct copy of poll flags */ + pollfdPtr->events = pds->in_flags; + } + } + _PR_IOQ_TIMEOUT(me->cpu) = min_timeout; #else - /* + /* * assigment of fd_sets */ - r = _PR_FD_READ_SET(me->cpu); - w = _PR_FD_WRITE_SET(me->cpu); - e = _PR_FD_EXCEPTION_SET(me->cpu); + r = _PR_FD_READ_SET(me->cpu); + w = _PR_FD_WRITE_SET(me->cpu); + e = _PR_FD_EXCEPTION_SET(me->cpu); - rp = &r; - wp = &w; - ep = &e; + rp = &r; + wp = &w; + ep = &e; - max_osfd = _PR_IOQ_MAX_OSFD(me->cpu) + 1; - min_timeout = _PR_IOQ_TIMEOUT(me->cpu); + max_osfd = _PR_IOQ_MAX_OSFD(me->cpu) + 1; + min_timeout = _PR_IOQ_TIMEOUT(me->cpu); #endif /* _PR_USE_POLL */ - /* + /* ** Compute the minimum timeout value: make it the smaller of the ** timeouts specified by the i/o pollers or the timeout of the first ** sleeping thread. */ - q = _PR_SLEEPQ(me->cpu).next; + q = _PR_SLEEPQ(me->cpu).next; - if (q != &_PR_SLEEPQ(me->cpu)) { - PRThread *t = _PR_THREAD_PTR(q); + if (q != &_PR_SLEEPQ(me->cpu)) { + PRThread *t = _PR_THREAD_PTR(q); - if (t->sleep < min_timeout) { - min_timeout = t->sleep; - } - } - if (min_timeout > ticks) { - min_timeout = ticks; - } + if (t->sleep < min_timeout) { + min_timeout = t->sleep; + } + } + if (min_timeout > ticks) { + min_timeout = ticks; + } #ifdef _PR_USE_POLL - if (min_timeout == PR_INTERVAL_NO_TIMEOUT) - timeout = -1; - else - timeout = PR_IntervalToMilliseconds(min_timeout); + if (min_timeout == PR_INTERVAL_NO_TIMEOUT) + timeout = -1; + else + timeout = PR_IntervalToMilliseconds(min_timeout); #else - if (min_timeout == PR_INTERVAL_NO_TIMEOUT) { - tvp = NULL; - } else { - timeout.tv_sec = PR_IntervalToSeconds(min_timeout); - timeout.tv_usec = PR_IntervalToMicroseconds(min_timeout) - % PR_USEC_PER_SEC; - tvp = &timeout; - } + if (min_timeout == PR_INTERVAL_NO_TIMEOUT) { + tvp = NULL; + } else { + timeout.tv_sec = PR_IntervalToSeconds(min_timeout); + timeout.tv_usec = PR_IntervalToMicroseconds(min_timeout) + % PR_USEC_PER_SEC; + tvp = &timeout; + } #endif /* _PR_USE_POLL */ - _PR_MD_IOQ_UNLOCK(); - _MD_CHECK_FOR_EXIT(); - /* + _PR_MD_IOQ_UNLOCK(); + _MD_CHECK_FOR_EXIT(); + /* * check for i/o operations */ #ifndef _PR_NO_CLOCK_TIMER - /* + /* * Disable the clock interrupts while we are in select, if clock interrupts * are enabled. Otherwise, when the select/poll calls are interrupted, the * timer value starts ticking from zero again when the system call is restarted. */ #ifdef IRIX - /* - * SIGCHLD signal is used on Irix to detect he termination of an - * sproc by SIGSEGV, SIGBUS or SIGABRT signals when - * _nspr_terminate_on_error is set. - */ - if ((!_nspr_noclock) || (_nspr_terminate_on_error)) + /* + * SIGCHLD signal is used on Irix to detect he termination of an + * sproc by SIGSEGV, SIGBUS or SIGABRT signals when + * _nspr_terminate_on_error is set. + */ + if ((!_nspr_noclock) || (_nspr_terminate_on_error)) #else - if (!_nspr_noclock) -#endif /* IRIX */ + if (!_nspr_noclock) +#endif /* IRIX */ #ifdef IRIX - sigprocmask(SIG_BLOCK, &ints_off, &oldset); + sigprocmask(SIG_BLOCK, &ints_off, &oldset); #else - PR_ASSERT(sigismember(&timer_set, SIGALRM)); - sigprocmask(SIG_BLOCK, &timer_set, &oldset); -#endif /* IRIX */ + PR_ASSERT(sigismember(&timer_set, SIGALRM)); + sigprocmask(SIG_BLOCK, &timer_set, &oldset); +#endif /* IRIX */ #endif /* !_PR_NO_CLOCK_TIMER */ #ifndef _PR_USE_POLL - PR_ASSERT(FD_ISSET(_pr_md_pipefd[0],rp)); - nfd = _MD_SELECT(max_osfd, rp, wp, ep, tvp); + PR_ASSERT(FD_ISSET(_pr_md_pipefd[0],rp)); + nfd = _MD_SELECT(max_osfd, rp, wp, ep, tvp); #else - nfd = _MD_POLL(pollfds, npollfds, timeout); + nfd = _MD_POLL(pollfds, npollfds, timeout); #endif /* !_PR_USE_POLL */ #ifndef _PR_NO_CLOCK_TIMER #ifdef IRIX - if ((!_nspr_noclock) || (_nspr_terminate_on_error)) + if ((!_nspr_noclock) || (_nspr_terminate_on_error)) #else - if (!_nspr_noclock) -#endif /* IRIX */ - sigprocmask(SIG_SETMASK, &oldset, 0); + if (!_nspr_noclock) +#endif /* IRIX */ + sigprocmask(SIG_SETMASK, &oldset, 0); #endif /* !_PR_NO_CLOCK_TIMER */ - _MD_CHECK_FOR_EXIT(); - _PR_MD_IOQ_LOCK(); - /* + _MD_CHECK_FOR_EXIT(); + +#ifdef IRIX + _PR_MD_primordial_cpu(); +#endif + + _PR_MD_IOQ_LOCK(); + /* ** Notify monitors that are associated with the selected descriptors. */ #ifdef _PR_USE_POLL - if (nfd > 0) { - pollfdPtr = pollfds; - if (_PR_IS_NATIVE_THREAD_SUPPORTED()) { + if (nfd > 0) { + pollfdPtr = pollfds; + if (_PR_IS_NATIVE_THREAD_SUPPORTED()) { + /* + * Assert that the pipe is the first element in the + * pollfds array. + */ + PR_ASSERT(pollfds[0].fd == _pr_md_pipefd[0]); + if ((pollfds[0].revents & POLLIN) && (nfd == 1)) { + /* + * woken up by another thread; read all the data + * in the pipe to empty the pipe + */ + while ((rv = read(_pr_md_pipefd[0], _pr_md_pipebuf, + PIPE_BUF)) == PIPE_BUF){ + } + PR_ASSERT((rv > 0) || ((rv == -1) && (errno == EAGAIN))); + } + pollfdPtr++; +#ifdef IRIX /* - * Assert that the pipe is the first element in the - * pollfds array. - */ - PR_ASSERT(pollfds[0].fd == _pr_md_pipefd[0]); - if ((pollfds[0].revents & PR_POLL_READ) && (nfd == 1)) { - /* - * woken up by another thread; read all the data - * in the pipe to empty the pipe - */ - while ((rv = read(_pr_md_pipefd[0], _pr_md_pipebuf, - PIPE_BUF)) == PIPE_BUF){ + * On Irix, check to see if the primordial cpu needs to exit + * to cause the process to terminate + */ + if (me->cpu->id == 0) { + PR_ASSERT(pollfds[1].fd == _pr_irix_primoridal_cpu_fd[0]); + if (pollfdPtr->revents & POLLIN) { + if (_pr_irix_process_exit) { + /* + * process exit due to a call to PR_ProcessExit + */ + prctl(PR_SETEXITSIG, SIGKILL); + _exit(_pr_irix_process_exit_code); + } else { + while ((rv = read(_pr_irix_primoridal_cpu_fd[0], + _pr_md_pipebuf, PIPE_BUF)) == PIPE_BUF) { + } + PR_ASSERT(rv > 0); + } } - PR_ASSERT((rv > 0) || ((rv == -1) && (errno == EAGAIN))); + pollfdPtr++; } - pollfdPtr++; - } - for (q = _PR_IOQ(me->cpu).next; q != &_PR_IOQ(me->cpu); q = q->next) { - PRPollQueue *pq = _PR_POLLQUEUE_PTR(q); - PRBool notify = PR_FALSE; - _PRUnixPollDesc *pds = pq->pds; - _PRUnixPollDesc *epds = pds + pq->npds; +#endif + } + for (q = _PR_IOQ(me->cpu).next; q != &_PR_IOQ(me->cpu); q = q->next) { + PRPollQueue *pq = _PR_POLLQUEUE_PTR(q); + PRBool notify = PR_FALSE; + _PRUnixPollDesc *pds = pq->pds; + _PRUnixPollDesc *epds = pds + pq->npds; - for (; pds < epds; pds++, pollfdPtr++) { - /* - * Assert that the pollfdPtr pointer does not go beyond - * the end of the pollfds array. - */ - PR_ASSERT(pollfdPtr < pollfds + npollfds); - /* - * Assert that the fd's in the pollfds array (stepped - * through by pollfdPtr) are in the same order as - * the fd's in _PR_IOQ() (stepped through by q and pds). - * This is how the pollfds array was created earlier. - */ - PR_ASSERT(pollfdPtr->fd == pds->osfd); - pds->out_flags = pollfdPtr->revents; - /* Negative fd's are ignored by poll() */ - if (pds->osfd >= 0 && pds->out_flags) { - notify = PR_TRUE; - } - } - if (notify) { - PRIntn pri; - PRThread *thred; + for (; pds < epds; pds++, pollfdPtr++) { + /* + * Assert that the pollfdPtr pointer does not go beyond + * the end of the pollfds array. + */ + PR_ASSERT(pollfdPtr < pollfds + npollfds); + /* + * Assert that the fd's in the pollfds array (stepped + * through by pollfdPtr) are in the same order as + * the fd's in _PR_IOQ() (stepped through by q and pds). + * This is how the pollfds array was created earlier. + */ + PR_ASSERT(pollfdPtr->fd == pds->osfd); + pds->out_flags = pollfdPtr->revents; + /* Negative fd's are ignored by poll() */ + if (pds->osfd >= 0 && pds->out_flags) { + notify = PR_TRUE; + } + } + if (notify) { + PRIntn pri; + PRThread *thred; - PR_REMOVE_LINK(&pq->links); - pq->on_ioq = PR_FALSE; + PR_REMOVE_LINK(&pq->links); + pq->on_ioq = PR_FALSE; - thred = pq->thr; + thred = pq->thr; _PR_THREAD_LOCK(thred); - if (pq->thr->flags & (_PR_ON_PAUSEQ|_PR_ON_SLEEPQ)) { - _PRCPU *cpu = pq->thr->cpu; - _PR_SLEEPQ_LOCK(pq->thr->cpu); - _PR_DEL_SLEEPQ(pq->thr, PR_TRUE); - _PR_SLEEPQ_UNLOCK(pq->thr->cpu); - - pri = pq->thr->priority; - pq->thr->state = _PR_RUNNABLE; - - _PR_RUNQ_LOCK(cpu); - _PR_ADD_RUNQ(pq->thr, cpu, pri); - _PR_RUNQ_UNLOCK(cpu); - if (_pr_md_idle_cpus > 1) - _PR_MD_WAKEUP_WAITER(thred); - } - _PR_THREAD_UNLOCK(thred); - _PR_IOQ_OSFD_CNT(me->cpu) -= pq->npds; - PR_ASSERT(_PR_IOQ_OSFD_CNT(me->cpu) >= 0); - } - } - } else if (nfd == -1) { - PR_LOG(_pr_io_lm, PR_LOG_MAX, ("poll() failed with errno %d", errno)); - } + if (pq->thr->flags & (_PR_ON_PAUSEQ|_PR_ON_SLEEPQ)) { + _PRCPU *cpu = pq->thr->cpu; + _PR_SLEEPQ_LOCK(pq->thr->cpu); + _PR_DEL_SLEEPQ(pq->thr, PR_TRUE); + _PR_SLEEPQ_UNLOCK(pq->thr->cpu); + + pri = pq->thr->priority; + pq->thr->state = _PR_RUNNABLE; + + _PR_RUNQ_LOCK(cpu); + _PR_ADD_RUNQ(pq->thr, cpu, pri); + _PR_RUNQ_UNLOCK(cpu); + if (_pr_md_idle_cpus > 1) + _PR_MD_WAKEUP_WAITER(thred); + } + _PR_THREAD_UNLOCK(thred); + _PR_IOQ_OSFD_CNT(me->cpu) -= pq->npds; + PR_ASSERT(_PR_IOQ_OSFD_CNT(me->cpu) >= 0); + } + } + } else if (nfd == -1) { + PR_LOG(_pr_io_lm, PR_LOG_MAX, ("poll() failed with errno %d", errno)); + } #else - if (nfd > 0) { - q = _PR_IOQ(me->cpu).next; - _PR_IOQ_MAX_OSFD(me->cpu) = -1; - _PR_IOQ_TIMEOUT(me->cpu) = PR_INTERVAL_NO_TIMEOUT; - while (q != &_PR_IOQ(me->cpu)) { - PRPollQueue *pq = _PR_POLLQUEUE_PTR(q); - PRBool notify = PR_FALSE; - _PRUnixPollDesc *pds = pq->pds; - _PRUnixPollDesc *epds = pds + pq->npds; - PRInt32 pq_max_osfd = -1; - - q = q->next; - for (; pds < epds; pds++) { - PRInt32 osfd = pds->osfd; - PRInt16 in_flags = pds->in_flags; - PRInt16 out_flags = 0; - PR_ASSERT(osfd >= 0 || in_flags == 0); - if ((in_flags & PR_POLL_READ) && FD_ISSET(osfd, rp)) { - out_flags |= PR_POLL_READ; - } - if ((in_flags & PR_POLL_WRITE) && FD_ISSET(osfd, wp)) { - out_flags |= PR_POLL_WRITE; - } - if ((in_flags & PR_POLL_EXCEPT) && FD_ISSET(osfd, ep)) { - out_flags |= PR_POLL_EXCEPT; - } - pds->out_flags = out_flags; - if (out_flags) { - notify = PR_TRUE; - } - if (osfd > pq_max_osfd) { - pq_max_osfd = osfd; - } - } - if (notify == PR_TRUE) { - PRIntn pri; - PRThread *thred; + if (nfd > 0) { + q = _PR_IOQ(me->cpu).next; + _PR_IOQ_MAX_OSFD(me->cpu) = -1; + _PR_IOQ_TIMEOUT(me->cpu) = PR_INTERVAL_NO_TIMEOUT; + while (q != &_PR_IOQ(me->cpu)) { + PRPollQueue *pq = _PR_POLLQUEUE_PTR(q); + PRBool notify = PR_FALSE; + _PRUnixPollDesc *pds = pq->pds; + _PRUnixPollDesc *epds = pds + pq->npds; + PRInt32 pq_max_osfd = -1; + + q = q->next; + for (; pds < epds; pds++) { + PRInt32 osfd = pds->osfd; + PRInt16 in_flags = pds->in_flags; + PRInt16 out_flags = 0; + PR_ASSERT(osfd >= 0 || in_flags == 0); + if ((in_flags & _PR_UNIX_POLL_READ) && FD_ISSET(osfd, rp)) { + out_flags |= _PR_UNIX_POLL_READ; + } + if ((in_flags & _PR_UNIX_POLL_WRITE) && FD_ISSET(osfd, wp)) { + out_flags |= _PR_UNIX_POLL_WRITE; + } + if ((in_flags & _PR_UNIX_POLL_EXCEPT) && FD_ISSET(osfd, ep)) { + out_flags |= _PR_UNIX_POLL_EXCEPT; + } + pds->out_flags = out_flags; + if (out_flags) { + notify = PR_TRUE; + } + if (osfd > pq_max_osfd) { + pq_max_osfd = osfd; + } + } + if (notify == PR_TRUE) { + PRIntn pri; + PRThread *thred; - PR_REMOVE_LINK(&pq->links); - pq->on_ioq = PR_FALSE; + PR_REMOVE_LINK(&pq->links); + pq->on_ioq = PR_FALSE; - /* - * Decrement the count of descriptors for each desciptor/event - * because this I/O request is being removed from the - * ioq - */ - pds = pq->pds; - for (; pds < epds; pds++) { - PRInt32 osfd = pds->osfd; - PRInt16 in_flags = pds->in_flags; - PR_ASSERT(osfd >= 0 || in_flags == 0); - if (in_flags & PR_POLL_READ) { - if (--(_PR_FD_READ_CNT(me->cpu))[osfd] == 0) - FD_CLR(osfd, &_PR_FD_READ_SET(me->cpu)); - } - if (in_flags & PR_POLL_WRITE) { - if (--(_PR_FD_WRITE_CNT(me->cpu))[osfd] == 0) - FD_CLR(osfd, &_PR_FD_WRITE_SET(me->cpu)); - } - if (in_flags & PR_POLL_EXCEPT) { - if (--(_PR_FD_EXCEPTION_CNT(me->cpu))[osfd] == 0) - FD_CLR(osfd, &_PR_FD_EXCEPTION_SET(me->cpu)); - } - } + /* + * Decrement the count of descriptors for each desciptor/event + * because this I/O request is being removed from the + * ioq + */ + pds = pq->pds; + for (; pds < epds; pds++) { + PRInt32 osfd = pds->osfd; + PRInt16 in_flags = pds->in_flags; + PR_ASSERT(osfd >= 0 || in_flags == 0); + if (in_flags & _PR_UNIX_POLL_READ) { + if (--(_PR_FD_READ_CNT(me->cpu))[osfd] == 0) + FD_CLR(osfd, &_PR_FD_READ_SET(me->cpu)); + } + if (in_flags & _PR_UNIX_POLL_WRITE) { + if (--(_PR_FD_WRITE_CNT(me->cpu))[osfd] == 0) + FD_CLR(osfd, &_PR_FD_WRITE_SET(me->cpu)); + } + if (in_flags & _PR_UNIX_POLL_EXCEPT) { + if (--(_PR_FD_EXCEPTION_CNT(me->cpu))[osfd] == 0) + FD_CLR(osfd, &_PR_FD_EXCEPTION_SET(me->cpu)); + } + } - /* - * Because this thread can run on a different cpu right - * after being added to the run queue, do not dereference - * pq - */ - thred = pq->thr; + /* + * Because this thread can run on a different cpu right + * after being added to the run queue, do not dereference + * pq + */ + thred = pq->thr; _PR_THREAD_LOCK(thred); - if (pq->thr->flags & (_PR_ON_PAUSEQ|_PR_ON_SLEEPQ)) { - _PRCPU *cpu = thred->cpu; - _PR_SLEEPQ_LOCK(pq->thr->cpu); - _PR_DEL_SLEEPQ(pq->thr, PR_TRUE); - _PR_SLEEPQ_UNLOCK(pq->thr->cpu); - - pri = pq->thr->priority; - pq->thr->state = _PR_RUNNABLE; - - pq->thr->cpu = cpu; - _PR_RUNQ_LOCK(cpu); - _PR_ADD_RUNQ(pq->thr, cpu, pri); - _PR_RUNQ_UNLOCK(cpu); - if (_pr_md_idle_cpus > 1) - _PR_MD_WAKEUP_WAITER(thred); + if (pq->thr->flags & (_PR_ON_PAUSEQ|_PR_ON_SLEEPQ)) { + _PRCPU *cpu = thred->cpu; + _PR_SLEEPQ_LOCK(pq->thr->cpu); + _PR_DEL_SLEEPQ(pq->thr, PR_TRUE); + _PR_SLEEPQ_UNLOCK(pq->thr->cpu); + + pri = pq->thr->priority; + pq->thr->state = _PR_RUNNABLE; + + pq->thr->cpu = cpu; + _PR_RUNQ_LOCK(cpu); + _PR_ADD_RUNQ(pq->thr, cpu, pri); + _PR_RUNQ_UNLOCK(cpu); + if (_pr_md_idle_cpus > 1) + _PR_MD_WAKEUP_WAITER(thred); + } + _PR_THREAD_UNLOCK(thred); + } else { + if (pq->timeout < _PR_IOQ_TIMEOUT(me->cpu)) + _PR_IOQ_TIMEOUT(me->cpu) = pq->timeout; + if (_PR_IOQ_MAX_OSFD(me->cpu) < pq_max_osfd) + _PR_IOQ_MAX_OSFD(me->cpu) = pq_max_osfd; + } + } + if (_PR_IS_NATIVE_THREAD_SUPPORTED()) { + if ((FD_ISSET(_pr_md_pipefd[0], rp)) && (nfd == 1)) { + /* + * woken up by another thread; read all the data + * in the pipe to empty the pipe + */ + while ((rv = + read(_pr_md_pipefd[0], _pr_md_pipebuf, PIPE_BUF)) + == PIPE_BUF){ + } + PR_ASSERT((rv > 0) || + ((rv == -1) && (errno == EAGAIN))); + } + if (_PR_IOQ_MAX_OSFD(me->cpu) < _pr_md_pipefd[0]) + _PR_IOQ_MAX_OSFD(me->cpu) = _pr_md_pipefd[0]; +#ifdef IRIX + if ((me->cpu->id == 0) && + (FD_ISSET(_pr_irix_primoridal_cpu_fd[0], rp))) { + if (_pr_irix_process_exit) { + /* + * process exit due to a call to PR_ProcessExit + */ + prctl(PR_SETEXITSIG, SIGKILL); + _exit(_pr_irix_process_exit_code); + } else { + while ((rv = read(_pr_irix_primoridal_cpu_fd[0], + _pr_md_pipebuf, PIPE_BUF)) == PIPE_BUF) { + } + PR_ASSERT(rv > 0); } - _PR_THREAD_UNLOCK(thred); - } else { - if (pq->timeout < _PR_IOQ_TIMEOUT(me->cpu)) - _PR_IOQ_TIMEOUT(me->cpu) = pq->timeout; - if (_PR_IOQ_MAX_OSFD(me->cpu) < pq_max_osfd) - _PR_IOQ_MAX_OSFD(me->cpu) = pq_max_osfd; } - } - if (_PR_IS_NATIVE_THREAD_SUPPORTED()) { - if ((FD_ISSET(_pr_md_pipefd[0], rp)) && (nfd == 1)) { - /* - * woken up by another thread; read all the data - * in the pipe to empty the pipe - */ - while ((rv = - read(_pr_md_pipefd[0], _pr_md_pipebuf, PIPE_BUF)) - == PIPE_BUF){ - } - PR_ASSERT((rv > 0) || - ((rv == -1) && (errno == EAGAIN))); + if (me->cpu->id == 0) { + if (_PR_IOQ_MAX_OSFD(me->cpu) < _pr_irix_primoridal_cpu_fd[0]) + _PR_IOQ_MAX_OSFD(me->cpu) = _pr_irix_primoridal_cpu_fd[0]; } - if (_PR_IOQ_MAX_OSFD(me->cpu) < _pr_md_pipefd[0]) - _PR_IOQ_MAX_OSFD(me->cpu) = _pr_md_pipefd[0]; - } - } else if (nfd < 0) { - if (errno == EBADF) { - FindBadFDs(); - } else { - PR_LOG(_pr_io_lm, PR_LOG_MAX, ("select() failed with errno %d", - errno)); - } - } else { - PR_ASSERT(nfd == 0); - /* - * compute the new value of _PR_IOQ_TIMEOUT - */ - q = _PR_IOQ(me->cpu).next; - _PR_IOQ_MAX_OSFD(me->cpu) = -1; - _PR_IOQ_TIMEOUT(me->cpu) = PR_INTERVAL_NO_TIMEOUT; - while (q != &_PR_IOQ(me->cpu)) { - PRPollQueue *pq = _PR_POLLQUEUE_PTR(q); - _PRUnixPollDesc *pds = pq->pds; - _PRUnixPollDesc *epds = pds + pq->npds; - PRInt32 pq_max_osfd = -1; - - q = q->next; - for (; pds < epds; pds++) { - if (pds->osfd > pq_max_osfd) { - pq_max_osfd = pds->osfd; - } - } - if (pq->timeout < _PR_IOQ_TIMEOUT(me->cpu)) - _PR_IOQ_TIMEOUT(me->cpu) = pq->timeout; - if (_PR_IOQ_MAX_OSFD(me->cpu) < pq_max_osfd) - _PR_IOQ_MAX_OSFD(me->cpu) = pq_max_osfd; - } - if (_PR_IS_NATIVE_THREAD_SUPPORTED()) { - if (_PR_IOQ_MAX_OSFD(me->cpu) < _pr_md_pipefd[0]) - _PR_IOQ_MAX_OSFD(me->cpu) = _pr_md_pipefd[0]; - } - } +#endif + } + } else if (nfd < 0) { + if (errno == EBADF) { + FindBadFDs(); + } else { + PR_LOG(_pr_io_lm, PR_LOG_MAX, ("select() failed with errno %d", + errno)); + } + } else { + PR_ASSERT(nfd == 0); + /* + * compute the new value of _PR_IOQ_TIMEOUT + */ + q = _PR_IOQ(me->cpu).next; + _PR_IOQ_MAX_OSFD(me->cpu) = -1; + _PR_IOQ_TIMEOUT(me->cpu) = PR_INTERVAL_NO_TIMEOUT; + while (q != &_PR_IOQ(me->cpu)) { + PRPollQueue *pq = _PR_POLLQUEUE_PTR(q); + _PRUnixPollDesc *pds = pq->pds; + _PRUnixPollDesc *epds = pds + pq->npds; + PRInt32 pq_max_osfd = -1; + + q = q->next; + for (; pds < epds; pds++) { + if (pds->osfd > pq_max_osfd) { + pq_max_osfd = pds->osfd; + } + } + if (pq->timeout < _PR_IOQ_TIMEOUT(me->cpu)) + _PR_IOQ_TIMEOUT(me->cpu) = pq->timeout; + if (_PR_IOQ_MAX_OSFD(me->cpu) < pq_max_osfd) + _PR_IOQ_MAX_OSFD(me->cpu) = pq_max_osfd; + } + if (_PR_IS_NATIVE_THREAD_SUPPORTED()) { + if (_PR_IOQ_MAX_OSFD(me->cpu) < _pr_md_pipefd[0]) + _PR_IOQ_MAX_OSFD(me->cpu) = _pr_md_pipefd[0]; + } + } #endif /* _PR_USE_POLL */ - _PR_MD_IOQ_UNLOCK(); + _PR_MD_IOQ_UNLOCK(); } void _MD_Wakeup_CPUs() { - PRInt32 rv, data; + PRInt32 rv, data; - data = 0; - rv = write(_pr_md_pipefd[1], &data, 1); + data = 0; + rv = write(_pr_md_pipefd[1], &data, 1); - while ((rv < 0) && (errno == EAGAIN)) { - /* - * pipe full, read all data in pipe to empty it - */ - while ((rv = - read(_pr_md_pipefd[0], _pr_md_pipebuf, PIPE_BUF)) - == PIPE_BUF) { - } - PR_ASSERT((rv > 0) || - ((rv == -1) && (errno == EAGAIN))); - rv = write(_pr_md_pipefd[1], &data, 1); - } + while ((rv < 0) && (errno == EAGAIN)) { + /* + * pipe full, read all data in pipe to empty it + */ + while ((rv = + read(_pr_md_pipefd[0], _pr_md_pipebuf, PIPE_BUF)) + == PIPE_BUF) { + } + PR_ASSERT((rv > 0) || + ((rv == -1) && (errno == EAGAIN))); + rv = write(_pr_md_pipefd[1], &data, 1); + } } void _MD_InitCPUS() { - PRInt32 rv, flags; - PRThread *me = _MD_CURRENT_THREAD(); + PRInt32 rv, flags; + PRThread *me = _MD_CURRENT_THREAD(); - rv = pipe(_pr_md_pipefd); - PR_ASSERT(rv == 0); - _PR_IOQ_MAX_OSFD(me->cpu) = _pr_md_pipefd[0]; + rv = pipe(_pr_md_pipefd); + PR_ASSERT(rv == 0); + _PR_IOQ_MAX_OSFD(me->cpu) = _pr_md_pipefd[0]; #ifndef _PR_USE_POLL - FD_SET(_pr_md_pipefd[0], &_PR_FD_READ_SET(me->cpu)); + FD_SET(_pr_md_pipefd[0], &_PR_FD_READ_SET(me->cpu)); #endif - flags = fcntl(_pr_md_pipefd[0], F_GETFL, 0); - fcntl(_pr_md_pipefd[0], F_SETFL, flags | O_NONBLOCK); - flags = fcntl(_pr_md_pipefd[1], F_GETFL, 0); - fcntl(_pr_md_pipefd[1], F_SETFL, flags | O_NONBLOCK); + flags = fcntl(_pr_md_pipefd[0], F_GETFL, 0); + fcntl(_pr_md_pipefd[0], F_SETFL, flags | O_NONBLOCK); + flags = fcntl(_pr_md_pipefd[1], F_GETFL, 0); + fcntl(_pr_md_pipefd[1], F_SETFL, flags | O_NONBLOCK); } /* @@ -2438,68 +1908,68 @@ void _MD_InitCPUS() */ static void ClockInterruptHandler() { - int olderrno; - PRUintn pri; - _PRCPU *cpu = _PR_MD_CURRENT_CPU(); - PRThread *me = _MD_CURRENT_THREAD(); + int olderrno; + PRUintn pri; + _PRCPU *cpu = _PR_MD_CURRENT_CPU(); + PRThread *me = _MD_CURRENT_THREAD(); #ifdef SOLARIS - if (!me || _PR_IS_NATIVE_THREAD(me)) { - _pr_primordialCPU->u.missed[_pr_primordialCPU->where] |= _PR_MISSED_CLOCK; - return; - } + if (!me || _PR_IS_NATIVE_THREAD(me)) { + _pr_primordialCPU->u.missed[_pr_primordialCPU->where] |= _PR_MISSED_CLOCK; + return; + } #endif - if (_PR_MD_GET_INTSOFF() != 0) { - cpu->u.missed[cpu->where] |= _PR_MISSED_CLOCK; - return; - } - _PR_MD_SET_INTSOFF(1); + if (_PR_MD_GET_INTSOFF() != 0) { + cpu->u.missed[cpu->where] |= _PR_MISSED_CLOCK; + return; + } + _PR_MD_SET_INTSOFF(1); - olderrno = errno; - _PR_ClockInterrupt(); - errno = olderrno; + olderrno = errno; + _PR_ClockInterrupt(); + errno = olderrno; - /* + /* ** If the interrupt wants a resched or if some other thread at ** the same priority needs the cpu, reschedule. */ - pri = me->priority; - if ((cpu->u.missed[3] || (_PR_RUNQREADYMASK(me->cpu) >> pri))) { + pri = me->priority; + if ((cpu->u.missed[3] || (_PR_RUNQREADYMASK(me->cpu) >> pri))) { #ifdef _PR_NO_PREEMPT - cpu->resched = PR_TRUE; - if (pr_interruptSwitchHook) { - (*pr_interruptSwitchHook)(pr_interruptSwitchHookArg); - } + cpu->resched = PR_TRUE; + if (pr_interruptSwitchHook) { + (*pr_interruptSwitchHook)(pr_interruptSwitchHookArg); + } #else /* _PR_NO_PREEMPT */ - /* + /* ** Re-enable unix interrupts (so that we can use ** setjmp/longjmp for context switching without having to ** worry about the signal state) */ - sigprocmask(SIG_SETMASK, &empty_set, 0); - PR_LOG(_pr_sched_lm, PR_LOG_MIN, ("clock caused context switch")); - - if(!(me->flags & _PR_IDLE_THREAD)) { - _PR_THREAD_LOCK(me); - me->state = _PR_RUNNABLE; - me->cpu = cpu; - _PR_RUNQ_LOCK(cpu); - _PR_ADD_RUNQ(me, cpu, pri); - _PR_RUNQ_UNLOCK(cpu); - _PR_THREAD_UNLOCK(me); - } else - me->state = _PR_RUNNABLE; - _MD_SWITCH_CONTEXT(me); - PR_LOG(_pr_sched_lm, PR_LOG_MIN, ("clock back from context switch")); + sigprocmask(SIG_SETMASK, &empty_set, 0); + PR_LOG(_pr_sched_lm, PR_LOG_MIN, ("clock caused context switch")); + + if(!(me->flags & _PR_IDLE_THREAD)) { + _PR_THREAD_LOCK(me); + me->state = _PR_RUNNABLE; + me->cpu = cpu; + _PR_RUNQ_LOCK(cpu); + _PR_ADD_RUNQ(me, cpu, pri); + _PR_RUNQ_UNLOCK(cpu); + _PR_THREAD_UNLOCK(me); + } else + me->state = _PR_RUNNABLE; + _MD_SWITCH_CONTEXT(me); + PR_LOG(_pr_sched_lm, PR_LOG_MIN, ("clock back from context switch")); #endif /* _PR_NO_PREEMPT */ - } - /* + } + /* * Because this thread could be running on a different cpu after * a context switch the current cpu should be accessed and the * value of the 'cpu' variable should not be used. */ - _PR_MD_SET_INTSOFF(0); + _PR_MD_SET_INTSOFF(0); } /* @@ -2525,204 +1995,704 @@ static void HPUX9_ClockInterruptHandler( void _MD_StartInterrupts() { - struct itimerval itval; - char *eval; + struct itimerval itval; + char *eval; #ifdef HPUX9 - struct sigvec vec; + struct sigvec vec; - vec.sv_handler = (void (*)()) HPUX9_ClockInterruptHandler; - vec.sv_mask = 0; - vec.sv_flags = 0; - sigvector(SIGALRM, &vec, 0); + vec.sv_handler = (void (*)()) HPUX9_ClockInterruptHandler; + vec.sv_mask = 0; + vec.sv_flags = 0; + sigvector(SIGALRM, &vec, 0); #else - struct sigaction vtact; + struct sigaction vtact; - vtact.sa_handler = (void (*)()) ClockInterruptHandler; - sigemptyset(&vtact.sa_mask); - vtact.sa_flags = SA_RESTART; - sigaction(SIGALRM, &vtact, 0); + vtact.sa_handler = (void (*)()) ClockInterruptHandler; + sigemptyset(&vtact.sa_mask); + vtact.sa_flags = SA_RESTART; + sigaction(SIGALRM, &vtact, 0); #endif /* HPUX9 */ - if ((eval = getenv("NSPR_NOCLOCK")) != NULL) { - if (atoi(eval) == 0) - _nspr_noclock = 0; - else - _nspr_noclock = 1; - } + if ((eval = getenv("NSPR_NOCLOCK")) != NULL) { + if (atoi(eval) == 0) + _nspr_noclock = 0; + else + _nspr_noclock = 1; + } #ifndef _PR_NO_CLOCK_TIMER - if (!_nspr_noclock) { - itval.it_interval.tv_sec = 0; - itval.it_interval.tv_usec = MSEC_PER_TICK * PR_USEC_PER_MSEC; - itval.it_value = itval.it_interval; - setitimer(ITIMER_REAL, &itval, 0); - } + if (!_nspr_noclock) { + itval.it_interval.tv_sec = 0; + itval.it_interval.tv_usec = MSEC_PER_TICK * PR_USEC_PER_MSEC; + itval.it_value = itval.it_interval; + setitimer(ITIMER_REAL, &itval, 0); + } #endif } void _MD_StopInterrupts() { - sigprocmask(SIG_BLOCK, &timer_set, 0); + sigprocmask(SIG_BLOCK, &timer_set, 0); +} + +void _MD_EnableClockInterrupts() +{ + struct itimerval itval; + extern PRUintn _pr_numCPU; + + PR_ASSERT(_pr_numCPU == 1); + itval.it_interval.tv_sec = 0; + itval.it_interval.tv_usec = MSEC_PER_TICK * PR_USEC_PER_MSEC; + itval.it_value = itval.it_interval; + setitimer(ITIMER_REAL, &itval, 0); } void _MD_DisableClockInterrupts() { - struct itimerval itval; - extern PRUintn _pr_numCPU; + struct itimerval itval; + extern PRUintn _pr_numCPU; - PR_ASSERT(_pr_numCPU == 1); - if (!_nspr_noclock) { - itval.it_interval.tv_sec = 0; - itval.it_interval.tv_usec = 0; - itval.it_value = itval.it_interval; - setitimer(ITIMER_REAL, &itval, 0); - } + PR_ASSERT(_pr_numCPU == 1); + itval.it_interval.tv_sec = 0; + itval.it_interval.tv_usec = 0; + itval.it_value = itval.it_interval; + setitimer(ITIMER_REAL, &itval, 0); } void _MD_BlockClockInterrupts() { - sigprocmask(SIG_BLOCK, &timer_set, 0); + sigprocmask(SIG_BLOCK, &timer_set, 0); } void _MD_UnblockClockInterrupts() { - sigprocmask(SIG_UNBLOCK, &timer_set, 0); + sigprocmask(SIG_UNBLOCK, &timer_set, 0); } void _MD_MakeNonblock(PRFileDesc *fd) { - PRInt32 osfd = fd->secret->md.osfd; - int flags; + PRInt32 osfd = fd->secret->md.osfd; + int flags; - if (osfd <= 2) { - /* Don't mess around with stdin, stdout or stderr */ - return; - } - flags = fcntl(osfd, F_GETFL, 0); + if (osfd <= 2) { + /* Don't mess around with stdin, stdout or stderr */ + return; + } + flags = fcntl(osfd, F_GETFL, 0); - /* + /* * Use O_NONBLOCK (POSIX-style non-blocking I/O) whenever possible. * On SunOS 4, we must use FNDELAY (BSD-style non-blocking I/O), * otherwise connect() still blocks and can be interrupted by SIGALRM. */ #ifdef SUNOS4 - fcntl(osfd, F_SETFL, flags | FNDELAY); + fcntl(osfd, F_SETFL, flags | FNDELAY); #else - fcntl(osfd, F_SETFL, flags | O_NONBLOCK); + fcntl(osfd, F_SETFL, flags | O_NONBLOCK); #endif - } + } PRInt32 _MD_open(const char *name, PRIntn flags, PRIntn mode) { - PRInt32 osflags; - PRInt32 rv, err; + PRInt32 osflags; + PRInt32 rv, err; - if (flags & PR_RDWR) { - osflags = O_RDWR; - } else if (flags & PR_WRONLY) { - osflags = O_WRONLY; - } else { - osflags = O_RDONLY; - } + if (flags & PR_RDWR) { + osflags = O_RDWR; + } else if (flags & PR_WRONLY) { + osflags = O_WRONLY; + } else { + osflags = O_RDONLY; + } - if (flags & PR_APPEND) - osflags |= O_APPEND; - if (flags & PR_TRUNCATE) - osflags |= O_TRUNC; - if (flags & PR_SYNC) { + if (flags & PR_APPEND) + osflags |= O_APPEND; + if (flags & PR_TRUNCATE) + osflags |= O_TRUNC; + if (flags & PR_SYNC) { #if defined(O_SYNC) - osflags |= O_SYNC; + osflags |= O_SYNC; #elif defined(O_FSYNC) - osflags |= O_FSYNC; + osflags |= O_FSYNC; #else #error "Neither O_SYNC nor O_FSYNC is defined on this platform" #endif - } + } /* ** On creations we hold the 'create' lock in order to enforce ** the semantics of PR_Rename. (see the latter for more details) */ - if (flags & PR_CREATE_FILE) + if (flags & PR_CREATE_FILE) { - osflags |= O_CREAT ; + osflags |= O_CREAT; if (NULL !=_pr_rename_lock) PR_Lock(_pr_rename_lock); } - rv = open(name, osflags, mode); + rv = _md_iovector._open64(name, osflags, mode); - if (rv < 0) { - err = _MD_ERRNO(); - _PR_MD_MAP_OPEN_ERROR(err); - } + if (rv < 0) { + err = _MD_ERRNO(); + _PR_MD_MAP_OPEN_ERROR(err); + } if ((flags & PR_CREATE_FILE) && (NULL !=_pr_rename_lock)) PR_Unlock(_pr_rename_lock); - return rv; + return rv; } PRIntervalTime intr_timeout_ticks; #if defined(SOLARIS) || defined(IRIX) static void sigsegvhandler() { - fprintf(stderr,"Received SIGSEGV\n"); - fflush(stderr); + fprintf(stderr,"Received SIGSEGV\n"); + fflush(stderr); pause(); } static void sigaborthandler() { - fprintf(stderr,"Received SIGABRT\n"); - fflush(stderr); + fprintf(stderr,"Received SIGABRT\n"); + fflush(stderr); pause(); } static void sigbushandler() { - fprintf(stderr,"Received SIGBUS\n"); - fflush(stderr); + fprintf(stderr,"Received SIGBUS\n"); + fflush(stderr); pause(); } #endif /* SOLARIS, IRIX */ #endif /* !defined(_PR_PTHREADS) */ -void _PR_UnixInit() +PRInt32 _MD_lseek(PRFileDesc *fd, PRInt32 offset, PRSeekWhence whence) +{ + PRInt32 rv, where; + + switch (whence) { + case PR_SEEK_SET: + where = SEEK_SET; + break; + case PR_SEEK_CUR: + where = SEEK_CUR; + break; + case PR_SEEK_END: + where = SEEK_END; + break; + default: + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + rv = -1; + goto done; + } + rv = lseek(fd->secret->md.osfd,offset,where); + if (rv == -1) + { + PRInt32 syserr = _MD_ERRNO(); + _PR_MD_MAP_LSEEK_ERROR(syserr); + } +done: + return(rv); +} + +PRInt64 _MD_lseek64(PRFileDesc *fd, PRInt64 offset, PRSeekWhence whence) +{ + PRInt32 where; + PRInt64 rv; + + switch (whence) + { + case PR_SEEK_SET: + where = SEEK_SET; + break; + case PR_SEEK_CUR: + where = SEEK_CUR; + break; + case PR_SEEK_END: + where = SEEK_END; + break; + default: + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + rv = minus_one; + goto done; + } + rv = _md_iovector._lseek64(fd->secret->md.osfd, offset, where); + if (LL_EQ(rv, minus_one)) + { + PRInt32 syserr = _MD_ERRNO(); + _PR_MD_MAP_LSEEK_ERROR(syserr); + } +done: + return rv; +} /* _MD_lseek64 */ + +/* +** _MD_set_fileinfo_times -- +** Set the modifyTime and creationTime of the PRFileInfo +** structure using the values in struct stat. +** +** _MD_set_fileinfo64_times -- +** Set the modifyTime and creationTime of the PRFileInfo64 +** structure using the values in _MDStat64. +*/ + +#if defined(_PR_STAT_HAS_ST_ATIM) +/* +** struct stat has st_atim, st_mtim, and st_ctim fields of +** type timestruc_t. +*/ +static void _MD_set_fileinfo_times( + const struct stat *sb, + PRFileInfo *info) +{ + info->modifyTime = ((PRTime)sb->st_mtim.tv_sec * PR_USEC_PER_SEC); + info->modifyTime += (sb->st_mtim.tv_nsec / 1000); + info->creationTime = ((PRTime)sb->st_ctim.tv_sec * PR_USEC_PER_SEC); + info->creationTime += (sb->st_ctim.tv_nsec / 1000); +} + +static void _MD_set_fileinfo64_times( + const _MDStat64 *sb, + PRFileInfo64 *info) +{ + info->modifyTime = ((PRTime)sb->st_mtim.tv_sec * PR_USEC_PER_SEC); + info->modifyTime += (sb->st_mtim.tv_nsec / 1000); + info->creationTime = ((PRTime)sb->st_ctim.tv_sec * PR_USEC_PER_SEC); + info->creationTime += (sb->st_ctim.tv_nsec / 1000); +} +#elif defined(_PR_STAT_HAS_ST_ATIMESPEC) +/* +** struct stat has st_atimespec, st_mtimespec, and st_ctimespec +** fields of type struct timespec. +*/ +#if defined(_PR_TIMESPEC_HAS_TS_SEC) +static void _MD_set_fileinfo_times( + const struct stat *sb, + PRFileInfo *info) +{ + PRInt64 us, s2us; + + LL_I2L(s2us, PR_USEC_PER_SEC); + LL_I2L(info->modifyTime, sb->st_mtimespec.ts_sec); + LL_MUL(info->modifyTime, info->modifyTime, s2us); + LL_I2L(us, sb->st_mtimespec.ts_nsec / 1000); + LL_ADD(info->modifyTime, info->modifyTime, us); + LL_I2L(info->creationTime, sb->st_ctimespec.ts_sec); + LL_MUL(info->creationTime, info->creationTime, s2us); + LL_I2L(us, sb->st_ctimespec.ts_nsec / 1000); + LL_ADD(info->creationTime, info->creationTime, us); +} + +static void _MD_set_fileinfo64_times( + const _MDStat64 *sb, + PRFileInfo64 *info) +{ + PRInt64 us, s2us; + + LL_I2L(s2us, PR_USEC_PER_SEC); + LL_I2L(info->modifyTime, sb->st_mtimespec.ts_sec); + LL_MUL(info->modifyTime, info->modifyTime, s2us); + LL_I2L(us, sb->st_mtimespec.ts_nsec / 1000); + LL_ADD(info->modifyTime, info->modifyTime, us); + LL_I2L(info->creationTime, sb->st_ctimespec.ts_sec); + LL_MUL(info->creationTime, info->creationTime, s2us); + LL_I2L(us, sb->st_ctimespec.ts_nsec / 1000); + LL_ADD(info->creationTime, info->creationTime, us); +} +#else /* _PR_TIMESPEC_HAS_TS_SEC */ +/* +** The POSIX timespec structure has tv_sec and tv_nsec. +*/ +static void _MD_set_fileinfo_times( + const struct stat *sb, + PRFileInfo *info) +{ + PRInt64 us, s2us; + + LL_I2L(s2us, PR_USEC_PER_SEC); + LL_I2L(info->modifyTime, sb->st_mtimespec.tv_sec); + LL_MUL(info->modifyTime, info->modifyTime, s2us); + LL_I2L(us, sb->st_mtimespec.tv_nsec / 1000); + LL_ADD(info->modifyTime, info->modifyTime, us); + LL_I2L(info->creationTime, sb->st_ctimespec.tv_sec); + LL_MUL(info->creationTime, info->creationTime, s2us); + LL_I2L(us, sb->st_ctimespec.tv_nsec / 1000); + LL_ADD(info->creationTime, info->creationTime, us); +} + +static void _MD_set_fileinfo64_times( + const _MDStat64 *sb, + PRFileInfo64 *info) +{ + PRInt64 us, s2us; + + LL_I2L(s2us, PR_USEC_PER_SEC); + LL_I2L(info->modifyTime, sb->st_mtimespec.tv_sec); + LL_MUL(info->modifyTime, info->modifyTime, s2us); + LL_I2L(us, sb->st_mtimespec.tv_nsec / 1000); + LL_ADD(info->modifyTime, info->modifyTime, us); + LL_I2L(info->creationTime, sb->st_ctimespec.tv_sec); + LL_MUL(info->creationTime, info->creationTime, s2us); + LL_I2L(us, sb->st_ctimespec.tv_nsec / 1000); + LL_ADD(info->creationTime, info->creationTime, us); +} +#endif /* _PR_TIMESPEC_HAS_TS_SEC */ +#elif defined(_PR_STAT_HAS_ONLY_ST_ATIME) +/* +** struct stat only has st_atime, st_mtime, and st_ctime fields +** of type time_t. +*/ +static void _MD_set_fileinfo_times( + const struct stat *sb, + PRFileInfo *info) +{ + PRInt64 s, s2us; + LL_I2L(s2us, PR_USEC_PER_SEC); + LL_I2L(s, sb->st_mtime); + LL_MUL(s, s, s2us); + info->modifyTime = s; + LL_I2L(s, sb->st_ctime); + LL_MUL(s, s, s2us); + info->creationTime = s; +} + +static void _MD_set_fileinfo64_times( + const _MDStat64 *sb, + PRFileInfo64 *info) +{ + PRInt64 s, s2us; + LL_I2L(s2us, PR_USEC_PER_SEC); + LL_I2L(s, sb->st_mtime); + LL_MUL(s, s, s2us); + info->modifyTime = s; + LL_I2L(s, sb->st_ctime); + LL_MUL(s, s, s2us); + info->creationTime = s; +} +#else +#error "I don't know yet" +#endif + +static int _MD_convert_stat_to_fileinfo( + const struct stat *sb, + PRFileInfo *info) +{ + if (S_IFREG & sb->st_mode) + info->type = PR_FILE_FILE; + else if (S_IFDIR & sb->st_mode) + info->type = PR_FILE_DIRECTORY; + else + info->type = PR_FILE_OTHER; + +#if defined(_PR_HAVE_LARGE_OFF_T) + if (0x7fffffffL < sb->st_size) + { + PR_SetError(PR_FILE_TOO_BIG_ERROR, 0); + return -1; + } +#endif /* defined(_PR_HAVE_LARGE_OFF_T) */ + info->size = sb->st_size; + + _MD_set_fileinfo_times(sb, info); + return 0; +} /* _MD_convert_stat_to_fileinfo */ + +static int _MD_convert_stat64_to_fileinfo64( + const _MDStat64 *sb, + PRFileInfo64 *info) { - struct sigaction sigact; - int rv; + if (S_IFREG & sb->st_mode) + info->type = PR_FILE_FILE; + else if (S_IFDIR & sb->st_mode) + info->type = PR_FILE_DIRECTORY; + else + info->type = PR_FILE_OTHER; + + LL_I2L(info->size, sb->st_size); + + _MD_set_fileinfo64_times(sb, info); + return 0; +} /* _MD_convert_stat64_to_fileinfo64 */ - sigemptyset(&timer_set); +PRInt32 _MD_getfileinfo(const char *fn, PRFileInfo *info) +{ + PRInt32 rv; + struct stat sb; + + rv = stat(fn, &sb); + if (rv < 0) + _PR_MD_MAP_STAT_ERROR(_MD_ERRNO()); + else if (NULL != info) + rv = _MD_convert_stat_to_fileinfo(&sb, info); + return rv; +} + +PRInt32 _MD_getfileinfo64(const char *fn, PRFileInfo64 *info) +{ + _MDStat64 sb; + PRInt32 rv = _md_iovector._stat64(fn, &sb); + if (rv < 0) + _PR_MD_MAP_STAT_ERROR(_MD_ERRNO()); + else if (NULL != info) + rv = _MD_convert_stat64_to_fileinfo64(&sb, info); + return rv; +} + +PRInt32 _MD_getopenfileinfo(const PRFileDesc *fd, PRFileInfo *info) +{ + struct stat sb; + PRInt32 rv = fstat(fd->secret->md.osfd, &sb); + if (rv < 0) + _PR_MD_MAP_FSTAT_ERROR(_MD_ERRNO()); + else if (NULL != info) + rv = _MD_convert_stat_to_fileinfo(&sb, info); + return rv; +} + +PRInt32 _MD_getopenfileinfo64(const PRFileDesc *fd, PRFileInfo64 *info) +{ + _MDStat64 sb; + PRInt32 rv = _md_iovector._fstat64(fd->secret->md.osfd, &sb); + if (rv < 0) + _PR_MD_MAP_FSTAT_ERROR(_MD_ERRNO()); + else if (NULL != info) + rv = _MD_convert_stat64_to_fileinfo64(&sb, info); + return rv; +} + +struct _MD_IOVector _md_iovector; + +/* +** These implementations are to emulate large file routines on systems that +** don't have them. Their goal is to check in case overflow occurs. Otherwise +** they will just operate as normal using 32-bit file routines. +** +** The checking might be pre- or post-op, depending on the semantics. +*/ + +#if defined(SOLARIS2_5) + +static PRIntn _MD_solaris25_fstat64(PRIntn osfd, _MDStat64 *buf) +{ + PRInt32 rv; + struct stat sb; + + rv = fstat(osfd, &sb); + if (rv >= 0) + { + /* + ** I'm only copying the fields that are immediately needed. + ** If somebody else calls this function, some of the fields + ** may not be defined. + */ + (void)memset(buf, 0, sizeof(_MDStat64)); + buf->st_mode = sb.st_mode; + buf->st_ctim = sb.st_ctim; + buf->st_mtim = sb.st_mtim; + buf->st_size = sb.st_size; + } + return rv; +} /* _MD_solaris25_fstat64 */ + +static PRIntn _MD_solaris25_stat64(const char *fn, _MDStat64 *buf) +{ + PRInt32 rv; + struct stat sb; + + rv = stat(fn, &sb); + if (rv >= 0) + { + /* + ** I'm only copying the fields that are immediately needed. + ** If somebody else calls this function, some of the fields + ** may not be defined. + */ + (void)memset(buf, 0, sizeof(_MDStat64)); + buf->st_mode = sb.st_mode; + buf->st_ctim = sb.st_ctim; + buf->st_mtim = sb.st_mtim; + buf->st_size = sb.st_size; + } + return rv; +} /* _MD_solaris25_stat64 */ +#endif /* defined(SOLARIS2_5) */ + +#if defined(_PR_NO_LARGE_FILES) || defined(SOLARIS2_5) + +static PRIntn _MD_Unix_lockf64(PRIntn osfd, PRIntn function, PRInt64 size) +{ +#if defined(RHAPSODY) || defined(BSDI) + /* No lockf */ + PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); + return -1; +#else + PRInt64 desired, maxoff; + PRInt32 current = lseek(osfd, SEEK_CUR, 0); + + LL_I2L(maxoff, 0x7fffffff); + LL_I2L(desired, current); + LL_ADD(desired, desired, size); + if (LL_CMP(desired, <=, maxoff)) + { + off_t offset; + LL_L2I(offset, size); + return lockf(osfd, function, offset); + } + PR_SetError(PR_FILE_TOO_BIG_ERROR, 0); + return -1; +#endif +} /* _MD_Unix_lockf64 */ + +static PRInt64 _MD_Unix_lseek64(PRIntn osfd, PRInt64 offset, PRIntn whence) +{ + PRUint64 maxoff; + PRInt64 rv = minus_one; + LL_I2L(maxoff, 0x7fffffff); + if (LL_CMP(offset, <=, maxoff)) + { + off_t off; + LL_L2I(off, offset); + LL_I2L(rv, lseek(osfd, off, whence)); + } + else errno = EFBIG; /* we can't go there */ + return rv; +} /* _MD_Unix_lseek64 */ + +static void* _MD_Unix_mmap64( + void *addr, PRSize len, PRIntn prot, PRIntn flags, + PRIntn fildes, PRInt64 offset) +{ + PR_SetError(PR_FILE_TOO_BIG_ERROR, 0); + return NULL; +} /* _MD_Unix_mmap64 */ +#endif /* defined(_PR_NO_LARGE_FILES) || defined(SOLARIS2_5) */ + +#if defined(IRIX) + +/* +** This function emulates a lock64 for IRIX using fcntl calls. It is a true +** 64-bit operation, just a different system API to get it. +*/ +static PRIntn _MD_irix_lockf64(PRIntn osfd, PRIntn function, PRInt64 size) +{ +#if 1 + PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); + PR_NOT_REACHED("NOT IMPLEMENTED"); + return -1; +#else + flock64_t lock; + /* $$$ have no idea what I'm doing $$$ */ + lock.l_type = function; + lock.l_whence = SEEK_CUR; + lock.l_start = 0; + lock.l_len = size; + + return fcntl(osfd, F_SETLKW64, &lock); +#endif +} /* _MD_irix_lockf64 */ + +#endif /* defined(IRIX) */ + +static void _PR_InitIOV(void) +{ +#if defined(SOLARIS2_5) + PRLibrary *lib; + void *open64_func; + + open64_func = PR_FindSymbolAndLibrary("open64", &lib); + if (NULL != open64_func) + { + PR_ASSERT(NULL != lib); + _md_iovector._open64 = (_MD_Open64)open64_func; + _md_iovector._mmap64 = (_MD_Mmap64)PR_FindSymbol(lib, "mmap64"); + _md_iovector._fstat64 = (_MD_Fstat64)PR_FindSymbol(lib, "fstat64"); + _md_iovector._stat64 = (_MD_Stat64)PR_FindSymbol(lib, "stat64"); + _md_iovector._lockf64 = (_MD_Lockf64)PR_FindSymbol(lib, "lockf64"); + _md_iovector._lseek64 = (_MD_Lseek64)PR_FindSymbol(lib, "lseek64"); + (void)PR_UnloadLibrary(lib); + } + else + { + _md_iovector._open64 = open; + _md_iovector._mmap64 = _MD_Unix_mmap64; + _md_iovector._fstat64 = _MD_solaris25_fstat64; + _md_iovector._stat64 = _MD_solaris25_stat64; + _md_iovector._lockf64 = _MD_Unix_lockf64; + _md_iovector._lseek64 = _MD_Unix_lseek64; + } +#elif defined(_PR_NO_LARGE_FILES) + _md_iovector._open64 = open; + _md_iovector._mmap64 = _MD_Unix_mmap64; + _md_iovector._fstat64 = fstat; + _md_iovector._stat64 = stat; + _md_iovector._lockf64 = _MD_Unix_lockf64; + _md_iovector._lseek64 = _MD_Unix_lseek64; +#elif defined(_PR_HAVE_OFF64_T) + _md_iovector._open64 = open64; + _md_iovector._mmap64 = mmap64; + _md_iovector._fstat64 = fstat64; + _md_iovector._stat64 = stat64; + +/* +** $$$ IRIX does not have a lockf64. One must fabricate it from fcntl +** calls with 64 bit arguments. +*/ +#if defined(IRIX) + _md_iovector._lockf64 = _MD_irix_lockf64; +#else + _md_iovector._lockf64 = lockf64; +#endif + _md_iovector._lseek64 = lseek64; +#elif defined(_PR_HAVE_LARGE_OFF_T) + _md_iovector._open64 = open; + _md_iovector._mmap64 = mmap; + _md_iovector._fstat64 = fstat; + _md_iovector._stat64 = stat; + _md_iovector._lockf64 = lockf; + _md_iovector._lseek64 = lseek; +#else +#error "I don't know yet" +#endif + LL_I2L(minus_one, -1); +} /* _PR_InitIOV */ + +void _PR_UnixInit(void) +{ + struct sigaction sigact; + int rv; + + sigemptyset(&timer_set); #if !defined(_PR_PTHREADS) - sigaddset(&timer_set, SIGALRM); - sigemptyset(&empty_set); - intr_timeout_ticks = - PR_SecondsToInterval(_PR_INTERRUPT_CHECK_INTERVAL_SECS); + sigaddset(&timer_set, SIGALRM); + sigemptyset(&empty_set); + intr_timeout_ticks = + PR_SecondsToInterval(_PR_INTERRUPT_CHECK_INTERVAL_SECS); #if defined(SOLARIS) || defined(IRIX) if (getenv("NSPR_SIGSEGV_HANDLE")) { - sigact.sa_handler = sigsegvhandler; - sigact.sa_flags = 0; - sigact.sa_mask = timer_set; - sigaction(SIGSEGV, &sigact, 0); - } + sigact.sa_handler = sigsegvhandler; + sigact.sa_flags = 0; + sigact.sa_mask = timer_set; + sigaction(SIGSEGV, &sigact, 0); + } if (getenv("NSPR_SIGABRT_HANDLE")) { - sigact.sa_handler = sigaborthandler; - sigact.sa_flags = 0; - sigact.sa_mask = timer_set; - sigaction(SIGABRT, &sigact, 0); - } + sigact.sa_handler = sigaborthandler; + sigact.sa_flags = 0; + sigact.sa_mask = timer_set; + sigaction(SIGABRT, &sigact, 0); + } if (getenv("NSPR_SIGBUS_HANDLE")) { - sigact.sa_handler = sigbushandler; - sigact.sa_flags = 0; - sigact.sa_mask = timer_set; - sigaction(SIGBUS, &sigact, 0); - } + sigact.sa_handler = sigbushandler; + sigact.sa_flags = 0; + sigact.sa_mask = timer_set; + sigaction(SIGBUS, &sigact, 0); + } #endif #endif /* !defined(_PR_PTHREADS) */ @@ -2743,18 +2713,19 @@ void _PR_UnixInit() PR_ASSERT(0 == rv); } #else - sigact.sa_handler = SIG_IGN; - sigemptyset(&sigact.sa_mask); - sigact.sa_flags = 0; - rv = sigaction(SIGPIPE, &sigact, 0); - PR_ASSERT(0 == rv); + sigact.sa_handler = SIG_IGN; + sigemptyset(&sigact.sa_mask); + sigact.sa_flags = 0; + rv = sigaction(SIGPIPE, &sigact, 0); + PR_ASSERT(0 == rv); #endif /* HPUX && _PR_DCETHREADS */ - _pr_rename_lock = PR_NewLock(); - PR_ASSERT(NULL != _pr_rename_lock); - _pr_Xfe_mon = PR_NewMonitor(); - PR_ASSERT(NULL != _pr_Xfe_mon); + _pr_rename_lock = PR_NewLock(); + PR_ASSERT(NULL != _pr_rename_lock); + _pr_Xfe_mon = PR_NewMonitor(); + PR_ASSERT(NULL != _pr_Xfe_mon); + _PR_InitIOV(); /* one last hack */ } /* @@ -2764,77 +2735,75 @@ void _PR_UnixInit() * called by _PR_InitSegs(), which in turn is called by * PR_Init(). */ -void _MD_InitSegs() +void _MD_InitSegs(void) { #ifdef DEBUG - /* + /* ** Disable using mmap(2) if NSPR_NO_MMAP is set */ - if (getenv("NSPR_NO_MMAP")) { - _pr_zero_fd = -2; - return; - } + if (getenv("NSPR_NO_MMAP")) { + _pr_zero_fd = -2; + return; + } #endif - _pr_zero_fd = open("/dev/zero",O_RDWR , 0); - _pr_md_lock = PR_NewLock(); + _pr_zero_fd = open("/dev/zero",O_RDWR , 0); + _pr_md_lock = PR_NewLock(); } PRStatus _MD_AllocSegment(PRSegment *seg, PRUint32 size, void *vaddr) { - static char *lastaddr = (char*) _PR_STACK_VMBASE; - PRStatus retval = PR_SUCCESS; - int prot; - void *rv; + static char *lastaddr = (char*) _PR_STACK_VMBASE; + PRStatus retval = PR_SUCCESS; + int prot; + void *rv; - PR_ASSERT(seg != 0); - PR_ASSERT(size != 0); + PR_ASSERT(seg != 0); + PR_ASSERT(size != 0); - PR_Lock(_pr_md_lock); - if (_pr_zero_fd < 0) { + PR_Lock(_pr_md_lock); + if (_pr_zero_fd < 0) { from_heap: - seg->vaddr = PR_MALLOC(size); - if (!seg->vaddr) { - retval = PR_FAILURE; - } - else { - seg->size = size; - seg->access = PR_SEGMENT_RDWR; - } - goto exit; - } + seg->vaddr = PR_MALLOC(size); + if (!seg->vaddr) { + retval = PR_FAILURE; + } + else { + seg->size = size; + } + goto exit; + } - prot = PROT_READ|PROT_WRITE; - /* - * On Alpha Linux, the user-level thread stack needs - * to be made executable because longjmp/signal seem - * to put machine instructions on the stack. - */ + prot = PROT_READ|PROT_WRITE; + /* + * On Alpha Linux, the user-level thread stack needs + * to be made executable because longjmp/signal seem + * to put machine instructions on the stack. + */ #if defined(LINUX) && defined(__alpha) - prot |= PROT_EXEC; + prot |= PROT_EXEC; #endif - rv = mmap((vaddr != 0) ? vaddr : lastaddr, size, prot, - _MD_MMAP_FLAGS, - _pr_zero_fd, 0); - if (rv == (void*)-1) { - goto from_heap; - } - lastaddr += size; - seg->vaddr = rv; - seg->size = size; - seg->access = PR_SEGMENT_RDWR; - seg->flags = _PR_SEG_VM; + rv = mmap((vaddr != 0) ? vaddr : lastaddr, size, prot, + _MD_MMAP_FLAGS, + _pr_zero_fd, 0); + if (rv == (void*)-1) { + goto from_heap; + } + lastaddr += size; + seg->vaddr = rv; + seg->size = size; + seg->flags = _PR_SEG_VM; exit: - PR_Unlock(_pr_md_lock); - return retval; + PR_Unlock(_pr_md_lock); + return retval; } void _MD_FreeSegment(PRSegment *seg) { - if (seg->flags & _PR_SEG_VM) - (void) munmap(seg->vaddr, seg->size); - else - PR_DELETE(seg->vaddr); + if (seg->flags & _PR_SEG_VM) + (void) munmap(seg->vaddr, seg->size); + else + PR_DELETE(seg->vaddr); } /* @@ -2854,159 +2823,159 @@ void _MD_FreeSegment(PRSegment *seg) PR_IMPLEMENT(PRTime) PR_Now(void) { - struct timeval tv; - PRInt64 s, us, s2us; + struct timeval tv; + PRInt64 s, us, s2us; - GETTIMEOFDAY(&tv); - LL_I2L(s2us, PR_USEC_PER_SEC); - LL_I2L(s, tv.tv_sec); - LL_I2L(us, tv.tv_usec); - LL_MUL(s, s, s2us); - LL_ADD(s, s, us); - return s; + GETTIMEOFDAY(&tv); + LL_I2L(s2us, PR_USEC_PER_SEC); + LL_I2L(s, tv.tv_sec); + LL_I2L(us, tv.tv_usec); + LL_MUL(s, s, s2us); + LL_ADD(s, s, us); + return s; } PRIntervalTime _PR_UNIX_GetInterval() { - struct timeval time; - PRIntervalTime ticks; + struct timeval time; + PRIntervalTime ticks; - (void)GETTIMEOFDAY(&time); /* fallicy of course */ - ticks = (PRUint32)time.tv_sec * PR_MSEC_PER_SEC; /* that's in milliseconds */ - ticks += (PRUint32)time.tv_usec / PR_USEC_PER_MSEC; /* so's that */ - return ticks; + (void)GETTIMEOFDAY(&time); /* fallicy of course */ + ticks = (PRUint32)time.tv_sec * PR_MSEC_PER_SEC; /* that's in milliseconds */ + ticks += (PRUint32)time.tv_usec / PR_USEC_PER_MSEC; /* so's that */ + return ticks; } /* _PR_SUNOS_GetInterval */ PRIntervalTime _PR_UNIX_TicksPerSecond() { - return 1000; /* this needs some work :) */ + return 1000; /* this needs some work :) */ } /* * _PR_UnixTransmitFile * - * Send file fd across socket sd. If headers is non-NULL, 'hlen' - * bytes of headers is sent before sending the file. + * 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 + * PR_TRANSMITFILE_CLOSE_SOCKET flag - close socket after sending file + * + * return number of bytes sent or -1 on error * */ -#define TRANSMITFILE_MMAP_CHUNK (256 * 1024) +#define TRANSMITFILE_MMAP_CHUNK (256 * 1024) PR_IMPLEMENT(PRInt32) _PR_UnixTransmitFile(PRFileDesc *sd, PRFileDesc *fd, const void *headers, PRInt32 hlen, PRTransmitFileFlags flags, PRIntervalTime timeout) { - PRInt32 rv, count = 0; - PRInt32 len, index = 0; - struct stat statbuf; - struct PRIOVec iov[2]; - void *addr; - PRInt32 err; + PRInt32 rv, count = 0; + PRInt32 len, index = 0; + struct stat statbuf; + struct PRIOVec iov[2]; + void *addr; + PRInt32 err; - /* Get file size */ - if (fstat(fd->secret->md.osfd, &statbuf) == -1) { + /* Get file size */ + if (fstat(fd->secret->md.osfd, &statbuf) == -1) { err = _MD_ERRNO(); - switch (err) { - case EBADF: - PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); - break; - case EFAULT: - PR_SetError(PR_ACCESS_FAULT_ERROR, err); - break; - case EINTR: - PR_SetError(PR_PENDING_INTERRUPT_ERROR, err); - break; - case ETIMEDOUT: + switch (err) { + case EBADF: + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); + break; + case EFAULT: + PR_SetError(PR_ACCESS_FAULT_ERROR, err); + break; + case EINTR: + PR_SetError(PR_PENDING_INTERRUPT_ERROR, err); + break; + case ETIMEDOUT: #ifdef ENOLINK - case ENOLINK: + case ENOLINK: #endif - PR_SetError(PR_REMOTE_FILE_ERROR, err); - break; - default: - PR_SetError(PR_UNKNOWN_ERROR, err); - break; - } - count = -1; - goto done; - } - /* - * If the file is large, mmap and send the file in chunks so as - * to not consume too much virtual address space - */ - len = statbuf.st_size < TRANSMITFILE_MMAP_CHUNK ? statbuf.st_size : - TRANSMITFILE_MMAP_CHUNK; - /* - * Map in (part of) file. Take care of zero-length files. - */ - if (len) { - addr = mmap((caddr_t) 0, len, PROT_READ, MAP_PRIVATE, - fd->secret->md.osfd, 0); - - if (addr == (void*)-1) { - _PR_MD_MAP_MMAP_ERROR(_MD_ERRNO()); - count = -1; - goto done; - } - } - /* - * send headers, first, followed by the file - */ - if (hlen) { - iov[index].iov_base = (char *) headers; - iov[index].iov_len = hlen; - index++; - } - iov[index].iov_base = (char*)addr; - iov[index].iov_len = len; - index++; - rv = PR_Writev(sd, iov, index, timeout); - if (len) - munmap(addr,len); - if (rv >= 0) { - PR_ASSERT(rv == hlen + len); - statbuf.st_size -= len; - count += rv; - } else { - count = -1; - goto done; - } - /* - * send remaining bytes of the file, if any - */ - len = statbuf.st_size < TRANSMITFILE_MMAP_CHUNK ? statbuf.st_size : - TRANSMITFILE_MMAP_CHUNK; - while (len > 0) { - /* - * Map in (part of) file - */ - PR_ASSERT((count - hlen) % TRANSMITFILE_MMAP_CHUNK == 0); - addr = mmap((caddr_t) 0, len, PROT_READ, MAP_PRIVATE, - fd->secret->md.osfd, count - hlen); - - if (addr == (void*)-1) { - _PR_MD_MAP_MMAP_ERROR(_MD_ERRNO()); - count = -1; - goto done; - } - rv = PR_Send(sd, addr, len, 0, timeout); - munmap(addr,len); - if (rv >= 0) { - PR_ASSERT(rv == len); - statbuf.st_size -= rv; - count += rv; - len = statbuf.st_size < TRANSMITFILE_MMAP_CHUNK ? - statbuf.st_size : TRANSMITFILE_MMAP_CHUNK; - } else { - count = -1; - goto done; - } - } + PR_SetError(PR_REMOTE_FILE_ERROR, err); + break; + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } + count = -1; + goto done; + } + /* + * If the file is large, mmap and send the file in chunks so as + * to not consume too much virtual address space + */ + len = statbuf.st_size < TRANSMITFILE_MMAP_CHUNK ? statbuf.st_size : + TRANSMITFILE_MMAP_CHUNK; + /* + * Map in (part of) file. Take care of zero-length files. + */ + if (len) { + addr = mmap((caddr_t) 0, len, PROT_READ, MAP_PRIVATE, + fd->secret->md.osfd, 0); + + if (addr == (void*)-1) { + _PR_MD_MAP_MMAP_ERROR(_MD_ERRNO()); + count = -1; + goto done; + } + } + /* + * send headers, first, followed by the file + */ + if (hlen) { + iov[index].iov_base = (char *) headers; + iov[index].iov_len = hlen; + index++; + } + iov[index].iov_base = (char*)addr; + iov[index].iov_len = len; + index++; + rv = PR_Writev(sd, iov, index, timeout); + if (len) + munmap(addr,len); + if (rv >= 0) { + PR_ASSERT(rv == hlen + len); + statbuf.st_size -= len; + count += rv; + } else { + count = -1; + goto done; + } + /* + * send remaining bytes of the file, if any + */ + len = statbuf.st_size < TRANSMITFILE_MMAP_CHUNK ? statbuf.st_size : + TRANSMITFILE_MMAP_CHUNK; + while (len > 0) { + /* + * Map in (part of) file + */ + PR_ASSERT((count - hlen) % TRANSMITFILE_MMAP_CHUNK == 0); + addr = mmap((caddr_t) 0, len, PROT_READ, MAP_PRIVATE, + fd->secret->md.osfd, count - hlen); + + if (addr == (void*)-1) { + _PR_MD_MAP_MMAP_ERROR(_MD_ERRNO()); + count = -1; + goto done; + } + rv = PR_Send(sd, addr, len, 0, timeout); + munmap(addr,len); + if (rv >= 0) { + PR_ASSERT(rv == len); + statbuf.st_size -= rv; + count += rv; + len = statbuf.st_size < TRANSMITFILE_MMAP_CHUNK ? + statbuf.st_size : TRANSMITFILE_MMAP_CHUNK; + } else { + count = -1; + goto done; + } + } done: - if ((count >= 0) && (flags & PR_TRANSMITFILE_CLOSE_SOCKET)) - PR_Close(sd); - return count; + if ((count >= 0) && (flags & PR_TRANSMITFILE_CLOSE_SOCKET)) + PR_Close(sd); + return count; } #if defined(HPUX11) && !defined(_PR_PTHREADS) @@ -3014,12 +2983,12 @@ done: /* * _PR_HPUXTransmitFile * - * Send file fd across socket sd. If headers is non-NULL, 'hlen' - * bytes of headers is sent before sending the file. + * 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 + * 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 HP-UX B.11.00. @@ -3079,7 +3048,7 @@ _PR_HPUXTransmitFile(PRFileDesc *sd, PRFileDesc *fd, } continue; /* retry */ } - if (err != EAGAIN && err != EWOULDBLOCK) { + if (err != EAGAIN && err != EWOULDBLOCK) { _MD_hpux_map_sendfile_error(err); return -1; } @@ -3094,20 +3063,9 @@ _PR_HPUXTransmitFile(PRFileDesc *sd, PRFileDesc *fd, * the next sendfile() call will return EWOULDBLOCK. */ if (!_PR_IS_NATIVE_THREAD(me)) { - if (_PR_WaitForFD(sd->secret->md.osfd, - PR_POLL_WRITE, timeout) == 0) { - if (_PR_PENDING_INTERRUPT(me)) { - me->flags &= ~_PR_INTERRUPT; - PR_SetError( PR_PENDING_INTERRUPT_ERROR, 0); - } else { - PR_SetError(PR_IO_TIMEOUT_ERROR, 0); - } + if ((rv = local_io_wait(sd->secret->md.osfd, + _PR_UNIX_POLL_WRITE, timeout)) < 0) return -1; - } else if (_PR_PENDING_INTERRUPT(me)) { - me->flags &= ~_PR_INTERRUPT; - PR_SetError( PR_PENDING_INTERRUPT_ERROR, 0); - return -1; - } } else { if (socket_io_wait(sd->secret->md.osfd, WRITE_FD, timeout)< 0) { return -1; @@ -3142,71 +3100,72 @@ _PR_HPUXTransmitFile(PRFileDesc *sd, PRFileDesc *fd, #if !defined(_PR_PTHREADS) /* -** Wait for I/O on a single descriptor. + * Wait for I/O on multiple descriptors. * - * return 0, if timed-out or interrupted, else return 1 -*/ -PRInt32 _PR_WaitForFD(PRInt32 osfd, PRUintn how, PRIntervalTime timeout) + * Return 0 if timed out, return -1 if interrupted, + * else return the number of ready descriptors. + */ +PRInt32 _PR_WaitForMultipleFDs( + _PRUnixPollDesc *unixpds, + PRInt32 pdcnt, + PRIntervalTime timeout) { - _PRUnixPollDesc pd; PRPollQueue pq; PRIntn is; - PRInt32 rv = 1; - _PRCPU *io_cpu; + PRInt32 rv; + _PRCPU *io_cpu; + _PRUnixPollDesc *unixpd, *eunixpd; PRThread *me = _PR_MD_CURRENT_THREAD(); PR_ASSERT(!(me->flags & _PR_IDLE_THREAD)); - PR_LOG(_pr_io_lm, PR_LOG_MIN, - ("waiting to %s on osfd=%d", - (how == PR_POLL_READ) ? "read" : "write", - osfd)); - if (timeout == PR_INTERVAL_NO_WAIT) return 0; - - pd.osfd = osfd; - pd.in_flags = how; - pd.out_flags = 0; + if (_PR_PENDING_INTERRUPT(me)) { + me->flags &= ~_PR_INTERRUPT; + PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); + return -1; + } - pq.pds = &pd; - pq.npds = 1; + pq.pds = unixpds; + pq.npds = pdcnt; _PR_INTSOFF(is); _PR_MD_IOQ_LOCK(); _PR_THREAD_LOCK(me); - if (_PR_PENDING_INTERRUPT(me)) { - _PR_THREAD_UNLOCK(me); - _PR_MD_IOQ_UNLOCK(); - _PR_FAST_INTSON(is); - return 0; - } - pq.thr = me; - io_cpu = me->cpu; + io_cpu = me->cpu; pq.on_ioq = PR_TRUE; pq.timeout = timeout; _PR_ADD_TO_IOQ(pq, me->cpu); -#ifndef _PR_USE_POLL - if (how == PR_POLL_READ) { - FD_SET(osfd, &_PR_FD_READ_SET(me->cpu)); - (_PR_FD_READ_CNT(me->cpu))[osfd]++; - } else if (how == PR_POLL_WRITE) { - FD_SET(osfd, &_PR_FD_WRITE_SET(me->cpu)); - (_PR_FD_WRITE_CNT(me->cpu))[osfd]++; - } else { - FD_SET(osfd, &_PR_FD_EXCEPTION_SET(me->cpu)); - (_PR_FD_EXCEPTION_CNT(me->cpu))[osfd]++; - } -#endif /* _PR_USE_POLL */ +#if !defined(_PR_USE_POLL) + eunixpd = unixpds + pdcnt; + for (unixpd = unixpds; unixpd < eunixpd; unixpd++) { + PRInt32 osfd = unixpd->osfd; + if (unixpd->in_flags & _PR_UNIX_POLL_READ) { + FD_SET(osfd, &_PR_FD_READ_SET(me->cpu)); + _PR_FD_READ_CNT(me->cpu)[osfd]++; + } + if (unixpd->in_flags & _PR_UNIX_POLL_WRITE) { + FD_SET(osfd, &_PR_FD_WRITE_SET(me->cpu)); + (_PR_FD_WRITE_CNT(me->cpu))[osfd]++; + } + if (unixpd->in_flags & _PR_UNIX_POLL_EXCEPT) { + FD_SET(osfd, &_PR_FD_EXCEPTION_SET(me->cpu)); + (_PR_FD_EXCEPTION_CNT(me->cpu))[osfd]++; + } + if (osfd > _PR_IOQ_MAX_OSFD(me->cpu)) { + _PR_IOQ_MAX_OSFD(me->cpu) = osfd; + } + } +#endif /* !defined(_PR_USE_POLL) */ - if (_PR_IOQ_MAX_OSFD(me->cpu) < osfd) - _PR_IOQ_MAX_OSFD(me->cpu) = osfd; - if (_PR_IOQ_TIMEOUT(me->cpu) > timeout) - _PR_IOQ_TIMEOUT(me->cpu) = timeout; + if (_PR_IOQ_TIMEOUT(me->cpu) > timeout) { + _PR_IOQ_TIMEOUT(me->cpu) = timeout; + } - _PR_IOQ_OSFD_CNT(me->cpu) += 1; - + _PR_IOQ_OSFD_CNT(me->cpu) += pdcnt; + _PR_SLEEPQ_LOCK(me->cpu); _PR_ADD_SLEEPQ(me, timeout); me->state = _PR_IO_WAIT; @@ -3217,53 +3176,84 @@ PRInt32 _PR_WaitForFD(PRInt32 osfd, PRUintn how, PRIntervalTime timeout) _PR_MD_IOQ_UNLOCK(); _PR_MD_WAIT(me, timeout); + me->io_pending = PR_FALSE; me->io_suspended = PR_FALSE; - /* - * This thread should run on the same cpu on which it was blocked; when - * the IO request times out the fd sets and fd counts for the - * cpu are updated below. - */ - PR_ASSERT(me->cpu == io_cpu); + /* + * This thread should run on the same cpu on which it was blocked; when + * the IO request times out the fd sets and fd counts for the + * cpu are updated below. + */ + PR_ASSERT(me->cpu == io_cpu); /* ** If we timed out the pollq might still be on the ioq. Remove it ** before continuing. */ if (pq.on_ioq) { - _PR_MD_IOQ_LOCK(); - /* - * Need to check pq.on_ioq again - */ + _PR_MD_IOQ_LOCK(); + /* + * Need to check pq.on_ioq again + */ if (pq.on_ioq) { - PR_REMOVE_LINK(&pq.links); + PR_REMOVE_LINK(&pq.links); #ifndef _PR_USE_POLL - if (how == PR_POLL_READ) { - if ((--(_PR_FD_READ_CNT(me->cpu))[osfd]) == 0) - FD_CLR(osfd, &_PR_FD_READ_SET(me->cpu)); - - } else if (how == PR_POLL_WRITE) { - if ((--(_PR_FD_WRITE_CNT(me->cpu))[osfd]) == 0) - FD_CLR(osfd, &_PR_FD_WRITE_SET(me->cpu)); - } else { - if ((--(_PR_FD_EXCEPTION_CNT(me->cpu))[osfd]) == 0) - FD_CLR(osfd, &_PR_FD_EXCEPTION_SET(me->cpu)); - } -#endif /* _PR_USE_POLL */ - PR_ASSERT(pq.npds == 1); - _PR_IOQ_OSFD_CNT(me->cpu) -= 1; + eunixpd = unixpds + pdcnt; + for (unixpd = unixpds; unixpd < eunixpd; unixpd++) { + PRInt32 osfd = unixpd->osfd; + PRInt16 in_flags = unixpd->in_flags; + + if (in_flags & _PR_UNIX_POLL_READ) { + if (--(_PR_FD_READ_CNT(me->cpu))[osfd] == 0) + FD_CLR(osfd, &_PR_FD_READ_SET(me->cpu)); + } + if (in_flags & _PR_UNIX_POLL_WRITE) { + if (--(_PR_FD_WRITE_CNT(me->cpu))[osfd] == 0) + FD_CLR(osfd, &_PR_FD_WRITE_SET(me->cpu)); + } + if (in_flags & _PR_UNIX_POLL_EXCEPT) { + if (--(_PR_FD_EXCEPTION_CNT(me->cpu))[osfd] == 0) + FD_CLR(osfd, &_PR_FD_EXCEPTION_SET(me->cpu)); + } + } +#endif /* _PR_USE_POLL */ + PR_ASSERT(pq.npds == pdcnt); + _PR_IOQ_OSFD_CNT(me->cpu) -= pdcnt; + PR_ASSERT(_PR_IOQ_OSFD_CNT(me->cpu) >= 0); } - _PR_MD_IOQ_UNLOCK(); - rv = 0; + _PR_MD_IOQ_UNLOCK(); } - _PR_FAST_INTSON(is); - return(rv); + /* XXX Should we use _PR_FAST_INTSON or _PR_INTSON? */ + if (1 == pdcnt) { + _PR_FAST_INTSON(is); + } else { + _PR_INTSON(is); + } + + if (_PR_PENDING_INTERRUPT(me)) { + me->flags &= ~_PR_INTERRUPT; + PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); + return -1; + } + + rv = 0; + if (pq.on_ioq == PR_FALSE) { + /* Count the number of ready descriptors */ + while (--pdcnt >= 0) { + if (unixpds->out_flags != 0) { + rv++; + } + unixpds++; + } + } + + return rv; } /* * Unblock threads waiting for I/O - * used when interrupting threads + * used when interrupting threads * * NOTE: The thread lock should held when this function is called. * On return, the thread lock is released. @@ -3273,9 +3263,9 @@ void _PR_Unblock_IO_Wait(PRThread *thr) int pri = thr->priority; _PRCPU *cpu = thr->cpu; - /* - * GLOBAL threads wakeup periodically to check for interrupt - */ + /* + * GLOBAL threads wakeup periodically to check for interrupt + */ if (_PR_IS_NATIVE_THREAD(thr)) { _PR_THREAD_UNLOCK(thr); return; @@ -3338,34 +3328,34 @@ int _MD_unix_get_nonblocking_connect_error(int osfd) ** in a pre-emptive threaded environment, we need to use a lock. */ -void PR_XLock() +void PR_XLock(void) { - PR_EnterMonitor(_pr_Xfe_mon); + PR_EnterMonitor(_pr_Xfe_mon); } -void PR_XUnlock() +void PR_XUnlock(void) { - PR_ExitMonitor(_pr_Xfe_mon); + PR_ExitMonitor(_pr_Xfe_mon); } -PRBool PR_XIsLocked() +PRBool PR_XIsLocked(void) { - return (PR_InMonitor(_pr_Xfe_mon)) ? PR_TRUE : PR_FALSE; + return (PR_InMonitor(_pr_Xfe_mon)) ? PR_TRUE : PR_FALSE; } void PR_XWait(int ms) { - PR_Wait(_pr_Xfe_mon, PR_MillisecondsToInterval(ms)); + PR_Wait(_pr_Xfe_mon, PR_MillisecondsToInterval(ms)); } void PR_XNotify(void) { - PR_Notify(_pr_Xfe_mon); + PR_Notify(_pr_Xfe_mon); } void PR_XNotifyAll(void) { - PR_NotifyAll(_pr_Xfe_mon); + PR_NotifyAll(_pr_Xfe_mon); } #ifdef HAVE_BSD_FLOCK @@ -3375,68 +3365,68 @@ void PR_XNotifyAll(void) PR_IMPLEMENT(PRStatus) _MD_LockFile(PRInt32 f) { - PRInt32 rv; - rv = flock(f, LOCK_EX); - if (rv == 0) - return PR_SUCCESS; - _PR_MD_MAP_FLOCK_ERROR(_MD_ERRNO()); - return PR_FAILURE; + PRInt32 rv; + rv = flock(f, LOCK_EX); + if (rv == 0) + return PR_SUCCESS; + _PR_MD_MAP_FLOCK_ERROR(_MD_ERRNO()); + return PR_FAILURE; } PR_IMPLEMENT(PRStatus) _MD_TLockFile(PRInt32 f) { - PRInt32 rv; - rv = flock(f, LOCK_EX|LOCK_NB); - if (rv == 0) - return PR_SUCCESS; - _PR_MD_MAP_FLOCK_ERROR(_MD_ERRNO()); - return PR_FAILURE; + PRInt32 rv; + rv = flock(f, LOCK_EX|LOCK_NB); + if (rv == 0) + return PR_SUCCESS; + _PR_MD_MAP_FLOCK_ERROR(_MD_ERRNO()); + return PR_FAILURE; } PR_IMPLEMENT(PRStatus) _MD_UnlockFile(PRInt32 f) { - PRInt32 rv; - rv = flock(f, LOCK_UN); - if (rv == 0) - return PR_SUCCESS; - _PR_MD_MAP_FLOCK_ERROR(_MD_ERRNO()); - return PR_FAILURE; + PRInt32 rv; + rv = flock(f, LOCK_UN); + if (rv == 0) + return PR_SUCCESS; + _PR_MD_MAP_FLOCK_ERROR(_MD_ERRNO()); + return PR_FAILURE; } #else PR_IMPLEMENT(PRStatus) _MD_LockFile(PRInt32 f) { - PRInt32 rv; - rv = lockf(f, F_LOCK, 0); - if (rv == 0) - return PR_SUCCESS; - _PR_MD_MAP_LOCKF_ERROR(_MD_ERRNO()); - return PR_FAILURE; + PRInt32 rv; + rv = lockf(f, F_LOCK, 0); + if (rv == 0) + return PR_SUCCESS; + _PR_MD_MAP_LOCKF_ERROR(_MD_ERRNO()); + return PR_FAILURE; } PR_IMPLEMENT(PRStatus) _MD_TLockFile(PRInt32 f) { - PRInt32 rv; - rv = lockf(f, F_TLOCK, 0); - if (rv == 0) - return PR_SUCCESS; - _PR_MD_MAP_LOCKF_ERROR(_MD_ERRNO()); - return PR_FAILURE; + PRInt32 rv; + rv = lockf(f, F_TLOCK, 0); + if (rv == 0) + return PR_SUCCESS; + _PR_MD_MAP_LOCKF_ERROR(_MD_ERRNO()); + return PR_FAILURE; } PR_IMPLEMENT(PRStatus) _MD_UnlockFile(PRInt32 f) { - PRInt32 rv; - rv = lockf(f, F_ULOCK, 0); - if (rv == 0) - return PR_SUCCESS; - _PR_MD_MAP_LOCKF_ERROR(_MD_ERRNO()); - return PR_FAILURE; + PRInt32 rv; + rv = lockf(f, F_ULOCK, 0); + if (rv == 0) + return PR_SUCCESS; + _PR_MD_MAP_LOCKF_ERROR(_MD_ERRNO()); + return PR_FAILURE; } #endif @@ -3446,9 +3436,9 @@ PR_IMPLEMENT(PRStatus) _MD_gethostname(char *name, PRUint32 namelen) rv = gethostname(name, namelen); if (0 == rv) { - return PR_SUCCESS; + return PR_SUCCESS; } - _PR_MD_MAP_GETHOSTNAME_ERROR(_MD_ERRNO()); + _PR_MD_MAP_GETHOSTNAME_ERROR(_MD_ERRNO()); return PR_FAILURE; } @@ -3468,34 +3458,34 @@ PRStatus _MD_CreateFileMap(PRFileMap *fmap, PRInt64 size) LL_L2UI(sz, size); if (sz) { if (PR_GetOpenFileInfo(fmap->fd, &info) == PR_FAILURE) { - return PR_FAILURE; + return PR_FAILURE; } if (sz > info.size) { /* * Need to extend the file */ if (fmap->prot != PR_PROT_READWRITE) { - PR_SetError(PR_NO_ACCESS_RIGHTS_ERROR, 0); - return PR_FAILURE; + PR_SetError(PR_NO_ACCESS_RIGHTS_ERROR, 0); + return PR_FAILURE; } if (PR_Seek(fmap->fd, sz - 1, PR_SEEK_SET) == -1) { - return PR_FAILURE; + return PR_FAILURE; } if (PR_Write(fmap->fd, "", 1) != 1) { - return PR_FAILURE; + return PR_FAILURE; } - } + } } if (fmap->prot == PR_PROT_READONLY) { - fmap->md.prot = PROT_READ; - fmap->md.flags = 0; + fmap->md.prot = PROT_READ; + fmap->md.flags = MAP_PRIVATE; } else if (fmap->prot == PR_PROT_READWRITE) { - fmap->md.prot = PROT_READ | PROT_WRITE; - fmap->md.flags = MAP_SHARED; + fmap->md.prot = PROT_READ | PROT_WRITE; + fmap->md.flags = MAP_SHARED; } else { - PR_ASSERT(fmap->prot == PR_PROT_WRITECOPY); - fmap->md.prot = PROT_READ | PROT_WRITE; - fmap->md.flags = MAP_PRIVATE; + PR_ASSERT(fmap->prot == PR_PROT_WRITECOPY); + fmap->md.prot = PROT_READ | PROT_WRITE; + fmap->md.flags = MAP_PRIVATE; } return PR_SUCCESS; } @@ -3510,8 +3500,8 @@ void * _MD_MemMap( LL_L2I(off, offset); if ((addr = mmap(0, len, fmap->md.prot, fmap->md.flags, - fmap->fd->secret->md.osfd, off)) == (void *) -1) { - _PR_MD_MAP_MMAP_ERROR(_MD_ERRNO()); + fmap->fd->secret->md.osfd, off)) == (void *) -1) { + _PR_MD_MAP_MMAP_ERROR(_MD_ERRNO()); addr = NULL; } return addr; @@ -3522,11 +3512,11 @@ PRStatus _MD_MemUnmap(void *addr, PRUint32 len) if (munmap(addr, len) == 0) { return PR_SUCCESS; } else { - if (errno == EINVAL) { + if (errno == EINVAL) { PR_SetError(PR_INVALID_ARGUMENT_ERROR, errno); - } else { - PR_SetError(PR_UNKNOWN_ERROR, errno); - } + } else { + PR_SetError(PR_UNKNOWN_ERROR, errno); + } return PR_FAILURE; } } @@ -3544,8 +3534,6 @@ PRStatus _MD_CloseFileMap(PRFileMap *fmap) * that calls poll(), we emulate poll() using select(). */ -#include <fcntl.h> - int poll(struct pollfd *filedes, unsigned long nfds, int timeout) { int i; @@ -3555,15 +3543,15 @@ int poll(struct pollfd *filedes, unsigned long nfds, int timeout) struct timeval tv, *tvp; if (timeout < 0 && timeout != -1) { - errno = EINVAL; - return -1; + errno = EINVAL; + return -1; } if (timeout == -1) { tvp = NULL; } else { - tv.tv_sec = timeout / 1000; - tv.tv_usec = (timeout % 1000) * 1000; + tv.tv_sec = timeout / 1000; + tv.tv_usec = (timeout % 1000) * 1000; tvp = &tv; } @@ -3573,100 +3561,100 @@ int poll(struct pollfd *filedes, unsigned long nfds, int timeout) FD_ZERO(&ex); for (i = 0; i < nfds; i++) { - int osfd = filedes[i].fd; - int events = filedes[i].events; - PRBool fdHasEvent = PR_FALSE; + int osfd = filedes[i].fd; + int events = filedes[i].events; + PRBool fdHasEvent = PR_FALSE; - if (osfd < 0) { + if (osfd < 0) { continue; /* Skip this osfd. */ - } + } - /* - * Map the native poll flags to nspr poll flags. - * POLLIN, POLLRDNORM ===> PR_POLL_READ - * POLLOUT, POLLWRNORM ===> PR_POLL_WRITE - * POLLPRI, POLLRDBAND ===> PR_POLL_EXCEPTION - * POLLNORM, POLLWRBAND (and POLLMSG on some platforms) - * are ignored. - * - * The output events POLLERR and POLLHUP are never turned on. - * POLLNVAL may be turned on. - */ - - if (events & (POLLIN | POLLRDNORM)) { - FD_SET(osfd, &rd); - fdHasEvent = PR_TRUE; - } - if (events & (POLLOUT | POLLWRNORM)) { - FD_SET(osfd, &wr); - fdHasEvent = PR_TRUE; - } - if (events & (POLLPRI | POLLRDBAND)) { - FD_SET(osfd, &ex); - fdHasEvent = PR_TRUE; - } - if (fdHasEvent && osfd > maxfd) { - maxfd = osfd; - } + /* + * Map the poll events to the select fd_sets. + * POLLIN, POLLRDNORM ===> readable + * POLLOUT, POLLWRNORM ===> writable + * POLLPRI, POLLRDBAND ===> exception + * POLLNORM, POLLWRBAND (and POLLMSG on some platforms) + * are ignored. + * + * The output events POLLERR and POLLHUP are never turned on. + * POLLNVAL may be turned on. + */ + + if (events & (POLLIN | POLLRDNORM)) { + FD_SET(osfd, &rd); + fdHasEvent = PR_TRUE; + } + if (events & (POLLOUT | POLLWRNORM)) { + FD_SET(osfd, &wr); + fdHasEvent = PR_TRUE; + } + if (events & (POLLPRI | POLLRDBAND)) { + FD_SET(osfd, &ex); + fdHasEvent = PR_TRUE; + } + if (fdHasEvent && osfd > maxfd) { + maxfd = osfd; + } } rv = select(maxfd + 1, &rd, &wr, &ex, tvp); /* Compute poll results */ if (rv > 0) { - rv = 0; + rv = 0; for (i = 0; i < nfds; i++) { - PRBool fdHasEvent = PR_FALSE; + PRBool fdHasEvent = PR_FALSE; - filedes[i].revents = 0; + filedes[i].revents = 0; if (filedes[i].fd < 0) { continue; } - if (FD_ISSET(filedes[i].fd, &rd)) { - if (filedes[i].events & POLLIN) { - filedes[i].revents |= POLLIN; - } - if (filedes[i].events & POLLRDNORM) { - filedes[i].revents |= POLLRDNORM; - } - fdHasEvent = PR_TRUE; - } - if (FD_ISSET(filedes[i].fd, &wr)) { - if (filedes[i].events & POLLOUT) { - filedes[i].revents |= POLLOUT; - } - if (filedes[i].events & POLLWRNORM) { - filedes[i].revents |= POLLWRNORM; - } - fdHasEvent = PR_TRUE; - } - if (FD_ISSET(filedes[i].fd, &ex)) { - if (filedes[i].events & POLLPRI) { - filedes[i].revents |= POLLPRI; - } - if (filedes[i].events & POLLRDBAND) { - filedes[i].revents |= POLLRDBAND; - } - fdHasEvent = PR_TRUE; - } - if (fdHasEvent) { - rv++; + if (FD_ISSET(filedes[i].fd, &rd)) { + if (filedes[i].events & POLLIN) { + filedes[i].revents |= POLLIN; + } + if (filedes[i].events & POLLRDNORM) { + filedes[i].revents |= POLLRDNORM; + } + fdHasEvent = PR_TRUE; + } + if (FD_ISSET(filedes[i].fd, &wr)) { + if (filedes[i].events & POLLOUT) { + filedes[i].revents |= POLLOUT; + } + if (filedes[i].events & POLLWRNORM) { + filedes[i].revents |= POLLWRNORM; + } + fdHasEvent = PR_TRUE; + } + if (FD_ISSET(filedes[i].fd, &ex)) { + if (filedes[i].events & POLLPRI) { + filedes[i].revents |= POLLPRI; + } + if (filedes[i].events & POLLRDBAND) { + filedes[i].revents |= POLLRDBAND; + } + fdHasEvent = PR_TRUE; + } + if (fdHasEvent) { + rv++; } } - PR_ASSERT(rv > 0); + PR_ASSERT(rv > 0); } else if (rv == -1 && errno == EBADF) { - rv = 0; + rv = 0; for (i = 0; i < nfds; i++) { - filedes[i].revents = 0; + filedes[i].revents = 0; if (filedes[i].fd < 0) { continue; } - if (fcntl(filedes[i].fd, F_GETFL, 0) == -1) { - filedes[i].revents = POLLNVAL; - rv++; - } + if (fcntl(filedes[i].fd, F_GETFL, 0) == -1) { + filedes[i].revents = POLLNVAL; + rv++; + } } - PR_ASSERT(rv > 0); + PR_ASSERT(rv > 0); } PR_ASSERT(-1 != timeout || rv != 0); diff --git a/pr/src/md/unix/unix_errors.c b/pr/src/md/unix/unix_errors.c index 82d30428..e080138a 100644 --- a/pr/src/md/unix/unix_errors.c +++ b/pr/src/md/unix/unix_errors.c @@ -16,9 +16,10 @@ * Reserved. */ -#include "prtypes.h" -#include "md/_unix_errors.h" -#include "prerror.h" +#include "primpl.h" +#if defined(_PR_POLL_AVAILABLE) +#include <sys/poll.h> +#endif #include <errno.h> void _MD_unix_map_opendir_error(int err) @@ -77,14 +78,11 @@ void _MD_unix_readdir_error(int err) case EBADF: PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); break; -#ifdef IRIX -#ifdef IRIX5_3 -#else +#ifdef EDIRCORRUPTED case EDIRCORRUPTED: PR_SetError(PR_DIRECTORY_CORRUPTED_ERROR, err); break; #endif -#endif #ifdef EOVERFLOW case EOVERFLOW: PR_SetError(PR_IO_ERROR, err); @@ -655,6 +653,9 @@ void _MD_unix_map_close_error(int err) case EBADF: PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); break; + case EFBIG: + PR_SetError(PR_FILE_TOO_BIG_ERROR, err); + break; case EINTR: PR_SetError(PR_PENDING_INTERRUPT_ERROR, err); break; @@ -804,6 +805,9 @@ void _MD_unix_map_send_error(int err) case EINVAL: PR_SetError(PR_INVALID_ARGUMENT_ERROR, err); break; + case EIO: + PR_SetError(PR_IO_ERROR, err); + break; #if !defined(SCO) case ENOBUFS: PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, err); @@ -911,6 +915,9 @@ void _MD_unix_map_writev_error(int err) case EINTR: PR_SetError(PR_PENDING_INTERRUPT_ERROR, err); break; + case EIO: + PR_SetError(PR_IO_ERROR, err); + break; #ifdef ENOSR case ENOSR: PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, err); @@ -1382,20 +1389,31 @@ void _MD_unix_map_open_error(int err) void _MD_unix_map_mmap_error(int err) { - switch (err) { + case EACCES: + PR_SetError(PR_NO_ACCESS_RIGHTS_ERROR, err); + break; + case EAGAIN: + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, err); + break; case EBADF: PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); break; - case EAGAIN: + case EINVAL: + PR_SetError(PR_INVALID_ARGUMENT_ERROR, err); + break; + case EMFILE: PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, err); break; - case EACCES: - PR_SetError(PR_NO_ACCESS_RIGHTS_ERROR, err); + case ENODEV: + PR_SetError(PR_OPERATION_NOT_SUPPORTED_ERROR, err); break; case ENOMEM: PR_SetError(PR_OUT_OF_MEMORY_ERROR, err); break; + case ENXIO: + PR_SetError(PR_INVALID_ARGUMENT_ERROR, err); + break; default: PR_SetError(PR_UNKNOWN_ERROR, err); break; @@ -1432,6 +1450,7 @@ void _MD_unix_map_select_error(int err) } } +#ifdef _PR_POLL_AVAILABLE void _MD_unix_map_poll_error(int err) { PRErrorCode prerror; @@ -1452,6 +1471,21 @@ void _MD_unix_map_poll_error(int err) PR_SetError(prerror, err); } +void _MD_unix_map_poll_revents_error(int err) +{ + + if (err & POLLNVAL) + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, EBADF); + else if (err & POLLHUP) + PR_SetError(PR_CONNECT_RESET_ERROR, EPIPE); + else if (err & POLLERR) + PR_SetError(PR_IO_ERROR, EIO); + else + PR_SetError(PR_UNKNOWN_ERROR, err); +} +#endif /* _PR_POLL_AVAILABLE */ + + void _MD_unix_map_flock_error(int err) { switch (err) { diff --git a/pr/src/md/unix/unixware.c b/pr/src/md/unix/unixware.c index 4bc410bf..76c9c751 100644 --- a/pr/src/md/unix/unixware.c +++ b/pr/src/md/unix/unixware.c @@ -91,6 +91,14 @@ _MD_ATOMIC_INCREMENT(PRInt32 *val) } void +_MD_ATOMIC_ADD(PRInt32 *ptr, PRInt32 val) +{ + flockfile(_uw_semf); + (*ptr) += val; + unflockfile(_uw_semf); +} + +void _MD_ATOMIC_DECREMENT(PRInt32 *val) { flockfile(_uw_semf); @@ -194,6 +202,12 @@ _MD_ATOMIC_INCREMENT(PRInt32 *val) } void +_MD_ATOMIC_ADD(PRInt32 *ptr, PRInt32 val) +{ + TEST_THEN_ADD(ptr, val); +} + +void _MD_ATOMIC_DECREMENT(PRInt32 *val) { TEST_THEN_ADD(val, 0xffffffff); diff --git a/pr/src/md/unix/uxpoll.c b/pr/src/md/unix/uxpoll.c new file mode 100644 index 00000000..a4f6b6fc --- /dev/null +++ b/pr/src/md/unix/uxpoll.c @@ -0,0 +1,681 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "NPL"); you may not use this file except in + * compliance with the NPL. You may obtain a copy of the NPL at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the NPL is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL + * for the specific language governing rights and limitations under the + * NPL. + * + * The Initial Developer of this code under the NPL is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All Rights + * Reserved. + */ + +#if defined(_PR_PTHREADS) +#else /* defined(_PR_PTHREADS) */ + +#include "primpl.h" + +#include <sys/time.h> + +#include <fcntl.h> +#ifdef _PR_USE_POLL +#include <sys/poll.h> +#endif + +#if defined(_PR_USE_POLL) +static PRInt32 NativeThreadPoll( + PRPollDesc *pds, PRIntn npds, PRIntervalTime timeout) +{ + /* + * This function is mostly duplicated from ptio.s's PR_Poll(). + */ + PRInt32 ready = 0; + /* + * For restarting poll() if it is interrupted by a signal. + * We use these variables to figure out how much time has + * elapsed and how much of the timeout still remains. + */ + PRIntn index, msecs; + struct pollfd *syspoll = NULL; + PRIntervalTime start, elapsed, remaining; + + syspoll = (struct pollfd*)PR_MALLOC(npds * sizeof(struct pollfd)); + if (NULL == syspoll) + { + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + return -1; + } + for (index = 0; index < npds; ++index) + { + PRFileDesc *bottom; + PRInt16 in_flags_read = 0, in_flags_write = 0; + PRInt16 out_flags_read = 0, out_flags_write = 0; + + if ((NULL != pds[index].fd) && (0 != pds[index].in_flags)) + { + if (pds[index].in_flags & PR_POLL_READ) + { + in_flags_read = (pds[index].fd->methods->poll)( + pds[index].fd, + pds[index].in_flags & ~PR_POLL_WRITE, + &out_flags_read); + } + if (pds[index].in_flags & PR_POLL_WRITE) + { + in_flags_write = (pds[index].fd->methods->poll)( + pds[index].fd, + pds[index].in_flags & ~PR_POLL_READ, + &out_flags_write); + } + if ((0 != (in_flags_read & out_flags_read)) + || (0 != (in_flags_write & out_flags_write))) + { + /* this one is ready right now */ + if (0 == ready) + { + /* + * We will return without calling the system + * poll function. So zero the out_flags + * fields of all the poll descriptors before + * this one. + */ + int i; + for (i = 0; i < index; i++) + { + pds[i].out_flags = 0; + } + } + ready += 1; + pds[index].out_flags = out_flags_read | out_flags_write; + } + else + { + pds[index].out_flags = 0; /* pre-condition */ + /* now locate the NSPR layer at the bottom of the stack */ + bottom = PR_GetIdentitiesLayer(pds[index].fd, PR_NSPR_IO_LAYER); + PR_ASSERT(NULL != bottom); /* what to do about that? */ + if ((NULL != bottom) + && (_PR_FILEDESC_OPEN == bottom->secret->state)) + { + if (0 == ready) + { + syspoll[index].fd = bottom->secret->md.osfd; + syspoll[index].events = 0; /* pre-condition */ + if (in_flags_read & PR_POLL_READ) + { + pds[index].out_flags |= + _PR_POLL_READ_SYS_READ; + syspoll[index].events |= POLLIN; + } + if (in_flags_read & PR_POLL_WRITE) + { + pds[index].out_flags |= + _PR_POLL_READ_SYS_WRITE; + syspoll[index].events |= POLLOUT; + } + if (in_flags_write & PR_POLL_READ) + { + pds[index].out_flags |= + _PR_POLL_WRITE_SYS_READ; + syspoll[index].events |= POLLIN; + } + if (in_flags_write & PR_POLL_WRITE) + { + pds[index].out_flags |= + _PR_POLL_WRITE_SYS_WRITE; + syspoll[index].events |= POLLOUT; + } + if (pds[index].in_flags & PR_POLL_EXCEPT) + syspoll[index].events |= POLLPRI; + } + } + else + { + if (0 == ready) + { + int i; + for (i = 0; i < index; i++) + { + pds[i].out_flags = 0; + } + } + ready += 1; /* this will cause an abrupt return */ + pds[index].out_flags = PR_POLL_NVAL; /* bogii */ + } + } + } + else + { + /* make poll() ignore this entry */ + syspoll[index].fd = -1; + } + } + + if (0 == ready) + { + switch (timeout) + { + case PR_INTERVAL_NO_WAIT: msecs = 0; break; + case PR_INTERVAL_NO_TIMEOUT: msecs = -1; break; + default: + msecs = PR_IntervalToMilliseconds(timeout); + start = PR_IntervalNow(); + } + +retry: + ready = _MD_POLL(syspoll, npds, msecs); + if (-1 == ready) + { + PRIntn oserror = errno; + + if (EINTR == oserror) + { + if (timeout == PR_INTERVAL_NO_TIMEOUT) goto retry; + else if (timeout == PR_INTERVAL_NO_WAIT) ready = 0; + else + { + elapsed = (PRIntervalTime)(PR_IntervalNow() - start); + if (elapsed > timeout) ready = 0; /* timed out */ + else + { + remaining = timeout - elapsed; + msecs = PR_IntervalToMilliseconds(remaining); + goto retry; + } + } + } + else _PR_MD_MAP_POLL_ERROR(oserror); + } + else if (ready > 0) + { + for (index = 0; index < npds; ++index) + { + PRInt16 out_flags = 0; + if ((NULL != pds[index].fd) && (0 != pds[index].in_flags)) + { + if (0 != syspoll[index].revents) + { + /* + ** Set up the out_flags so that it contains the + ** bits that the highest layer thinks are nice + ** to have. Then the client of that layer will + ** call the appropriate I/O function and maybe + ** the protocol will make progress. + */ + if (syspoll[index].revents & POLLIN) + { + if (pds[index].out_flags + & _PR_POLL_READ_SYS_READ) + { + out_flags |= PR_POLL_READ; + } + if (pds[index].out_flags + & _PR_POLL_WRITE_SYS_READ) + { + out_flags |= PR_POLL_WRITE; + } + } + if (syspoll[index].revents & POLLOUT) + { + if (pds[index].out_flags + & _PR_POLL_READ_SYS_WRITE) + { + out_flags |= PR_POLL_READ; + } + if (pds[index].out_flags + & _PR_POLL_WRITE_SYS_WRITE) + { + out_flags |= PR_POLL_WRITE; + } + } + if (syspoll[index].revents & POLLPRI) + out_flags |= PR_POLL_EXCEPT; + if (syspoll[index].revents & POLLERR) + out_flags |= PR_POLL_ERR; + if (syspoll[index].revents & POLLNVAL) + out_flags |= PR_POLL_NVAL; + if (syspoll[index].revents & POLLHUP) + out_flags |= PR_POLL_HUP; + } + } + pds[index].out_flags = out_flags; + } + } + } + + PR_DELETE(syspoll); + return ready; + +} /* NativeThreadPoll */ +#endif /* defined(_PR_USE_POLL) */ + +#if !defined(_PR_USE_POLL) +static PRInt32 NativeThreadSelect( + PRPollDesc *pds, PRIntn npds, PRIntervalTime timeout) +{ + /* + * This code is almost a duplicate of w32poll.c's _PR_MD_PR_POLL(). + */ + fd_set rd, wt, ex; + PRFileDesc *bottom; + PRPollDesc *pd, *epd; + PRInt32 maxfd = -1, ready, err; + PRIntervalTime remaining, elapsed, start; + + struct timeval tv, *tvp = NULL; + + FD_ZERO(&rd); + FD_ZERO(&wt); + FD_ZERO(&ex); + + ready = 0; + for (pd = pds, epd = pd + npds; pd < epd; pd++) + { + PRInt16 in_flags_read = 0, in_flags_write = 0; + PRInt16 out_flags_read = 0, out_flags_write = 0; + + if ((NULL != pd->fd) && (0 != pd->in_flags)) + { + if (pd->in_flags & PR_POLL_READ) + { + in_flags_read = (pd->fd->methods->poll)( + pd->fd, pd->in_flags & ~PR_POLL_WRITE, &out_flags_read); + } + if (pd->in_flags & PR_POLL_WRITE) + { + in_flags_write = (pd->fd->methods->poll)( + pd->fd, pd->in_flags & ~PR_POLL_READ, &out_flags_write); + } + if ((0 != (in_flags_read & out_flags_read)) + || (0 != (in_flags_write & out_flags_write))) + { + /* this one's ready right now */ + if (0 == ready) + { + /* + * We will have to return without calling the + * system poll/select function. So zero the + * out_flags fields of all the poll descriptors + * before this one. + */ + PRPollDesc *prev; + for (prev = pds; prev < pd; prev++) + { + prev->out_flags = 0; + } + } + ready += 1; + pd->out_flags = out_flags_read | out_flags_write; + } + else + { + pd->out_flags = 0; /* pre-condition */ + + /* make sure this is an NSPR supported stack */ + bottom = PR_GetIdentitiesLayer(pd->fd, PR_NSPR_IO_LAYER); + PR_ASSERT(NULL != bottom); /* what to do about that? */ + if ((NULL != bottom) + && (_PR_FILEDESC_OPEN == bottom->secret->state)) + { + if (0 == ready) + { + PRInt32 osfd = bottom->secret->md.osfd; + if (osfd > maxfd) maxfd = osfd; + if (in_flags_read & PR_POLL_READ) + { + pd->out_flags |= _PR_POLL_READ_SYS_READ; + FD_SET(osfd, &rd); + } + if (in_flags_read & PR_POLL_WRITE) + { + pd->out_flags |= _PR_POLL_READ_SYS_WRITE; + FD_SET(osfd, &wt); + } + if (in_flags_write & PR_POLL_READ) + { + pd->out_flags |= _PR_POLL_WRITE_SYS_READ; + FD_SET(osfd, &rd); + } + if (in_flags_write & PR_POLL_WRITE) + { + pd->out_flags |= _PR_POLL_WRITE_SYS_WRITE; + FD_SET(osfd, &wt); + } + if (pd->in_flags & PR_POLL_EXCEPT) FD_SET(osfd, &ex); + } + } + else + { + if (0 == ready) + { + PRPollDesc *prev; + for (prev = pds; prev < pd; prev++) + { + prev->out_flags = 0; + } + } + ready += 1; /* this will cause an abrupt return */ + pd->out_flags = PR_POLL_NVAL; /* bogii */ + } + } + } + } + + if (0 != ready) return ready; /* no need to block */ + + remaining = timeout; + start = PR_IntervalNow(); + +retry: + if (timeout != PR_INTERVAL_NO_TIMEOUT) + { + PRInt32 ticksPerSecond = PR_TicksPerSecond(); + tv.tv_sec = remaining / ticksPerSecond; + tv.tv_usec = remaining - (ticksPerSecond * tv.tv_sec); + tv.tv_usec = (PR_USEC_PER_SEC * tv.tv_usec) / ticksPerSecond; + tvp = &tv; + } + + ready = _MD_SELECT(maxfd + 1, &rd, &wt, &ex, tvp); + + if (ready == -1 && errno == EINTR) + { + if (timeout == PR_INTERVAL_NO_TIMEOUT) goto retry; + else + { + elapsed = (PRIntervalTime) (PR_IntervalNow() - start); + if (elapsed > timeout) ready = 0; /* timed out */ + else + { + remaining = timeout - elapsed; + goto retry; + } + } + } + + /* + ** Now to unravel the select sets back into the client's poll + ** descriptor list. Is this possibly an area for pissing away + ** a few cycles or what? + */ + if (ready > 0) + { + ready = 0; + for (pd = pds, epd = pd + npds; pd < epd; pd++) + { + PRInt16 out_flags = 0; + if ((NULL != pd->fd) && (0 != pd->in_flags)) + { + PRInt32 osfd; + bottom = PR_GetIdentitiesLayer(pd->fd, PR_NSPR_IO_LAYER); + PR_ASSERT(NULL != bottom); + + osfd = bottom->secret->md.osfd; + + if (FD_ISSET(osfd, &rd)) + { + if (pd->out_flags & _PR_POLL_READ_SYS_READ) + out_flags |= PR_POLL_READ; + if (pd->out_flags & _PR_POLL_WRITE_SYS_READ) + out_flags |= PR_POLL_WRITE; + } + if (FD_ISSET(osfd, &wt)) + { + if (pd->out_flags & _PR_POLL_READ_SYS_WRITE) + out_flags |= PR_POLL_READ; + if (pd->out_flags & _PR_POLL_WRITE_SYS_WRITE) + out_flags |= PR_POLL_WRITE; + } + if (FD_ISSET(osfd, &ex)) out_flags |= PR_POLL_EXCEPT; + } + pd->out_flags = out_flags; + if (out_flags) ready++; + } + PR_ASSERT(ready > 0); + } + else if (ready < 0) + { + err = _MD_ERRNO(); + if (err == EBADF) + { + /* Find the bad fds */ + ready = 0; + for (pd = pds, epd = pd + npds; pd < epd; pd++) + { + pd->out_flags = 0; + if ((NULL != pd->fd) && (0 != pd->in_flags)) + { + bottom = PR_GetIdentitiesLayer(pd->fd, PR_NSPR_IO_LAYER); + if (fcntl(bottom->secret->md.osfd, F_GETFL, 0) == -1) + { + pd->out_flags = PR_POLL_NVAL; + ready++; + } + } + } + PR_ASSERT(ready > 0); + } + else _PR_MD_MAP_SELECT_ERROR(err); + } + + return ready; +} /* NativeThreadSelect */ +#endif /* !defined(_PR_USE_POLL) */ + +static PRInt32 LocalThreads( + PRPollDesc *pds, PRIntn npds, PRIntervalTime timeout) +{ + PRPollDesc *pd, *epd; + PRInt32 ready, pdcnt; + _PRUnixPollDesc *unixpds, *unixpd; + + /* + * XXX + * PRPollDesc has a PRFileDesc field, fd, while the IOQ + * is a list of PRPollQueue structures, each of which contains + * a _PRUnixPollDesc. A _PRUnixPollDesc struct contains + * the OS file descriptor, osfd, and not a PRFileDesc. + * So, we have allocate memory for _PRUnixPollDesc structures, + * copy the flags information from the pds list and have pq + * point to this list of _PRUnixPollDesc structures. + * + * It would be better if the memory allocation can be avoided. + */ + + unixpd = unixpds = (_PRUnixPollDesc*) + PR_MALLOC(npds * sizeof(_PRUnixPollDesc)); + if (NULL == unixpds) + { + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + return -1; + } + + ready = 0; + for (pdcnt = 0, pd = pds, epd = pd + npds; pd < epd; pd++) + { + PRFileDesc *bottom; + PRInt16 in_flags_read = 0, in_flags_write = 0; + PRInt16 out_flags_read = 0, out_flags_write = 0; + + if ((NULL != pd->fd) && (0 != pd->in_flags)) + { + if (pd->in_flags & PR_POLL_READ) + { + in_flags_read = (pd->fd->methods->poll)( + pd->fd, pd->in_flags & ~PR_POLL_WRITE, &out_flags_read); + } + if (pd->in_flags & PR_POLL_WRITE) + { + in_flags_write = (pd->fd->methods->poll)( + pd->fd, pd->in_flags & ~PR_POLL_READ, &out_flags_write); + } + if ((0 != (in_flags_read & out_flags_read)) + || (0 != (in_flags_write & out_flags_write))) + { + /* this one's ready right now */ + if (0 == ready) + { + /* + * We will have to return without calling the + * system poll/select function. So zero the + * out_flags fields of all the poll descriptors + * before this one. + */ + PRPollDesc *prev; + for (prev = pds; prev < pd; prev++) + { + prev->out_flags = 0; + } + } + ready += 1; + pd->out_flags = out_flags_read | out_flags_write; + } + else + { + pd->out_flags = 0; /* pre-condition */ + bottom = PR_GetIdentitiesLayer(pd->fd, PR_NSPR_IO_LAYER); + PR_ASSERT(NULL != bottom); /* what to do about that? */ + if ((NULL != bottom) + && (_PR_FILEDESC_OPEN == bottom->secret->state)) + { + if (0 == ready) + { + unixpd->osfd = bottom->secret->md.osfd; + unixpd->in_flags = 0; + if (in_flags_read & PR_POLL_READ) + { + unixpd->in_flags |= _PR_UNIX_POLL_READ; + pd->out_flags |= _PR_POLL_READ_SYS_READ; + } + if (in_flags_read & PR_POLL_WRITE) + { + unixpd->in_flags |= _PR_UNIX_POLL_WRITE; + pd->out_flags |= _PR_POLL_READ_SYS_WRITE; + } + if (in_flags_write & PR_POLL_READ) + { + unixpd->in_flags |= _PR_UNIX_POLL_READ; + pd->out_flags |= _PR_POLL_WRITE_SYS_READ; + } + if (in_flags_write & PR_POLL_WRITE) + { + unixpd->in_flags |= _PR_UNIX_POLL_WRITE; + pd->out_flags |= _PR_POLL_WRITE_SYS_WRITE; + } + if ((in_flags_read | in_flags_write) & PR_POLL_EXCEPT) + { + unixpd->in_flags |= _PR_UNIX_POLL_EXCEPT; + } + unixpd++; pdcnt++; + } + } + else + { + if (0 == ready) + { + PRPollDesc *prev; + for (prev = pds; prev < pd; prev++) + { + prev->out_flags = 0; + } + } + ready += 1; /* this will cause an abrupt return */ + pd->out_flags = PR_POLL_NVAL; /* bogii */ + } + } + } + } + + if (0 != ready) + { + /* no need to block */ + PR_DELETE(unixpds); + return ready; + } + + ready = _PR_WaitForMultipleFDs(unixpds, pdcnt, timeout); + + /* + * Copy the out_flags from the _PRUnixPollDesc structures to the + * user's PRPollDesc structures and free the allocated memory + */ + unixpd = unixpds; + for (pd = pds, epd = pd + npds; pd < epd; pd++) + { + PRInt16 out_flags = 0; + if ((NULL != pd->fd) && (0 != pd->in_flags)) + { + /* + * take errors from the poll operation, + * the R/W bits from the request + */ + if (0 != unixpd->out_flags) + { + if (unixpd->out_flags & _PR_UNIX_POLL_READ) + { + if (pd->out_flags & _PR_POLL_READ_SYS_READ) + out_flags |= PR_POLL_READ; + if (pd->out_flags & _PR_POLL_WRITE_SYS_READ) + out_flags |= PR_POLL_WRITE; + } + if (unixpd->out_flags & _PR_UNIX_POLL_WRITE) + { + if (pd->out_flags & _PR_POLL_READ_SYS_WRITE) + out_flags |= PR_POLL_READ; + if (pd->out_flags & _PR_POLL_WRITE_SYS_WRITE) + out_flags |= PR_POLL_WRITE; + } + if (unixpd->out_flags & _PR_UNIX_POLL_EXCEPT) + out_flags |= PR_POLL_EXCEPT; + if (unixpd->out_flags & _PR_UNIX_POLL_ERR) + out_flags |= PR_POLL_ERR; + if (unixpd->out_flags & _PR_UNIX_POLL_NVAL) + out_flags |= PR_POLL_NVAL; + if (unixpd->out_flags & _PR_UNIX_POLL_HUP) + out_flags |= PR_POLL_HUP; + } + unixpd++; + } + pd->out_flags = out_flags; + } + + PR_DELETE(unixpds); + + return ready; +} /* LocalThreads */ + +#if defined(_PR_USE_POLL) +#define NativeThreads NativeThreadPoll +#else +#define NativeThreads NativeThreadSelect +#endif + +PRInt32 _MD_pr_poll(PRPollDesc *pds, PRIntn npds, PRIntervalTime timeout) +{ + PRInt32 rv = 0; + PRThread *me = _PR_MD_CURRENT_THREAD(); + + if (_PR_PENDING_INTERRUPT(me)) + { + me->flags &= ~_PR_INTERRUPT; + PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); + return -1; + } + if (0 == npds) PR_Sleep(timeout); + else if (_PR_IS_NATIVE_THREAD(me)) + rv = NativeThreads(pds, npds, timeout); + else rv = LocalThreads(pds, npds, timeout); + + return rv; +} /* _MD_pr_poll */ + +#endif /* defined(_PR_PTHREADS) */ + +/* pruxpoll.c */ + diff --git a/pr/src/md/unix/uxproces.c b/pr/src/md/unix/uxproces.c index ecbc14d7..c2b7eee5 100644 --- a/pr/src/md/unix/uxproces.c +++ b/pr/src/md/unix/uxproces.c @@ -23,6 +23,9 @@ #include <fcntl.h> #include <signal.h> #include <sys/wait.h> +#if defined(AIX) +#include <dlfcn.h> /* For dlopen, dlsym, dlclose */ +#endif /* * HP-UX 9 doesn't have the SA_RESTART flag. @@ -98,6 +101,16 @@ static struct { #ifdef _PR_SHARE_CLONES struct pr_CreateProcOp *opHead, *opTail; #endif + +#ifdef AIX + pid_t (*forkptr)(void); /* Newer versions of AIX (starting in 4.3.2) + * have f_fork, which is faster than the + * regular fork in a multithreaded process + * because it skips calling the fork handlers. + * So we look up the f_fork symbol to see if + * it's available and fall back on fork. + */ +#endif /* AIX */ } pr_wp; #ifdef _PR_SHARE_CLONES @@ -134,7 +147,11 @@ ForkAndExec( return NULL; } +#ifdef AIX + process->md.pid = (*pr_wp.forkptr)(); +#else process->md.pid = fork(); +#endif if ((pid_t) -1 == process->md.pid) { PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, errno); PR_DELETE(process); @@ -578,6 +595,17 @@ static PRStatus _MD_InitProcesses() #define _PR_NBIO_FLAG O_NONBLOCK #endif +#ifdef AIX + { + void *handle = dlopen(NULL, RTLD_NOW | RTLD_GLOBAL); + pr_wp.forkptr = (pid_t (*)(void)) dlsym(handle, "f_fork"); + if (!pr_wp.forkptr) { + pr_wp.forkptr = fork; + } + dlclose(handle); + } +#endif /* AIX */ + pr_wp.ml = PR_NewLock(); PR_ASSERT(NULL != pr_wp.ml); diff --git a/pr/src/md/unix/uxwrap.c b/pr/src/md/unix/uxwrap.c index 577c4411..9a26c90d 100644 --- a/pr/src/md/unix/uxwrap.c +++ b/pr/src/md/unix/uxwrap.c @@ -48,38 +48,26 @@ ); \ PR_END_MACRO -#define COPY_SET(_to, _from, _width) \ - PR_BEGIN_MACRO \ - memcpy(_to, _from, \ - ((_width + 8*sizeof(int)-1) / (8*sizeof(int))) \ - * sizeof(int) \ - ); \ - PR_END_MACRO - -/* An internal global variable defined in prfile.c */ -extern PRIOMethods _pr_fileMethods; - - /* see comments in ns/cmd/xfe/mozilla.c (look for "PR_XGetXtHackFD") */ static int _pr_xt_hack_fd = -1; int PR_XGetXtHackFD(void) { - int fds[2]; + int fds[2]; - if (_pr_xt_hack_fd == -1) { - if (!pipe(fds)) { - _pr_xt_hack_fd = fds[0]; - } - } - return _pr_xt_hack_fd; - } + if (_pr_xt_hack_fd == -1) { + if (!pipe(fds)) { + _pr_xt_hack_fd = fds[0]; + } + } + return _pr_xt_hack_fd; +} static int (*_pr_xt_hack_okayToReleaseXLock)(void) = 0; void PR_SetXtHackOkayToReleaseXLockFn(int (*fn)(void)) { - _pr_xt_hack_okayToReleaseXLock = fn; + _pr_xt_hack_okayToReleaseXLock = fn; } @@ -97,7 +85,7 @@ void PR_SetXtHackOkayToReleaseXLockFn(int (*fn)(void)) int select(size_t width, int *rl, int *wl, int *el, const struct timeval *tv) #elif defined(AIX4_1) int wrap_select(unsigned long width, void *rl, void *wl, void *el, - struct timeval *tv) + struct timeval *tv) #elif (defined(BSDI) && !defined(BSDI_2)) int select(int width, fd_set *rd, fd_set *wr, fd_set *ex, const struct timeval *tv) @@ -105,12 +93,9 @@ int select(int width, fd_set *rd, fd_set *wr, fd_set *ex, int select(int width, fd_set *rd, fd_set *wr, fd_set *ex, struct timeval *tv) #endif { - int i; - int npds; - void *pollset; - PRPollDesc *pd; - PRFileDesc *prfd; - PRFilePrivate *secret; + int osfd; + _PRUnixPollDesc *unixpds, *unixpd, *eunixpd; + PRInt32 pdcnt; PRIntervalTime timeout; int retVal; #if defined(HPUX9) || defined(AIX4_1) @@ -118,7 +103,6 @@ int select(int width, fd_set *rd, fd_set *wr, fd_set *ex, struct timeval *tv) fd_set *wr = (fd_set*) wl; fd_set *ex = (fd_set*) el; #endif - fd_set r, w, x; #if 0 /* @@ -134,8 +118,9 @@ int select(int width, fd_set *rd, fd_set *wr, fd_set *ex, struct timeval *tv) } #endif - if (!_pr_initialized) - _PR_ImplicitInitialization(); + if (!_pr_initialized) { + _PR_ImplicitInitialization(); + } #ifndef _PR_LOCAL_THREADS_ONLY if (_PR_IS_NATIVE_THREAD(_PR_MD_CURRENT_THREAD())) { @@ -144,39 +129,35 @@ int select(int width, fd_set *rd, fd_set *wr, fd_set *ex, struct timeval *tv) #endif if (width < 0 || width > FD_SETSIZE) { - errno = EINVAL; - return -1; + errno = EINVAL; + return -1; } /* Compute timeout */ if (tv) { - /* - * These acceptable ranges for t_sec and t_usec are taken - * from the select() man pages. - */ - if (tv->tv_sec < 0 || tv->tv_sec > 100000000 - || tv->tv_usec < 0 || tv->tv_usec >= 1000000) { - errno = EINVAL; - return -1; - } - - /* Convert microseconds to ticks */ - timeout = PR_MicrosecondsToInterval(1000000*tv->tv_sec + tv->tv_usec); + /* + * These acceptable ranges for t_sec and t_usec are taken + * from the select() man pages. + */ + if (tv->tv_sec < 0 || tv->tv_sec > 100000000 + || tv->tv_usec < 0 || tv->tv_usec >= 1000000) { + errno = EINVAL; + return -1; + } + + /* Convert microseconds to ticks */ + timeout = PR_MicrosecondsToInterval(1000000*tv->tv_sec + tv->tv_usec); } else { - /* tv being a NULL pointer means blocking indefinitely */ - timeout = PR_INTERVAL_NO_TIMEOUT; + /* tv being a NULL pointer means blocking indefinitely */ + timeout = PR_INTERVAL_NO_TIMEOUT; } /* Check for no descriptors case (just doing a timeout) */ if ((!rd && !wr && !ex) || !width) { - PR_Sleep(timeout); - return 0; + PR_Sleep(timeout); + return 0; } - if (rd) { COPY_SET(&r, rd, width); } - if (wr) { COPY_SET(&w, wr, width); } - if (ex) { COPY_SET(&x, ex, width); } - /* * Set up for PR_Poll(). The PRPollDesc array is allocated * dynamically. If this turns out to have high performance @@ -187,63 +168,59 @@ int select(int width, fd_set *rd, fd_set *wr, fd_set *ex, struct timeval *tv) * I allocate an array of size 'width', which is the maximum * number of fds we may need to poll. */ - pollset = PR_CALLOC(width * - (sizeof(PRPollDesc) + sizeof(PRFileDesc) + sizeof(PRFilePrivate))); - if (!pollset) { + unixpds = (_PRUnixPollDesc *) PR_CALLOC(width * sizeof(_PRUnixPollDesc)); + if (!unixpds) { errno = ENOMEM; return -1; } - pd = (PRPollDesc*)pollset; - prfd = (PRFileDesc*)(&pd[width]); - secret = (PRFilePrivate*)(&prfd[width]); - - for (npds = 0, i = 0; i < width; i++) { - int in_flags = 0; - if (rd && FD_ISSET(i, &r)) { - in_flags |= PR_POLL_READ; - } - if (wr && FD_ISSET(i, &w)) { - in_flags |= PR_POLL_WRITE; - } - if (ex && FD_ISSET(i, &x)) { - in_flags |= PR_POLL_EXCEPT; - } - if (in_flags) { - prfd[npds].secret = &secret[npds]; - prfd[npds].secret->state = _PR_FILEDESC_OPEN; - prfd[npds].secret->md.osfd = i; - prfd[npds].methods = &_pr_fileMethods; - - pd[npds].fd = &prfd[npds]; - pd[npds].in_flags = in_flags; - pd[npds].out_flags = 0; - npds += 1; - } + + pdcnt = 0; + unixpd = unixpds; + for (osfd = 0; osfd < width; osfd++) { + int in_flags = 0; + if (rd && FD_ISSET(osfd, rd)) { + in_flags |= _PR_UNIX_POLL_READ; + } + if (wr && FD_ISSET(osfd, wr)) { + in_flags |= _PR_UNIX_POLL_WRITE; + } + if (ex && FD_ISSET(osfd, ex)) { + in_flags |= _PR_UNIX_POLL_EXCEPT; + } + if (in_flags) { + unixpd->osfd = osfd; + unixpd->in_flags = in_flags; + unixpd->out_flags = 0; + unixpd++; + pdcnt++; + } } - /* see comments in ns/cmd/xfe/mozilla.c (look for "PR_XGetXtHackFD") */ - { - + /* + * see comments in mozilla/cmd/xfe/mozilla.c (look for + * "PR_XGetXtHackFD") + */ + { int needToLockXAgain; needToLockXAgain = 0; - if (rd && (_pr_xt_hack_fd != -1) && - FD_ISSET(_pr_xt_hack_fd, &r) && PR_XIsLocked() && - (!_pr_xt_hack_okayToReleaseXLock || _pr_xt_hack_okayToReleaseXLock())) { - PR_XUnlock(); - needToLockXAgain = 1; + if (rd && (_pr_xt_hack_fd != -1) + && FD_ISSET(_pr_xt_hack_fd, rd) && PR_XIsLocked() + && (!_pr_xt_hack_okayToReleaseXLock + || _pr_xt_hack_okayToReleaseXLock())) { + PR_XUnlock(); + needToLockXAgain = 1; } /* This is the potentially blocking step */ - retVal = PR_Poll(pd, npds, timeout); + retVal = _PR_WaitForMultipleFDs(unixpds, pdcnt, timeout); if (needToLockXAgain) { - PR_XLock(); + PR_XLock(); } } - if (retVal > 0) - { + if (retVal > 0) { /* Compute select results */ if (rd) ZAP_SET(rd, width); if (wr) ZAP_SET(wr, width); @@ -254,43 +231,55 @@ int select(int width, fd_set *rd, fd_set *wr, fd_set *ex, struct timeval *tv) * descriptors or the number of set bits in the three fd_set's. */ retVal = 0; /* we're going to recompute */ - for (i = 0; i < npds; ++i, pd++) - { - if (pd->out_flags) { - int nbits = 0; /* The number of set bits on for this fd */ - - if (pd->out_flags & PR_POLL_NVAL) { - errno = EBADF; - PR_LOG(_pr_io_lm, PR_LOG_ERROR, - ("select returns EBADF for %d", pd->fd)); - retVal = -1; - break; - } - if (rd && (pd->out_flags & PR_POLL_READ)) { - FD_SET(pd->fd->secret->md.osfd, rd); - nbits++; - } - if (wr && (pd->out_flags & PR_POLL_WRITE)) { - FD_SET(pd->fd->secret->md.osfd, wr); - nbits++; - } - if (ex && (pd->out_flags & PR_POLL_EXCEPT)) { - FD_SET(pd->fd->secret->md.osfd, ex); - nbits++; - } - PR_ASSERT(nbits > 0); + eunixpd = unixpds + pdcnt; + for (unixpd = unixpds; unixpd < eunixpd; unixpd++) { + if (unixpd->out_flags) { + int nbits = 0; /* The number of set bits on for this fd */ + + if (unixpd->out_flags & _PR_UNIX_POLL_NVAL) { + errno = EBADF; + PR_LOG(_pr_io_lm, PR_LOG_ERROR, + ("select returns EBADF for %d", unixpd->osfd)); + retVal = -1; + break; + } + /* + * If a socket has a pending error, it is considered + * both readable and writable. (See W. Richard Stevens, + * Unix Network Programming, Vol. 1, 2nd Ed., Section 6.3, + * pp. 153-154.) We also consider a socket readable if + * it has a hangup condition. + */ + if (rd && (unixpd->in_flags & _PR_UNIX_POLL_READ) + && (unixpd->out_flags & (_PR_UNIX_POLL_READ + | _PR_UNIX_POLL_ERR | _PR_UNIX_POLL_HUP))) { + FD_SET(unixpd->osfd, rd); + nbits++; + } + if (wr && (unixpd->in_flags & _PR_UNIX_POLL_WRITE) + && (unixpd->out_flags & (_PR_UNIX_POLL_WRITE + | _PR_UNIX_POLL_ERR))) { + FD_SET(unixpd->osfd, wr); + nbits++; + } + if (ex && (unixpd->in_flags & _PR_UNIX_POLL_WRITE) + && (unixpd->out_flags & PR_POLL_EXCEPT)) { + FD_SET(unixpd->osfd, ex); + nbits++; + } + PR_ASSERT(nbits > 0); #if defined(HPUX) || defined(SOLARIS) || defined(SUNOS4) || defined(OSF1) || defined(AIX) retVal += nbits; #else /* IRIX */ retVal += 1; #endif - } + } } } PR_ASSERT(tv || retVal != 0); PR_LOG(_pr_io_lm, PR_LOG_MIN, ("select returns %d", retVal)); - PR_DELETE(pollset); + PR_DELETE(unixpds); return retVal; } @@ -314,7 +303,7 @@ int select(int width, fd_set *rd, fd_set *wr, fd_set *ex, struct timeval *tv) *----------------------------------------------------------------------- */ -#include <poll.h> +#include <sys/poll.h> #if defined(AIX4_1) int wrap_poll(void *listptr, unsigned long nfds, long timeout) @@ -326,6 +315,8 @@ int poll(struct pollfd filedes[], unsigned int nfds, int timeout) int poll(struct pollfd filedes[], int nfds, int timeout) #elif defined(NETBSD) int poll(struct pollfd *filedes, nfds_t nfds, int timeout) +#elif defined(OPENBSD) +int poll(struct pollfd *filedes, int nfds, int timeout) #else int poll(struct pollfd *filedes, unsigned long nfds, int timeout) #endif @@ -333,13 +324,11 @@ int poll(struct pollfd *filedes, unsigned long nfds, int timeout) #ifdef AIX struct pollfd *filedes = (struct pollfd *) listptr; #endif - void *pollset; - PRPollDesc *pd; - PRFileDesc *prfd; - PRFilePrivate *secret; - int i; - PRUint32 ticks; - PRInt32 retVal; + struct pollfd *pfd, *epfd; + _PRUnixPollDesc *unixpds, *unixpd, *eunixpd; + PRIntervalTime ticks; + PRInt32 pdcnt; + int ready; /* * Easy special case: zero timeout. Simply call the native @@ -359,8 +348,7 @@ int poll(struct pollfd *filedes, unsigned long nfds, int timeout) #ifndef _PR_LOCAL_THREADS_ONLY if (_PR_IS_NATIVE_THREAD(_PR_MD_CURRENT_THREAD())) { - retVal = _MD_POLL(filedes, nfds, timeout); - return(retVal); + return _MD_POLL(filedes, nfds, timeout); } #endif @@ -370,144 +358,155 @@ int poll(struct pollfd *filedes, unsigned long nfds, int timeout) #endif if (timeout < 0 && timeout != -1) { - errno = EINVAL; - return -1; + errno = EINVAL; + return -1; } /* Convert timeout from miliseconds to ticks */ if (timeout == -1) { - ticks = PR_INTERVAL_NO_TIMEOUT; - } else if (timeout == 0) { - ticks = PR_INTERVAL_NO_WAIT; + ticks = PR_INTERVAL_NO_TIMEOUT; } else { ticks = PR_MillisecondsToInterval(timeout); } /* Check for no descriptor case (just do a timeout) */ if (nfds == 0) { - PR_Sleep(ticks); - return 0; + PR_Sleep(ticks); + return 0; } - pollset = PR_CALLOC(nfds * - (sizeof(PRPollDesc) + sizeof(PRFileDesc) + sizeof(PRFilePrivate))); - if (!pollset) { + unixpds = (_PRUnixPollDesc *) + PR_MALLOC(nfds * sizeof(_PRUnixPollDesc)); + if (NULL == unixpds) { errno = EAGAIN; return -1; } - pd = (PRPollDesc*)pollset; - prfd = (PRFileDesc*)(&pd[nfds]); - secret = (PRFilePrivate*)(&prfd[nfds]); - - for (i = 0; i < nfds; i++) { - prfd[i].secret = &secret[i]; - prfd[i].secret->state = _PR_FILEDESC_OPEN; - prfd[i].secret->md.osfd = filedes[i].fd; - prfd[i].methods = &_pr_fileMethods; - - pd[i].fd = &prfd[i]; - pd[i].out_flags = 0; - - /* - * poll() ignores negative fd's. We emulate this behavior - * by making sure the in_flags for a negative fd is zero. - */ - if (filedes[i].fd < 0) { - pd[i].in_flags = 0; - continue; - } + + pdcnt = 0; + epfd = filedes + nfds; + unixpd = unixpds; + for (pfd = filedes; pfd < epfd; pfd++) { + /* + * poll() ignores negative fd's. + */ + if (pfd->fd >= 0) { + unixpd->osfd = pfd->fd; #ifdef _PR_USE_POLL - pd[i].in_flags = filedes[i].events; + unixpd->in_flags = pfd->events; #else - /* - * Map the native poll flags to nspr20 poll flags. - * POLLIN, POLLRDNORM ===> PR_POLL_READ - * POLLOUT, POLLWRNORM ===> PR_POLL_WRITE - * POLLPRI, POLLRDBAND ===> PR_POLL_EXCEPT - * POLLNORM, POLLWRBAND (and POLLMSG on some platforms) - * are ignored. - * - * The output events POLLERR and POLLHUP are never turned on. - * POLLNVAL may be turned on. - */ - pd[i].in_flags = 0; - if (filedes[i].events & (POLLIN + /* + * Map the poll events to one of the three that can be + * represented by the select fd_sets: + * POLLIN, POLLRDNORM ===> readable + * POLLOUT, POLLWRNORM ===> writable + * POLLPRI, POLLRDBAND ===> exception + * POLLNORM, POLLWRBAND (and POLLMSG on some platforms) + * are ignored. + * + * The output events POLLERR and POLLHUP are never turned on. + * POLLNVAL may be turned on. + */ + unixpd->in_flags = 0; + if (pfd->events & (POLLIN #ifdef POLLRDNORM - | POLLRDNORM + | POLLRDNORM #endif - )) { - pd[i].in_flags |= PR_POLL_READ; - } - if (filedes[i].events & (POLLOUT + )) { + unixpd->in_flags |= _PR_UNIX_POLL_READ; + } + if (pfd->events & (POLLOUT #ifdef POLLWRNORM - | POLLWRNORM + | POLLWRNORM #endif - )) { - pd[i].in_flags |= PR_POLL_WRITE; - } - if (filedes[i].events & (POLLPRI + )) { + unixpd->in_flags |= _PR_UNIX_POLL_WRITE; + } + if (pfd->events & (POLLPRI #ifdef POLLRDBAND - | POLLRDBAND + | POLLRDBAND #endif - )) { - pd[i].in_flags |= PR_POLL_EXCEPT; - } + )) { + unixpd->in_flags |= PR_POLL_EXCEPT; + } #endif /* _PR_USE_POLL */ + unixpd->out_flags = 0; + unixpd++; + pdcnt++; + } } - retVal = PR_Poll(pd, nfds, ticks); + ready = _PR_WaitForMultipleFDs(unixpds, pdcnt, ticks); + if (-1 == ready) { + if (PR_GetError() == PR_PENDING_INTERRUPT_ERROR) { + errno = EINTR; /* XXX we aren't interrupted by a signal, but... */ + } else { + errno = PR_GetOSError(); + } + } + if (ready <= 0) { + goto done; + } - if (retVal > 0) { - /* Set the revents bitmasks */ - for (i = 0; i < nfds; i++) { - PR_ASSERT(filedes[i].fd >= 0 || pd[i].in_flags == 0); - if (filedes[i].fd < 0) { - continue; /* skip negative fd's */ - } + /* + * Copy the out_flags from the _PRUnixPollDesc structures to the + * user's pollfd structures and free the allocated memory + */ + unixpd = unixpds; + for (pfd = filedes; pfd < epfd; pfd++) { + pfd->revents = 0; + if (pfd->fd >= 0) { #ifdef _PR_USE_POLL - filedes[i].revents = pd[i].out_flags; + pfd->revents = unixpd->out_flags; #else - filedes[i].revents = 0; - if (0 == pd[i].out_flags) { - continue; - } - if (pd[i].out_flags & PR_POLL_READ) { - if (filedes[i].events & POLLIN) - filedes[i].revents |= POLLIN; + if (0 != unixpd->out_flags) { + if (unixpd->out_flags & _PR_UNIX_POLL_READ) { + if (pfd->events & POLLIN) { + pfd->revents |= POLLIN; + } #ifdef POLLRDNORM - if (filedes[i].events & POLLRDNORM) - filedes[i].revents |= POLLRDNORM; + if (pfd->events & POLLRDNORM) { + pfd->revents |= POLLRDNORM; + } #endif - } - if (pd[i].out_flags & PR_POLL_WRITE) { - if (filedes[i].events & POLLOUT) - filedes[i].revents |= POLLOUT; + } + if (unixpd->out_flags & _PR_UNIX_POLL_WRITE) { + if (pfd->events & POLLOUT) { + pfd->revents |= POLLOUT; + } #ifdef POLLWRNORM - if (filedes[i].events & POLLWRNORM) - filedes[i].revents |= POLLWRNORM; + if (pfd->events & POLLWRNORM) { + pfd->revents |= POLLWRNORM; + } #endif - } - if (pd[i].out_flags & PR_POLL_EXCEPT) { - if (filedes[i].events & POLLPRI) - filedes[i].revents |= POLLPRI; + } + if (unixpd->out_flags & _PR_UNIX_POLL_EXCEPT) { + if (pfd->events & POLLPRI) { + pfd->revents |= POLLPRI; + } #ifdef POLLRDBAND - if (filedes[i].events & POLLRDBAND) - filedes[i].revents |= POLLRDBAND; + if (pfd->events & POLLRDBAND) { + pfd->revents |= POLLRDBAND; + } #endif - } - if (pd[i].out_flags & PR_POLL_ERR) { - filedes[i].revents |= POLLERR; - } - if (pd[i].out_flags & PR_POLL_NVAL) { - filedes[i].revents |= POLLNVAL; - } + } + if (unixpd->out_flags & _PR_UNIX_POLL_ERR) { + pfd->revents |= POLLERR; + } + if (unixpd->out_flags & _PR_UNIX_POLL_NVAL) { + pfd->revents |= POLLNVAL; + } + if (unixpd->out_flags & _PR_UNIX_POLL_HUP) { + pfd->revents |= POLLHUP; + } + } #endif /* _PR_USE_POLL */ + unixpd++; } } - PR_DELETE(pollset); - - return retVal; +done: + PR_DELETE(unixpds); + return ready; } #endif /* !defined(LINUX) */ diff --git a/pr/src/md/windows/Makefile b/pr/src/md/windows/Makefile index eaac7b56..c513a342 100644 --- a/pr/src/md/windows/Makefile +++ b/pr/src/md/windows/Makefile @@ -49,9 +49,11 @@ CSRCS = \ w95sock.c \ win32_errors.c \ w32poll.c \ + w95dllmain.c \ $(NULL) else CSRCS = \ + ntdllmn.c \ ntmisc.c \ ntsem.c \ ntinrval.c \ diff --git a/pr/src/md/windows/ntdllmn.c b/pr/src/md/windows/ntdllmn.c new file mode 100644 index 00000000..c9736a6e --- /dev/null +++ b/pr/src/md/windows/ntdllmn.c @@ -0,0 +1,67 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "NPL"); you may not use this file except in + * compliance with the NPL. You may obtain a copy of the NPL at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the NPL is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL + * for the specific language governing rights and limitations under the + * NPL. + * + * The Initial Developer of this code under the NPL is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All Rights + * Reserved. + */ + +/* + * The DLL entry point (DllMain) for NSPR. + * + * The only reason we use DLLMain() now is to find out whether + * the NSPR DLL is statically or dynamically loaded. When + * dynamically loaded, we cannot use static thread-local storage. + * However, static TLS is faster than the TlsXXX() functions. + * So we want to use static TLS whenever we can. A global + * variable _pr_use_static_tls is set in DllMain() during process + * attachment to indicate whether it is safe to use static TLS + * or not. + */ + +#include <windows.h> +#include <primpl.h> + +extern BOOL _pr_use_static_tls; /* defined in ntthread.c */ + +BOOL WINAPI DllMain( + HINSTANCE hinstDLL, + DWORD fdwReason, + LPVOID lpvReserved) +{ +PRThread *me; + + switch (fdwReason) { + case DLL_PROCESS_ATTACH: + /* + * If lpvReserved is NULL, we are dynamically loaded + * and therefore can't use static thread-local storage. + */ + if (lpvReserved == NULL) { + _pr_use_static_tls = FALSE; + } else { + _pr_use_static_tls = TRUE; + } + break; + case DLL_THREAD_ATTACH: + break; + case DLL_THREAD_DETACH: + me = _MD_GET_ATTACHED_THREAD(); + if ((me != NULL) && (me->flags & _PR_ATTACHED)) + _PRI_DetachThread(); + break; + case DLL_PROCESS_DETACH: + break; + } + return TRUE; +} diff --git a/pr/src/md/windows/ntio.c b/pr/src/md/windows/ntio.c index d3640995..160f2cf0 100644 --- a/pr/src/md/windows/ntio.c +++ b/pr/src/md/windows/ntio.c @@ -35,6 +35,7 @@ */ #include "primpl.h" +#include "pprmwait.h" #include <direct.h> static HANDLE _pr_completion_port; @@ -45,12 +46,9 @@ static struct _MDLock _pr_recycle_lock; static PRInt32 _pr_recycle_array[RECYCLE_SIZE]; static PRInt32 _pr_recycle_tail = 0; -#ifdef _PR_USE_STATIC_TLS __declspec(thread) PRThread *_pr_io_restarted_io = NULL; -#else DWORD _pr_io_restartedIOIndex; /* The thread local storage slot for each * thread is initialized to NULL. */ -#endif PRBool _nt_version_gets_lockfile_completion; @@ -76,7 +74,6 @@ PRBool IsFileLocalInit(); PRInt32 IsFileLocal(HANDLE hFile); #endif /* _NEED_351_FILE_LOCKING_HACK */ -static PRInt32 _md_Associate(HANDLE); static PRInt32 _md_MakeNonblock(HANDLE); /* The _nt_use_async flag is used to prevent nspr from using any async io. @@ -189,7 +186,7 @@ _PR_MD_PAUSE_CPU(PRIntervalTime ticks) unsigned long bytes, key; int rv; LPOVERLAPPED olp; - PRThread *completed_io; + _MDOverlapped *mdOlp; PRUint32 timeout; if (_nt_idleCount > 0) { @@ -259,84 +256,151 @@ _PR_MD_PAUSE_CPU(PRIntervalTime ticks) if (olp == NULL) return 0; - completed_io = _PR_THREAD_MD_TO_PTR(olp); - completed_io->md.blocked_io_status = rv; - if (rv == 0) - completed_io->md.blocked_io_error = GetLastError(); - completed_io->md.blocked_io_bytes = bytes; - - if ( !_PR_IS_NATIVE_THREAD(completed_io) ) { - int pri = completed_io->priority; - _PRCPU *lockedCPU = _PR_MD_CURRENT_CPU(); - - /* The KEY_CVAR notification only occurs when a native thread - * is notifying a user thread. For user-user notifications - * the wakeup occurs by having the notifier place the thread - * on the runq directly; for native-native notifications the - * wakeup occurs by calling ReleaseSemaphore. - */ - if ( key == KEY_CVAR ) { - PR_ASSERT(completed_io->io_pending == PR_FALSE || completed_io->io_suspended == PR_TRUE); - - /* Thread has already been deleted from sleepQ */ - - /* Switch CPU and add to runQ */ - completed_io->cpu = lockedCPU; - completed_io->state = _PR_RUNNABLE; - _PR_RUNQ_LOCK(lockedCPU); - _PR_ADD_RUNQ(completed_io, lockedCPU, pri); - _PR_RUNQ_UNLOCK(lockedCPU); - } else { - PR_ASSERT(key == KEY_IO); - PR_ASSERT(completed_io->io_pending == PR_TRUE); - - _PR_THREAD_LOCK(completed_io); - - completed_io->io_pending = PR_FALSE; - - /* If io_suspended is true, then this IO has already resumed. - * We don't need to do anything; because the thread is - * already running. - */ - if (completed_io->io_suspended == PR_FALSE) { - if (completed_io->flags & (_PR_ON_SLEEPQ|_PR_ON_PAUSEQ)) { - _PR_SLEEPQ_LOCK(completed_io->cpu); - _PR_DEL_SLEEPQ(completed_io, PR_TRUE); - _PR_SLEEPQ_UNLOCK(completed_io->cpu); - - _PR_THREAD_UNLOCK(completed_io); - - completed_io->cpu = lockedCPU; - completed_io->state = _PR_RUNNABLE; + mdOlp = (_MDOverlapped *)olp; + + if (mdOlp->ioModel == _MD_MultiWaitIO) { + PRRecvWait *desc; + PRWaitGroup *group; + PRThread *thred = NULL; + PRMWStatus mwstatus; + + desc = mdOlp->data.mw.desc; + PR_ASSERT(desc != NULL); + mwstatus = rv ? PR_MW_SUCCESS : PR_MW_FAILURE; + if (InterlockedCompareExchange((PVOID *)&desc->outcome, + (PVOID)mwstatus, (PVOID)PR_MW_PENDING) + == (PVOID)PR_MW_PENDING) { + if (mwstatus == PR_MW_SUCCESS) { + desc->bytesRecv = bytes; + } else { + mdOlp->data.mw.error = GetLastError(); + } + } + group = mdOlp->data.mw.group; + PR_ASSERT(group != NULL); + + _PR_MD_LOCK(&group->mdlock); + PR_APPEND_LINK(&mdOlp->data.mw.links, &group->io_ready); + PR_ASSERT(desc->fd != NULL); + NT_HashRemoveInternal(group, desc->fd); + if (!PR_CLIST_IS_EMPTY(&group->wait_list)) { + thred = _PR_THREAD_CONDQ_PTR(PR_LIST_HEAD(&group->wait_list)); + PR_REMOVE_LINK(&thred->waitQLinks); + } + _PR_MD_UNLOCK(&group->mdlock); + + if (thred) { + if (!_PR_IS_NATIVE_THREAD(thred)) { + int pri = thred->priority; + _PRCPU *lockedCPU = _PR_MD_CURRENT_CPU(); + _PR_THREAD_LOCK(thred); + if (thred->flags & _PR_ON_PAUSEQ) { + _PR_SLEEPQ_LOCK(thred->cpu); + _PR_DEL_SLEEPQ(thred, PR_TRUE); + _PR_SLEEPQ_UNLOCK(thred->cpu); + _PR_THREAD_UNLOCK(thred); + thred->cpu = lockedCPU; + thred->state = _PR_RUNNABLE; _PR_RUNQ_LOCK(lockedCPU); - _PR_ADD_RUNQ(completed_io, lockedCPU, pri); + _PR_ADD_RUNQ(thred, lockedCPU, pri); _PR_RUNQ_UNLOCK(lockedCPU); } else { - _PR_THREAD_UNLOCK(completed_io); + /* + * The thread was just interrupted and moved + * from the pause queue to the run queue. + */ + _PR_THREAD_UNLOCK(thred); } } else { - _PR_THREAD_UNLOCK(completed_io); + _PR_THREAD_LOCK(thred); + thred->state = _PR_RUNNABLE; + _PR_THREAD_UNLOCK(thred); + ReleaseSemaphore(thred->md.blocked_sema, 1, NULL); } } } else { - int old_count; - PRBool fNeedRelease = PR_FALSE; + PRThread *completed_io; + + PR_ASSERT(mdOlp->ioModel == _MD_BlockingIO); + completed_io = _PR_THREAD_MD_TO_PTR(mdOlp->data.mdThread); + completed_io->md.blocked_io_status = rv; + if (rv == 0) + completed_io->md.blocked_io_error = GetLastError(); + completed_io->md.blocked_io_bytes = bytes; + + if ( !_PR_IS_NATIVE_THREAD(completed_io) ) { + int pri = completed_io->priority; + _PRCPU *lockedCPU = _PR_MD_CURRENT_CPU(); + + /* The KEY_CVAR notification only occurs when a native thread + * is notifying a user thread. For user-user notifications + * the wakeup occurs by having the notifier place the thread + * on the runq directly; for native-native notifications the + * wakeup occurs by calling ReleaseSemaphore. + */ + if ( key == KEY_CVAR ) { + PR_ASSERT(completed_io->io_pending == PR_FALSE || completed_io->io_suspended == PR_TRUE); - /* For native threads, they are only notified through this loop - * when completing IO. So, don't worry about this being a CVAR - * notification, because that is not possible. - */ - _PR_THREAD_LOCK(completed_io); - completed_io->io_pending = PR_FALSE; - if (completed_io->io_suspended == PR_FALSE) { - completed_io->state = _PR_RUNNABLE; - fNeedRelease = PR_TRUE; - } - _PR_THREAD_UNLOCK(completed_io); - if (fNeedRelease) { - rv = ReleaseSemaphore(completed_io->md.blocked_sema, - 1, &old_count); - PR_ASSERT(0 != rv); + /* Thread has already been deleted from sleepQ */ + + /* Switch CPU and add to runQ */ + completed_io->cpu = lockedCPU; + completed_io->state = _PR_RUNNABLE; + _PR_RUNQ_LOCK(lockedCPU); + _PR_ADD_RUNQ(completed_io, lockedCPU, pri); + _PR_RUNQ_UNLOCK(lockedCPU); + } else { + PR_ASSERT(key == KEY_IO); + PR_ASSERT(completed_io->io_pending == PR_TRUE); + + _PR_THREAD_LOCK(completed_io); + + completed_io->io_pending = PR_FALSE; + + /* If io_suspended is true, then this IO has already resumed. + * We don't need to do anything; because the thread is + * already running. + */ + if (completed_io->io_suspended == PR_FALSE) { + if (completed_io->flags & (_PR_ON_SLEEPQ|_PR_ON_PAUSEQ)) { + _PR_SLEEPQ_LOCK(completed_io->cpu); + _PR_DEL_SLEEPQ(completed_io, PR_TRUE); + _PR_SLEEPQ_UNLOCK(completed_io->cpu); + + _PR_THREAD_UNLOCK(completed_io); + + completed_io->cpu = lockedCPU; + completed_io->state = _PR_RUNNABLE; + _PR_RUNQ_LOCK(lockedCPU); + _PR_ADD_RUNQ(completed_io, lockedCPU, pri); + _PR_RUNQ_UNLOCK(lockedCPU); + } else { + _PR_THREAD_UNLOCK(completed_io); + } + } else { + _PR_THREAD_UNLOCK(completed_io); + } + } + } else { + int old_count; + PRBool fNeedRelease = PR_FALSE; + + /* For native threads, they are only notified through this loop + * when completing IO. So, don't worry about this being a CVAR + * notification, because that is not possible. + */ + _PR_THREAD_LOCK(completed_io); + completed_io->io_pending = PR_FALSE; + if (completed_io->io_suspended == PR_FALSE) { + completed_io->state = _PR_RUNNABLE; + fNeedRelease = PR_TRUE; + } + _PR_THREAD_UNLOCK(completed_io); + if (fNeedRelease) { + rv = ReleaseSemaphore(completed_io->md.blocked_sema, + 1, &old_count); + PR_ASSERT(0 != rv); + } } } @@ -400,13 +464,7 @@ _PR_MD_WAIT(PRThread *thread, PRIntervalTime ticks) } else { PRInt32 is; - /* XXXMB - This is barely safe, but works. We should find a - * way to make all callers of PR_MD_WAIT zero the overlapped buffer - * themselves... - */ - if (thread->state != _PR_IO_WAIT) - memset(&(thread->md.overlapped), 0, sizeof(OVERLAPPED)); - if ( !_PR_IS_NATIVE_THREAD(thread)) _PR_INTSOFF(is); + _PR_INTSOFF(is); _PR_MD_SWITCH_CONTEXT(thread); } @@ -477,11 +535,11 @@ _NT_ResumeIO(PRThread *thread, PRIntervalTime ticks) PRBool fWait = PR_TRUE; if (!_PR_IS_NATIVE_THREAD(thread)) { -#ifdef _PR_USE_STATIC_TLS - _pr_io_restarted_io = thread; -#else - TlsSetValue(_pr_io_restartedIOIndex, thread); -#endif + if (_pr_use_static_tls) { + _pr_io_restarted_io = thread; + } else { + TlsSetValue(_pr_io_restartedIOIndex, thread); + } } else { _PR_THREAD_LOCK(thread); if (!thread->io_pending) @@ -534,7 +592,7 @@ _PR_MD_WAKEUP_WAITER(PRThread *thread) /* The thread should not be in any queue */ PR_ASSERT(thread->queueCount == 0); if ( PostQueuedCompletionStatus(_pr_completion_port, 0, - KEY_CVAR, &(thread->md.overlapped)) == FALSE) + KEY_CVAR, &(thread->md.overlapped.overlapped)) == FALSE) return PR_FAILURE; } return PR_SUCCESS; @@ -675,7 +733,7 @@ _md_put_recycled_socket(SOCKET newsock) * Associates a file with the completion port. * Returns 0 on failure, 1 on success. */ -static PRInt32 +PRInt32 _md_Associate(HANDLE file) { HANDLE port; @@ -873,7 +931,10 @@ _PR_MD_CONNECT(PRFileDesc *fd, const PRNetAddr *addr, PRUint32 addrlen, FD_SET((SOCKET)osfd, &wd); rv = select(osfd + 1, NULL, &wd, NULL, tvp); if (rv > 0) { - rv = 0; + /* + * Call Sleep(0) to work around a Winsock timing bug. + */ + Sleep(0); } else if (rv == 0) { PR_SetError(PR_IO_TIMEOUT_ERROR, 0); return(-1); @@ -1021,6 +1082,11 @@ _PR_MD_FAST_ACCEPT(PRFileDesc *fd, PRNetAddr *raddr, PRUint32 *rlen, return _nt_nonblock_accept(fd, (struct sockaddr_in *)raddr, rlen, timeout); } + if (me->io_suspended) { + PR_SetError(PR_INVALID_STATE_ERROR, 0); + return -1; + } + if (!fd->secret->md.io_model_committed) { rv = _md_Associate((HANDLE)osfd); PR_ASSERT(0 != rv); @@ -1039,10 +1105,8 @@ _PR_MD_FAST_ACCEPT(PRFileDesc *fd, PRNetAddr *raddr, PRUint32 *rlen, if (accept_sock == INVALID_SOCKET) return -1; - memset(&(me->md.overlapped), 0, sizeof(OVERLAPPED)); + memset(&(me->md.overlapped.overlapped), 0, sizeof(OVERLAPPED)); - PR_ASSERT(me->io_suspended == PR_FALSE); - me->io_pending = PR_TRUE; me->io_fd = osfd; me->state = _PR_IO_WAIT; @@ -1053,7 +1117,7 @@ _PR_MD_FAST_ACCEPT(PRFileDesc *fd, PRNetAddr *raddr, PRUint32 *rlen, INET_ADDR_PADDED, INET_ADDR_PADDED, &bytes, - &(me->md.overlapped)); + &(me->md.overlapped.overlapped)); if ( (rv == 0) && ((err = GetLastError()) != ERROR_IO_PENDING)) { /* Argh! The IO failed */ @@ -1110,7 +1174,7 @@ _PR_MD_FAST_ACCEPT(PRFileDesc *fd, PRNetAddr *raddr, PRUint32 *rlen, PRInt32 _PR_MD_FAST_ACCEPT_READ(PRFileDesc *sd, PRInt32 *newSock, PRNetAddr **raddr, void *buf, PRInt32 amount, PRIntervalTime timeout, - PRBool update, _PR_AcceptTimeoutCallback callback, + PRBool fast, _PR_AcceptTimeoutCallback callback, void *callbackArg) { PRInt32 sock = sd->secret->md.osfd; @@ -1132,12 +1196,16 @@ _PR_MD_FAST_ACCEPT_READ(PRFileDesc *sd, PRInt32 *newSock, PRNetAddr **raddr, */ PR_ASSERT(nd->secret->state == _PR_FILEDESC_OPEN); *newSock = nd->secret->md.osfd; - nd->secret->state = _PR_FILEDESC_CLOSED; PR_FreeFileDesc(nd); } return bytes; } + if (me->io_suspended) { + PR_SetError(PR_INVALID_STATE_ERROR, 0); + return -1; + } + if (!sd->secret->md.io_model_committed) { rv = _md_Associate((HANDLE)sock); PR_ASSERT(0 != rv); @@ -1148,10 +1216,8 @@ _PR_MD_FAST_ACCEPT_READ(PRFileDesc *sd, PRInt32 *newSock, PRNetAddr **raddr, if (*newSock == INVALID_SOCKET) return -1; - memset(&(me->md.overlapped), 0, sizeof(OVERLAPPED)); + memset(&(me->md.overlapped.overlapped), 0, sizeof(OVERLAPPED)); - PR_ASSERT(me->io_suspended == PR_FALSE); - me->io_pending = PR_TRUE; me->io_fd = sock; me->state = _PR_IO_WAIT; @@ -1162,7 +1228,7 @@ _PR_MD_FAST_ACCEPT_READ(PRFileDesc *sd, PRInt32 *newSock, PRNetAddr **raddr, INET_ADDR_PADDED, INET_ADDR_PADDED, &bytes, - &(me->md.overlapped)); + &(me->md.overlapped.overlapped)); if ( (rv == 0) && ((err = GetLastError()) != ERROR_IO_PENDING)) { me->io_pending = PR_FALSE; @@ -1249,7 +1315,7 @@ retry: return -1; } - if (update) + if (!fast) _PR_MD_UPDATE_ACCEPT_CONTEXT((SOCKET)*newSock, (SOCKET)sock); /* IO is done */ @@ -1285,6 +1351,11 @@ _PR_MD_TRANSMITFILE(PRFileDesc *sock, PRFileDesc *file, const void *headers, PRI return _PR_EmulateTransmitFile(sock, file, headers, hlen, flags, timeout); } + if (me->io_suspended) { + PR_SetError(PR_INVALID_STATE_ERROR, 0); + return -1; + } + if (!sock->secret->md.io_model_committed) { rv = _md_Associate((HANDLE)sock->secret->md.osfd); PR_ASSERT(0 != rv); @@ -1302,9 +1373,7 @@ _PR_MD_TRANSMITFILE(PRFileDesc *sock, PRFileDesc *file, const void *headers, PRI me->md.xmit_bufs->Tail = (void *)NULL; me->md.xmit_bufs->TailLength = 0; - memset(&(me->md.overlapped), 0, sizeof(OVERLAPPED)); - - PR_ASSERT(me->io_suspended == PR_FALSE); + memset(&(me->md.overlapped.overlapped), 0, sizeof(OVERLAPPED)); tflags = 0; if (flags & PR_TRANSMITFILE_CLOSE_SOCKET) @@ -1317,7 +1386,7 @@ _PR_MD_TRANSMITFILE(PRFileDesc *sock, PRFileDesc *file, const void *headers, PRI (HANDLE)file->secret->md.osfd, (DWORD)0, (DWORD)0, - (LPOVERLAPPED)&(me->md.overlapped), + (LPOVERLAPPED)&(me->md.overlapped.overlapped), (TRANSMIT_FILE_BUFFERS *)me->md.xmit_bufs, (DWORD)tflags); if ( (rv == 0) && ((err = GetLastError()) != ERROR_IO_PENDING) ) { @@ -1376,15 +1445,18 @@ _PR_MD_RECV(PRFileDesc *fd, void *buf, PRInt32 amount, PRIntn flags, return _nt_nonblock_recv(fd, buf, amount, timeout); } + if (me->io_suspended) { + PR_SetError(PR_INVALID_STATE_ERROR, 0); + return -1; + } + if (!fd->secret->md.io_model_committed) { rv = _md_Associate((HANDLE)osfd); PR_ASSERT(0 != rv); fd->secret->md.io_model_committed = PR_TRUE; } - memset(&(me->md.overlapped), 0, sizeof(OVERLAPPED)); - - PR_ASSERT(me->io_suspended == PR_FALSE); + memset(&(me->md.overlapped.overlapped), 0, sizeof(OVERLAPPED)); me->io_pending = PR_TRUE; me->io_fd = osfd; @@ -1393,7 +1465,7 @@ _PR_MD_RECV(PRFileDesc *fd, void *buf, PRInt32 amount, PRIntn flags, buf, amount, &bytes, - &(me->md.overlapped)); + &(me->md.overlapped.overlapped)); if ( (rv == 0) && (GetLastError() != ERROR_IO_PENDING) ) { me->io_pending = PR_FALSE; me->state = _PR_RUNNING; @@ -1450,15 +1522,18 @@ _PR_MD_SEND(PRFileDesc *fd, const void *buf, PRInt32 amount, PRIntn flags, return _nt_nonblock_send(fd, (char *)buf, amount, timeout); } + if (me->io_suspended) { + PR_SetError(PR_INVALID_STATE_ERROR, 0); + return -1; + } + if (!fd->secret->md.io_model_committed) { rv = _md_Associate((HANDLE)osfd); PR_ASSERT(0 != rv); fd->secret->md.io_model_committed = PR_TRUE; } - memset(&(me->md.overlapped), 0, sizeof(OVERLAPPED)); - - PR_ASSERT(me->io_suspended == PR_FALSE); + memset(&(me->md.overlapped.overlapped), 0, sizeof(OVERLAPPED)); me->io_pending = PR_TRUE; me->io_fd = osfd; @@ -1467,7 +1542,7 @@ _PR_MD_SEND(PRFileDesc *fd, const void *buf, PRInt32 amount, PRIntn flags, buf, amount, &bytes, - &(me->md.overlapped)); + &(me->md.overlapped.overlapped)); if ( (rv == 0) && ((err = GetLastError()) != ERROR_IO_PENDING) ) { me->io_pending = PR_FALSE; me->state = _PR_RUNNING; @@ -1777,11 +1852,14 @@ _PR_MD_READ(PRFileDesc *fd, void *buf, PRInt32 len) if (_nt_use_async && !fd->secret->md.nonoverlapped) { PRThread *me = _PR_MD_CURRENT_THREAD(); - memset(&(me->md.overlapped), 0, sizeof(OVERLAPPED)); + if (me->io_suspended) { + PR_SetError(PR_INVALID_STATE_ERROR, 0); + return -1; + } - PR_ASSERT(me->io_suspended == PR_FALSE); + memset(&(me->md.overlapped.overlapped), 0, sizeof(OVERLAPPED)); - me->md.overlapped.Offset = SetFilePointer((HANDLE)f, 0, 0, FILE_CURRENT); + me->md.overlapped.overlapped.Offset = SetFilePointer((HANDLE)f, 0, 0, FILE_CURRENT); me->io_pending = PR_TRUE; me->io_fd = f; @@ -1790,7 +1868,7 @@ _PR_MD_READ(PRFileDesc *fd, void *buf, PRInt32 len) (LPVOID)buf, len, &bytes, - &me->md.overlapped); + &me->md.overlapped.overlapped); if ( (rv == 0) && ((err = GetLastError()) != ERROR_IO_PENDING) ) { me->io_pending = PR_FALSE; me->state = _PR_RUNNING; @@ -1857,14 +1935,18 @@ _PR_MD_WRITE(PRFileDesc *fd, void *buf, PRInt32 len) PRInt32 f = fd->secret->md.osfd; PRInt32 bytes; int rv, err; - PRThread *me = _PR_MD_CURRENT_THREAD(); if (_nt_use_async && !fd->secret->md.nonoverlapped) { - memset(&(me->md.overlapped), 0, sizeof(OVERLAPPED)); + PRThread *me = _PR_MD_CURRENT_THREAD(); + + if (me->io_suspended) { + PR_SetError(PR_INVALID_STATE_ERROR, 0); + return -1; + } - PR_ASSERT(me->io_suspended == PR_FALSE); + memset(&(me->md.overlapped.overlapped), 0, sizeof(OVERLAPPED)); - me->md.overlapped.Offset = SetFilePointer((HANDLE)f, 0, 0, FILE_CURRENT); + me->md.overlapped.overlapped.Offset = SetFilePointer((HANDLE)f, 0, 0, FILE_CURRENT); me->io_pending = PR_TRUE; me->io_fd = f; @@ -1873,7 +1955,7 @@ _PR_MD_WRITE(PRFileDesc *fd, void *buf, PRInt32 len) buf, len, &bytes, - &(me->md.overlapped)); + &(me->md.overlapped.overlapped)); if ( (rv == 0) && ((err = GetLastError()) != ERROR_IO_PENDING) ) { me->io_pending = PR_FALSE; me->state = _PR_RUNNING; @@ -1953,23 +2035,44 @@ _PR_MD_LSEEK(PRFileDesc *fd, PRInt32 offset, int whence) PRInt64 _PR_MD_LSEEK64(PRFileDesc *fd, PRInt64 offset, int whence) { - PRInt64 result; - PRInt32 rv, low = (PRInt32)offset, hi = (PRInt32)(offset >> 32); + PRUint64 result; + PRUint32 position, uhi; + PRInt32 low = (PRInt32)offset, hi = (PRInt32)(offset >> 32); - rv = SetFilePointer((HANDLE)fd->secret->md.osfd, low, &hi, whence); + position = SetFilePointer((HANDLE)fd->secret->md.osfd, low, &hi, whence); /* - * If the lpDistanceToMoveHigh argument (third argument) is - * NULL, SetFilePointer returns 0xffffffff on failure. + * The lpDistanceToMoveHigh argument (third argument) is not + * NULL. Therefore, a -1 (unsigned) result is ambiguious. If + * the result just happens to be -1, also test to see if the + * last error is non-zero. If it is, the operation failed. + * Otherwise, the -1 is just the low half of the 64 bit position. */ - if (-1 == rv) + if (0xffffffff == position) { - _PR_MD_MAP_LSEEK_ERROR(GetLastError()); - return -1; + PRInt32 oserr = GetLastError(); + if (0 != oserr) + { + _PR_MD_MAP_LSEEK_ERROR(oserr); + return -1; + } } - result = (hi << 32) + rv; - return result; + /* + ** All this 'cause we keep extending the sign of rv into + ** the high bits of the result. We just know that the final + ** position of the file must be positive and probably nowhere + ** close to the maximum value of a PRUint64. + */ + uhi = (PRUint32)hi; + PR_ASSERT((PRInt32)uhi >= 0); + result = uhi; + PR_ASSERT((PRInt64)result >= 0); + result = (result << 32); + PR_ASSERT((PRInt64)result >= 0); + result += position; + PR_ASSERT((PRInt64)result >= 0); + return (PRInt64)result; } /* @@ -2601,9 +2704,12 @@ _PR_MD_LOCKFILE(PRInt32 f) PRInt32 rv, err; PRThread *me = _PR_MD_CURRENT_THREAD(); - memset(&(me->md.overlapped), 0, sizeof(OVERLAPPED)); + if (me->io_suspended) { + PR_SetError(PR_INVALID_STATE_ERROR, 0); + return PR_FAILURE; + } - PR_ASSERT(me->io_suspended == PR_FALSE); + memset(&(me->md.overlapped.overlapped), 0, sizeof(OVERLAPPED)); me->state = _PR_IO_WAIT; me->io_pending = PR_TRUE; @@ -2612,7 +2718,7 @@ _PR_MD_LOCKFILE(PRInt32 f) 0, 0x7fffffff, 0, - &me->md.overlapped); + &me->md.overlapped.overlapped); /* HACK AROUND NT BUG * NT 3.51 has a bug. In NT 3.51, if LockFileEx returns true, you @@ -2676,9 +2782,12 @@ _PR_MD_TLOCKFILE(PRInt32 f) PRInt32 rv, err; PRThread *me = _PR_MD_CURRENT_THREAD(); - memset(&(me->md.overlapped), 0, sizeof(OVERLAPPED)); + if (me->io_suspended) { + PR_SetError(PR_INVALID_STATE_ERROR, 0); + return PR_FAILURE; + } - PR_ASSERT(me->io_suspended == PR_FALSE); + memset(&(me->md.overlapped.overlapped), 0, sizeof(OVERLAPPED)); me->state = _PR_IO_WAIT; me->io_pending = PR_TRUE; @@ -2687,7 +2796,7 @@ _PR_MD_TLOCKFILE(PRInt32 f) 0, 0x7fffffff, 0, - &me->md.overlapped); + &me->md.overlapped.overlapped); if ( rv == FALSE && ((err = GetLastError()) != ERROR_IO_PENDING)) { me->io_pending = PR_FALSE; me->state = _PR_RUNNING; @@ -2730,15 +2839,18 @@ _PR_MD_UNLOCKFILE(PRInt32 f) PRInt32 rv; PRThread *me = _PR_MD_CURRENT_THREAD(); - memset(&(me->md.overlapped), 0, sizeof(OVERLAPPED)); + if (me->io_suspended) { + PR_SetError(PR_INVALID_STATE_ERROR, 0); + return PR_FAILURE; + } - PR_ASSERT(me->io_suspended == PR_FALSE); + memset(&(me->md.overlapped.overlapped), 0, sizeof(OVERLAPPED)); rv = UnlockFileEx((HANDLE)f, 0, 0x7fffffff, 0, - &me->md.overlapped); + &me->md.overlapped.overlapped); if (rv) return PR_SUCCESS; @@ -3750,7 +3862,7 @@ static PRInt32 pt_SendTo( op.arg2.buffer = (void*)buf; op.arg3.amount = amount; op.arg4.flags = flags; - op.arg5.addr = addr; + op.arg5.addr = (PRNetAddr*)addr; op.timeout = timeout; op.result.code = 0; /* initialize the number sent */ op.function = pt_sendto_cont; diff --git a/pr/src/md/windows/ntmisc.c b/pr/src/md/windows/ntmisc.c index 28eff1e9..869bc897 100644 --- a/pr/src/md/windows/ntmisc.c +++ b/pr/src/md/windows/ntmisc.c @@ -354,6 +354,7 @@ PRProcess * _PR_CreateWindowsProcess( char *cmdLine = NULL; char *envBlock = NULL; char **newEnvp; + char *cwd = NULL; /* current working directory */ PRProcess *proc = NULL; proc = PR_NEW(PRProcess); @@ -415,6 +416,7 @@ PRProcess * _PR_CreateWindowsProcess( if (redirected) { startupInfo.dwFlags |= STARTF_USESTDHANDLES; } + cwd = attr->currentDirectory; } retVal = CreateProcess(NULL, @@ -431,7 +433,7 @@ PRProcess * _PR_CreateWindowsProcess( * string is in the form: * name=value * XXX: usually NULL */ - attr->currentDirectory, /* current drive and directory */ + cwd, /* current drive and directory */ &startupInfo, &procInfo ); @@ -648,4 +650,70 @@ PRInt32 _PR_MD_ATOMIC_DECREMENT(PRInt32 *val) } #pragma warning(default: 4035) +#pragma warning(disable: 4035) +PRInt32 _PR_MD_ATOMIC_ADD(PRInt32 *intp, PRInt32 val) +{ + __asm + { + mov ecx, intp + mov eax, val + mov ebx, val + lock xadd dword ptr [ecx], eax + add eax, ebx + } +} +#pragma warning(default: 4035) + +#ifdef _PR_HAVE_ATOMIC_CAS + +#pragma warning(disable: 4035) +void +PR_StackPush(PRStack *stack, PRStackElem *stack_elem) +{ + __asm + { + mov ebx, stack + mov ecx, stack_elem +retry: mov eax,[ebx] + cmp eax,-1 + je retry + mov eax,-1 + xchg dword ptr [ebx], eax + cmp eax,-1 + je retry + mov [ecx],eax + mov [ebx],ecx + } +} +#pragma warning(default: 4035) + +#pragma warning(disable: 4035) +PRStackElem * +PR_StackPop(PRStack *stack) +{ + __asm + { + mov ebx, stack +retry: mov eax,[ebx] + cmp eax,-1 + je retry + mov eax,-1 + xchg dword ptr [ebx], eax + cmp eax,-1 + je retry + cmp eax,0 + je empty + mov ecx,[eax] + mov [ebx],ecx + mov [eax],0 + jmp done +empty: + mov [ebx],eax +done: + } +} +#pragma warning(default: 4035) + +#endif /* _PR_HAVE_ATOMIC_CAS */ + #endif /* x86 processors */ diff --git a/pr/src/md/windows/ntthread.c b/pr/src/md/windows/ntthread.c index d751581b..1f6de5ac 100644 --- a/pr/src/md/windows/ntthread.c +++ b/pr/src/md/windows/ntthread.c @@ -25,46 +25,34 @@ extern void _PR_Win32InitTimeZone(void); /* defined in ntmisc.c */ PRLock *_pr_schedLock = NULL; _PRInterruptTable _pr_interruptTable[] = { { 0 } }; -#ifdef _PR_USE_STATIC_TLS +BOOL _pr_use_static_tls = TRUE; __declspec(thread) PRThread *_pr_current_fiber; __declspec(thread) PRThread *_pr_fiber_last_run; __declspec(thread) _PRCPU *_pr_current_cpu; __declspec(thread) PRUintn _pr_ints_off; -#else /* _PR_USE_STATIC_TLS */ DWORD _pr_currentFiberIndex; DWORD _pr_lastFiberIndex; DWORD _pr_currentCPUIndex; DWORD _pr_intsOffIndex; -#endif /* _PR_USE_STATIC_TLS */ _MDLock _nt_idleLock; PRCList _nt_idleList; PRUint32 _nt_idleCount; -#ifdef _PR_USE_STATIC_TLS - extern __declspec(thread) PRThread *_pr_io_restarted_io; - -/* Must check the restarted_io *before* decrementing no_sched to 0 */ -#define POST_SWITCH_WORK() \ - if (_pr_io_restarted_io) \ - _nt_handle_restarted_io(_pr_io_restarted_io); \ - _PR_MD_LAST_THREAD()->no_sched = 0; - -#else /* _PR_USE_STATIC_TLS */ - extern DWORD _pr_io_restartedIOIndex; /* Must check the restarted_io *before* decrementing no_sched to 0 */ #define POST_SWITCH_WORK() \ -PR_BEGIN_MACRO \ - PRThread *restarted_io = (PRThread *) TlsGetValue(_pr_io_restartedIOIndex); \ - if (restarted_io) \ - _nt_handle_restarted_io(restarted_io); \ - _PR_MD_LAST_THREAD()->no_sched = 0; \ -PR_END_MACRO - -#endif /* _PR_USE_STATIC_TLS */ + PR_BEGIN_MACRO \ + PRThread *restarted_io = \ + (_pr_use_static_tls ? _pr_io_restarted_io \ + : (PRThread *) TlsGetValue(_pr_io_restartedIOIndex)); \ + if (restarted_io) { \ + _nt_handle_restarted_io(restarted_io); \ + } \ + _PR_MD_LAST_THREAD()->no_sched = 0; \ + PR_END_MACRO void _nt_handle_restarted_io(PRThread *restarted_io) @@ -94,11 +82,11 @@ _nt_handle_restarted_io(PRThread *restarted_io) _PR_THREAD_UNLOCK(restarted_io); -#ifdef _PR_USE_STATIC_TLS - _pr_io_restarted_io = NULL; -#else - TlsSetValue(_pr_io_restartedIOIndex, NULL); -#endif + if (_pr_use_static_tls) { + _pr_io_restarted_io = NULL; + } else { + TlsSetValue(_pr_io_restartedIOIndex, NULL); + } } void @@ -117,26 +105,26 @@ _PR_MD_EARLY_INIT() } #endif -#ifndef _PR_USE_STATIC_TLS - _pr_currentFiberIndex = TlsAlloc(); - _pr_lastFiberIndex = TlsAlloc(); - _pr_currentCPUIndex = TlsAlloc(); - _pr_intsOffIndex = TlsAlloc(); - _pr_io_restartedIOIndex = TlsAlloc(); -#endif + if (!_pr_use_static_tls) { + _pr_currentFiberIndex = TlsAlloc(); + _pr_lastFiberIndex = TlsAlloc(); + _pr_currentCPUIndex = TlsAlloc(); + _pr_intsOffIndex = TlsAlloc(); + _pr_io_restartedIOIndex = TlsAlloc(); + } } void _PR_MD_CLEANUP_BEFORE_EXIT(void) { WSACleanup(); -#ifndef _PR_USE_STATIC_TLS - TlsFree(_pr_currentFiberIndex); - TlsFree(_pr_lastFiberIndex); - TlsFree(_pr_currentCPUIndex); - TlsFree(_pr_intsOffIndex); - TlsFree(_pr_io_restartedIOIndex); -#endif + if (!_pr_use_static_tls) { + TlsFree(_pr_currentFiberIndex); + TlsFree(_pr_lastFiberIndex); + TlsFree(_pr_currentCPUIndex); + TlsFree(_pr_intsOffIndex); + TlsFree(_pr_io_restartedIOIndex); + } } void @@ -162,6 +150,8 @@ _PR_MD_INIT_PRIMORDIAL_THREAD(PRThread *thread) PRStatus _PR_MD_INIT_THREAD(PRThread *thread) { + thread->md.overlapped.ioModel = _MD_BlockingIO; + thread->md.overlapped.data.mdThread = &thread->md; /* Create the blocking IO semaphore */ thread->md.blocked_sema = CreateSemaphore(NULL, 0, 1, NULL); if (thread->md.blocked_sema == NULL) @@ -479,3 +469,18 @@ _PR_MD_RESUME_THREAD(PRThread *thread) } } +PRThread* +_MD_CURRENT_THREAD(void) +{ +PRThread *thread; + + thread = _MD_GET_ATTACHED_THREAD(); + + if (NULL == thread) { + thread = _PRI_AttachThread( + PR_USER_THREAD, PR_PRIORITY_NORMAL, NULL, 0); + } + PR_ASSERT(thread != NULL); + return thread; +} + diff --git a/pr/src/md/windows/w16callb.c b/pr/src/md/windows/w16callb.c index d25f7c19..9c9a4a79 100644 --- a/pr/src/md/windows/w16callb.c +++ b/pr/src/md/windows/w16callb.c @@ -233,7 +233,7 @@ int PR_MD_fprintf(FILE *fPtr, const char *fmt, ...) } else { - fwrite(buffer, 0, strlen(buffer), fPtr); /* XXX Is this a sec. hole? */ + fwrite(buffer, 1, strlen(buffer), fPtr); /* XXX Is this a sec. hole? */ } va_end(args); diff --git a/pr/src/md/windows/w16mem.c b/pr/src/md/windows/w16mem.c index f1fe6a08..dac82384 100644 --- a/pr/src/md/windows/w16mem.c +++ b/pr/src/md/windows/w16mem.c @@ -46,7 +46,6 @@ PRStatus _MD_AllocSegment(PRSegment *seg, PRUint32 size, void *vaddr) return PR_FAILURE; } - seg->access = PR_SEGMENT_RDWR; seg->size = size; return PR_SUCCESS; diff --git a/pr/src/md/windows/w32poll.c b/pr/src/md/windows/w32poll.c index e71fd936..5b73124d 100644 --- a/pr/src/md/windows/w32poll.c +++ b/pr/src/md/windows/w32poll.c @@ -45,55 +45,153 @@ _PR_MD_select_thread(void *cdata) #endif /* !defined(_PR_GLOBAL_THREADS_ONLY) */ -PRInt32 -_PR_MD_PR_POLL(PRPollDesc *pds, PRIntn npds, PRIntervalTime timeout) +PRInt32 _PR_MD_PR_POLL(PRPollDesc *pds, PRIntn npds, PRIntervalTime timeout) { + int ready, err; + fd_set rd, wt, ex; + PRFileDesc *bottom; PRPollDesc *pd, *epd; - int n, err; PRThread *me = _PR_MD_CURRENT_THREAD(); - fd_set rd, wt, ex; struct timeval tv, *tvp = NULL; + if (_PR_PENDING_INTERRUPT(me)) + { + me->flags &= ~_PR_INTERRUPT; + PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); + return -1; + } + + /* + ** Is it an empty set? If so, just sleep for the timeout and return + */ + if (0 == npds) + { + PR_Sleep(timeout); + return 0; + } + FD_ZERO(&rd); FD_ZERO(&wt); FD_ZERO(&ex); - for (pd = pds, epd = pd + npds; pd < epd; pd++) { + ready = 0; + for (pd = pds, epd = pd + npds; pd < epd; pd++) + { SOCKET osfd; - PRInt16 in_flags = pd->in_flags; - PRFileDesc *bottom = pd->fd; + PRInt16 in_flags_read = 0, in_flags_write = 0; + PRInt16 out_flags_read = 0, out_flags_write = 0; - if ((NULL == bottom) || (in_flags == 0)) { - continue; - } - while (bottom->lower != NULL) { - bottom = bottom->lower; - } - osfd = (SOCKET) bottom->secret->md.osfd; - - if (in_flags & PR_POLL_READ) { - FD_SET(osfd, &rd); - } - if (in_flags & PR_POLL_WRITE) { - FD_SET(osfd, &wt); - } - if (in_flags & PR_POLL_EXCEPT) { - FD_SET(osfd, &ex); + if ((NULL != pd->fd) && (0 != pd->in_flags)) + { + if (pd->in_flags & PR_POLL_READ) + { + in_flags_read = (pd->fd->methods->poll)( + pd->fd, (PRInt16)(pd->in_flags & ~PR_POLL_WRITE), + &out_flags_read); + } + if (pd->in_flags & PR_POLL_WRITE) + { + in_flags_write = (pd->fd->methods->poll)( + pd->fd, (PRInt16)(pd->in_flags & ~PR_POLL_READ), + &out_flags_write); + } + if ((0 != (in_flags_read & out_flags_read)) + || (0 != (in_flags_write & out_flags_write))) + { + /* this one's ready right now (buffered input) */ + if (0 == ready) + { + /* + * We will have to return without calling the + * system poll/select function. So zero the + * out_flags fields of all the poll descriptors + * before this one. + */ + PRPollDesc *prev; + for (prev = pds; prev < pd; prev++) + { + prev->out_flags = 0; + } + } + ready += 1; + pd->out_flags = out_flags_read | out_flags_write; + } + else + { + pd->out_flags = 0; /* pre-condition */ + /* make sure this is an NSPR supported stack */ + bottom = PR_GetIdentitiesLayer(pd->fd, PR_NSPR_IO_LAYER); + PR_ASSERT(NULL != bottom); /* what to do about that? */ + if ((NULL != bottom) + && (_PR_FILEDESC_OPEN == bottom->secret->state)) + { + if (0 == ready) + { + osfd = (SOCKET) bottom->secret->md.osfd; + if (in_flags_read & PR_POLL_READ) + { + pd->out_flags |= _PR_POLL_READ_SYS_READ; + FD_SET(osfd, &rd); + } + if (in_flags_read & PR_POLL_WRITE) + { + pd->out_flags |= _PR_POLL_READ_SYS_WRITE; + FD_SET(osfd, &wt); + } + if (in_flags_write & PR_POLL_READ) + { + pd->out_flags |= _PR_POLL_WRITE_SYS_READ; + FD_SET(osfd, &rd); + } + if (in_flags_write & PR_POLL_WRITE) + { + pd->out_flags |= _PR_POLL_WRITE_SYS_WRITE; + FD_SET(osfd, &wt); + } + if (pd->in_flags & PR_POLL_EXCEPT) FD_SET(osfd, &ex); + } + } + else + { + if (0 == ready) + { + PRPollDesc *prev; + for (prev = pds; prev < pd; prev++) + { + prev->out_flags = 0; + } + } + ready += 1; /* this will cause an abrupt return */ + pd->out_flags = PR_POLL_NVAL; /* bogii */ + } + } } } - if (timeout != PR_INTERVAL_NO_TIMEOUT) { - tv.tv_sec = PR_IntervalToSeconds(timeout); - tv.tv_usec = PR_IntervalToMicroseconds(timeout) % PR_USEC_PER_SEC; + + if (0 != ready) return ready; /* no need to block */ + + if (timeout != PR_INTERVAL_NO_TIMEOUT) + { + PRInt32 ticksPerSecond = PR_TicksPerSecond(); + tv.tv_sec = timeout / ticksPerSecond; + tv.tv_usec = timeout - (ticksPerSecond * tv.tv_sec); + tv.tv_usec = (PR_USEC_PER_SEC * tv.tv_usec) / ticksPerSecond; tvp = &tv; } #if defined(_PR_GLOBAL_THREADS_ONLY) - n = _MD_SELECT(0, &rd, &wt, &ex, tvp); + ready = _MD_SELECT(0, &rd, &wt, &ex, tvp); #else if (_PR_IS_NATIVE_THREAD(me)) { - n = _MD_SELECT(0, &rd, &wt, &ex, tvp); - } else { + ready = _MD_SELECT(0, &rd, &wt, &ex, tvp); + } + else + { + /* + ** Creating a new thread on each call to Poll()!! + ** I guess web server doesn't use non-block I/O. + */ PRThread *selectThread; struct select_data_s data; data.status = 0; @@ -103,87 +201,88 @@ _PR_MD_PR_POLL(PRPollDesc *pds, PRIntn npds, PRIntervalTime timeout) data.ex = &ex; data.tv = tvp; - selectThread = PR_CreateThread(PR_USER_THREAD, - _PR_MD_select_thread, - &data, - PR_PRIORITY_NORMAL, - PR_GLOBAL_THREAD, - PR_JOINABLE_THREAD, - 0); - if (selectThread == NULL) { - return -1; - } + selectThread = PR_CreateThread( + PR_USER_THREAD, _PR_MD_select_thread, &data, + PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD, PR_JOINABLE_THREAD, 0); + if (selectThread == NULL) return -1; + PR_JoinThread(selectThread); - n = data.status; - if (n == SOCKET_ERROR) { - WSASetLastError(data.error); - } + ready = data.status; + if (ready == SOCKET_ERROR) WSASetLastError(data.error); } #endif - if (n > 0) { - n = 0; - for (pd = pds, epd = pd + npds; pd < epd; pd++) { - SOCKET osfd; - PRInt16 in_flags = pd->in_flags; + /* + ** Now to unravel the select sets back into the client's poll + ** descriptor list. Is this possibly an area for pissing away + ** a few cycles or what? + */ + if (ready > 0) + { + ready = 0; + for (pd = pds, epd = pd + npds; pd < epd; pd++) + { PRInt16 out_flags = 0; - PRFileDesc *bottom = pd->fd; + if ((NULL != pd->fd) && (0 != pd->in_flags)) + { + SOCKET osfd; + bottom = PR_GetIdentitiesLayer(pd->fd, PR_NSPR_IO_LAYER); + PR_ASSERT(NULL != bottom); - if ((NULL == bottom) || (in_flags == 0)) { - pd->out_flags = 0; - continue; - } - while (bottom->lower != NULL) { - bottom = bottom->lower; - } - osfd = (SOCKET) bottom->secret->md.osfd; + osfd = (SOCKET) bottom->secret->md.osfd; - if ((in_flags & PR_POLL_READ) && FD_ISSET(osfd, &rd)) { - out_flags |= PR_POLL_READ; - } - if ((in_flags & PR_POLL_WRITE) && FD_ISSET(osfd, &wt)) { - out_flags |= PR_POLL_WRITE; - } - if ((in_flags & PR_POLL_EXCEPT) && FD_ISSET(osfd, &ex)) { - out_flags |= PR_POLL_EXCEPT; + if (FD_ISSET(osfd, &rd)) + { + if (pd->out_flags & _PR_POLL_READ_SYS_READ) + out_flags |= PR_POLL_READ; + if (pd->out_flags & _PR_POLL_WRITE_SYS_READ) + out_flags |= PR_POLL_WRITE; + } + if (FD_ISSET(osfd, &wt)) + { + if (pd->out_flags & _PR_POLL_READ_SYS_WRITE) + out_flags |= PR_POLL_READ; + if (pd->out_flags & _PR_POLL_WRITE_SYS_WRITE) + out_flags |= PR_POLL_WRITE; + } + if (FD_ISSET(osfd, &ex)) out_flags |= PR_POLL_EXCEPT; } pd->out_flags = out_flags; - if (out_flags) { - n++; - } + if (out_flags) ready++; } - PR_ASSERT(n > 0); - } else if (n == SOCKET_ERROR) { + PR_ASSERT(ready > 0); + } + else if (ready == SOCKET_ERROR) + { err = WSAGetLastError(); - if (err == WSAENOTSOCK) { + if (err == WSAENOTSOCK) + { /* Find the bad fds */ - n = 0; - for (pd = pds, epd = pd + npds; pd < epd; pd++) { - int optval; - int optlen = sizeof(optval); - PRFileDesc *bottom = pd->fd; - + int optval; + int optlen = sizeof(optval); + ready = 0; + for (pd = pds, epd = pd + npds; pd < epd; pd++) + { pd->out_flags = 0; - if ((NULL == bottom) || (pd->in_flags == 0)) { - continue; - } - while (bottom->lower != NULL) { - bottom = bottom->lower; - } - if (getsockopt(bottom->secret->md.osfd, SOL_SOCKET, - SO_TYPE, (char *) &optval, &optlen) == -1) { - PR_ASSERT(WSAGetLastError() == WSAENOTSOCK); - if (WSAGetLastError() == WSAENOTSOCK) { - pd->out_flags = PR_POLL_NVAL; - n++; + if ((NULL != pd->fd) && (0 != pd->in_flags)) + { + bottom = PR_GetIdentitiesLayer(pd->fd, PR_NSPR_IO_LAYER); + if (getsockopt(bottom->secret->md.osfd, SOL_SOCKET, + SO_TYPE, (char *) &optval, &optlen) == -1) + { + PR_ASSERT(WSAGetLastError() == WSAENOTSOCK); + if (WSAGetLastError() == WSAENOTSOCK) + { + pd->out_flags = PR_POLL_NVAL; + ready++; + } } } } - PR_ASSERT(n > 0); - } else { - _PR_MD_MAP_SELECT_ERROR(err); + PR_ASSERT(ready > 0); } + else _PR_MD_MAP_SELECT_ERROR(err); } - return n; + return ready; } diff --git a/pr/src/md/windows/w95dllmain.c b/pr/src/md/windows/w95dllmain.c new file mode 100644 index 00000000..ae83ec44 --- /dev/null +++ b/pr/src/md/windows/w95dllmain.c @@ -0,0 +1,50 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "NPL"); you may not use this file except in + * compliance with the NPL. You may obtain a copy of the NPL at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the NPL is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL + * for the specific language governing rights and limitations under the + * NPL. + * + * The Initial Developer of this code under the NPL is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All Rights + * Reserved. + */ + +/* + * The DLL entry point (DllMain) for NSPR. + * + * This is used to detach threads that were automatically attached by + * nspr. + */ + +#include <windows.h> +#include <primpl.h> + +BOOL WINAPI DllMain( + HINSTANCE hinstDLL, + DWORD fdwReason, + LPVOID lpvReserved) +{ +PRThread *me; + + switch (fdwReason) { + case DLL_PROCESS_ATTACH: + break; + case DLL_THREAD_ATTACH: + break; + case DLL_THREAD_DETACH: + me = _MD_GET_ATTACHED_THREAD(); + if ((me != NULL) && (me->flags & _PR_ATTACHED)) + _PRI_DetachThread(); + break; + case DLL_PROCESS_DETACH: + break; + } + return TRUE; +} diff --git a/pr/src/md/windows/w95sock.c b/pr/src/md/windows/w95sock.c index c5fbea4c..75030f55 100644 --- a/pr/src/md/windows/w95sock.c +++ b/pr/src/md/windows/w95sock.c @@ -22,6 +22,15 @@ #include "primpl.h" +#define READ_FD 1 +#define WRITE_FD 2 +#define CONNECT_FD 3 + +static PRInt32 socket_io_wait( + PRInt32 osfd, + PRInt32 fd_type, + PRIntervalTime timeout); + /* --- SOCKET IO --------------------------------------------------------- */ @@ -30,27 +39,23 @@ PRInt32 _PR_MD_SOCKET(int af, int type, int flags) { SOCKET sock; - PRUint32 one = 1; - PRInt32 rv; - PRInt32 err; + u_long one = 1; sock = socket(af, type, flags); if (sock == INVALID_SOCKET ) { - int rv = WSAGetLastError(); - closesocket(sock); - _PR_MD_MAP_SOCKET_ERROR(rv); - return (PRInt32)INVALID_SOCKET; + _PR_MD_MAP_SOCKET_ERROR(WSAGetLastError()); + return (PRInt32)sock; } /* ** Make the socket Non-Blocking */ - rv = ioctlsocket( sock, FIONBIO, &one); - if ( rv != 0 ) + if (ioctlsocket( sock, FIONBIO, &one) != 0) { - err = WSAGetLastError(); + PR_SetError(PR_UNKNOWN_ERROR, WSAGetLastError()); + closesocket(sock); return -1; } @@ -64,11 +69,11 @@ _PR_MD_SOCKET(int af, int type, int flags) PRInt32 _MD_CloseSocket(PRInt32 osfd) { - PRInt32 rv = SOCKET_ERROR; + PRInt32 rv; rv = closesocket((SOCKET) osfd ); - if (rv < 0) - _PR_MD_MAP_SOCKET_ERROR(WSAGetLastError()); + if (rv < 0) + _PR_MD_MAP_CLOSE_ERROR(WSAGetLastError()); return rv; } @@ -79,90 +84,39 @@ _MD_SocketAvailable(PRFileDesc *fd) PRInt32 result; if (ioctlsocket(fd->secret->md.osfd, FIONREAD, &result) < 0) { - PR_SetError(PR_BAD_DESCRIPTOR_ERROR, WSAGetLastError()); + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, WSAGetLastError()); return -1; } return result; } -PRInt32 -_MD_Accept(PRFileDesc *fd, PRNetAddr *raddr, PRUint32 *rlen, - PRIntervalTime timeout ) +PRInt32 _MD_Accept( + PRFileDesc *fd, + PRNetAddr *raddr, + PRUint32 *rlen, + PRIntervalTime timeout ) { PRInt32 osfd = fd->secret->md.osfd; PRInt32 rv, err; - fd_set rd; - struct timeval tv, *tvp; - FD_ZERO(&rd); - FD_SET((SOCKET)osfd, &rd); - if (timeout == PR_INTERVAL_NO_TIMEOUT) + while ((rv = accept(osfd, (struct sockaddr *) raddr, rlen)) == -1) { - while ((rv = accept(osfd, (struct sockaddr *) raddr, rlen)) == -1) - { - if (((err = WSAGetLastError()) == WSAEWOULDBLOCK) - && (!fd->secret->nonblocking)) - { - if ((rv = select(osfd + 1, &rd, NULL, NULL,NULL)) == -1) { - _PR_MD_MAP_SELECT_ERROR(WSAGetLastError()); - break; - } - } - else { - _PR_MD_MAP_ACCEPT_ERROR(err); - break; - } - } - return(rv); - } - else if (timeout == PR_INTERVAL_NO_WAIT) - { - if ((rv = accept(osfd, (struct sockaddr *) raddr, rlen)) == -1) + err = WSAGetLastError(); + if ((err == WSAEWOULDBLOCK) && (!fd->secret->nonblocking)) { - if (((err = WSAGetLastError()) == WSAEWOULDBLOCK) - && (!fd->secret->nonblocking)) + if ((rv = socket_io_wait(osfd, READ_FD, timeout)) < 0) { - PR_SetError(PR_IO_TIMEOUT_ERROR, 0); - } - else - { - _PR_MD_MAP_ACCEPT_ERROR(err); + return(-1); } } - return(rv); - } - else - { -retry: - if ((rv = accept(osfd, (struct sockaddr *) raddr, rlen)) == -1) + else { - if (((err = WSAGetLastError()) == WSAEWOULDBLOCK) - && (!fd->secret->nonblocking)) - { - tv.tv_sec = PR_IntervalToSeconds(timeout); - tv.tv_usec = PR_IntervalToMicroseconds( - timeout - PR_SecondsToInterval(tv.tv_sec)); - tvp = &tv; - - rv = select(osfd + 1, &rd, NULL, NULL, tvp); - if (rv > 0) { - goto retry; - } - else if (rv == 0) - { - PR_SetError(PR_IO_TIMEOUT_ERROR, 0); - rv = -1; - } else { - _PR_MD_MAP_SELECT_ERROR(WSAGetLastError()); - } - } else { - _PR_MD_MAP_ACCEPT_ERROR(err); - } + _PR_MD_MAP_ACCEPT_ERROR(err); + break; } } return(rv); -} /* end _MD_Accept() */ - +} /* end _MD_accept() */ PRInt32 _PR_MD_CONNECT(PRFileDesc *fd, const PRNetAddr *addr, PRUint32 addrlen, @@ -170,64 +124,25 @@ _PR_MD_CONNECT(PRFileDesc *fd, const PRNetAddr *addr, PRUint32 addrlen, { PRInt32 osfd = fd->secret->md.osfd; PRInt32 rv; - int err, len; - fd_set wd, ex; - struct timeval tv, *tvp; + int err; if ((rv = connect(osfd, (struct sockaddr *) addr, addrlen)) == -1) { err = WSAGetLastError(); if ((!fd->secret->nonblocking) && (err == WSAEWOULDBLOCK)) { - if (timeout == PR_INTERVAL_NO_TIMEOUT) - tvp = NULL; - else + rv = socket_io_wait(osfd, CONNECT_FD, timeout); + if ( rv < 0 ) { - tv.tv_sec = PR_IntervalToSeconds(timeout); - tv.tv_usec = PR_IntervalToMicroseconds( - timeout - PR_SecondsToInterval(tv.tv_sec)); - tvp = &tv; + return(-1); } - - FD_ZERO(&wd); - FD_SET((SOCKET)osfd, &wd); - FD_ZERO(&ex); - FD_SET((SOCKET)osfd, &ex); - rv = select(osfd + 1, NULL, &wd, &ex, tvp); - if (rv > 0) + else { - if (FD_ISSET((SOCKET)osfd, &ex)) - { - Sleep(0); - len = sizeof(err); - if (getsockopt(osfd, SOL_SOCKET, SO_ERROR, - (char *) &err, &len) == SOCKET_ERROR) - { - _PR_MD_MAP_GETSOCKOPT_ERROR(WSAGetLastError()); - return -1; - } - if (err != 0) - _PR_MD_MAP_CONNECT_ERROR(err); - else - PR_SetError(PR_UNKNOWN_ERROR, 0); - return -1; - } - if (FD_ISSET((SOCKET)osfd, &wd)) - { - /* it's connected */ - return 0; - } + PR_ASSERT(rv > 0); + /* it's connected */ + return(0); } - else if (rv == 0) - { - PR_SetError(PR_IO_TIMEOUT_ERROR, 0); - return(-1); - } else if (rv < 0) - { - _PR_MD_MAP_SELECT_ERROR(WSAGetLastError()); - return(-1); - } - } + } _PR_MD_MAP_CONNECT_ERROR(err); } return rv; @@ -242,9 +157,9 @@ _PR_MD_BIND(PRFileDesc *fd, const PRNetAddr *addr, PRUint32 addrlen) rv = bind(fd->secret->md.osfd, (const struct sockaddr *)&(addr->inet), addrlen); if (rv == SOCKET_ERROR) { - _PR_MD_MAP_BIND_ERROR(WSAGetLastError()); + _PR_MD_MAP_BIND_ERROR(WSAGetLastError()); return -1; - } + } return 0; } @@ -256,42 +171,21 @@ _PR_MD_RECV(PRFileDesc *fd, void *buf, PRInt32 amount, PRIntn flags, { PRInt32 osfd = fd->secret->md.osfd; PRInt32 rv, err; - struct timeval tv, *tvp; - fd_set rd; while ((rv = recv( osfd, buf, amount, 0)) == -1) { if (((err = WSAGetLastError()) == WSAEWOULDBLOCK) && (!fd->secret->nonblocking)) { - FD_ZERO(&rd); - FD_SET((SOCKET)osfd, &rd); - if (timeout == PR_INTERVAL_NO_TIMEOUT) - { - tvp = NULL; - } - else - { - tv.tv_sec = PR_IntervalToSeconds(timeout); - tv.tv_usec = PR_IntervalToMicroseconds( - timeout - PR_SecondsToInterval(tv.tv_sec)); - tvp = &tv; - } - if ((rv = select(osfd + 1, &rd, NULL, NULL, tvp)) == -1) + rv = socket_io_wait(osfd, READ_FD, timeout); + if ( rv < 0 ) { - _PR_MD_MAP_SELECT_ERROR(WSAGetLastError()); return -1; } - else if (rv == 0) - { - PR_SetError(PR_IO_TIMEOUT_ERROR, 0); - rv = -1; - break; - } } else { - _PR_MD_MAP_RECV_ERROR(err); + _PR_MD_MAP_RECV_ERROR(err); break; } } /* end while() */ @@ -304,8 +198,6 @@ _PR_MD_SEND(PRFileDesc *fd, const void *buf, PRInt32 amount, PRIntn flags, { PRInt32 osfd = fd->secret->md.osfd; PRInt32 rv, err; - struct timeval tv, *tvp; - fd_set wd; PRInt32 bytesSent = 0; while(bytesSent < amount ) @@ -315,62 +207,29 @@ _PR_MD_SEND(PRFileDesc *fd, const void *buf, PRInt32 amount, PRIntn flags, if (((err = WSAGetLastError()) == WSAEWOULDBLOCK) && (!fd->secret->nonblocking)) { - if ( timeout == PR_INTERVAL_NO_TIMEOUT ) - { - tvp = NULL; - } - else - { - tv.tv_sec = PR_IntervalToSeconds(timeout); - tv.tv_usec = PR_IntervalToMicroseconds( - timeout - PR_SecondsToInterval(tv.tv_sec)); - tvp = &tv; - } - FD_ZERO(&wd); - FD_SET((SOCKET)osfd, &wd); - if ((rv = select( osfd + 1, NULL, &wd, NULL,tvp)) == -1) { - _PR_MD_MAP_SELECT_ERROR(WSAGetLastError()); - break; - } - if (rv == 0) + rv = socket_io_wait(osfd, WRITE_FD, timeout); + if ( rv < 0 ) { - PR_SetError(PR_IO_TIMEOUT_ERROR, 0); - return -1; + return -1; } } - else { - _PR_MD_MAP_SEND_ERROR(err); + else + { + _PR_MD_MAP_SEND_ERROR(err); return -1; - } + } } bytesSent += rv; if (fd->secret->nonblocking) { break; } - if ((rv >= 0) && (bytesSent < amount )) + if (bytesSent < amount) { - if ( timeout == PR_INTERVAL_NO_TIMEOUT ) - { - tvp = NULL; - } - else - { - tv.tv_sec = PR_IntervalToSeconds(timeout); - tv.tv_usec = PR_IntervalToMicroseconds( - timeout - PR_SecondsToInterval(tv.tv_sec)); - tvp = &tv; - } - FD_ZERO(&wd); - FD_SET((SOCKET)osfd, &wd); - if ((rv = select(osfd + 1, NULL, &wd, NULL,tvp)) == -1) { - _PR_MD_MAP_SELECT_ERROR(WSAGetLastError()); - break; - } - if (rv == 0) + rv = socket_io_wait(osfd, WRITE_FD, timeout); + if ( rv < 0 ) { - PR_SetError(PR_IO_TIMEOUT_ERROR, 0); - return -1; + return -1; } } } @@ -383,8 +242,6 @@ _PR_MD_SENDTO(PRFileDesc *fd, const void *buf, PRInt32 amount, PRIntn flags, { PRInt32 osfd = fd->secret->md.osfd; PRInt32 rv, err; - struct timeval tv, *tvp; - fd_set wd; PRInt32 bytesSent = 0; while(bytesSent < amount) @@ -395,62 +252,29 @@ _PR_MD_SENDTO(PRFileDesc *fd, const void *buf, PRInt32 amount, PRIntn flags, if (((err = WSAGetLastError()) == WSAEWOULDBLOCK) && (!fd->secret->nonblocking)) { - if ( timeout == PR_INTERVAL_NO_TIMEOUT ) + rv = socket_io_wait(osfd, WRITE_FD, timeout); + if ( rv < 0 ) { - tvp = NULL; - } - else - { - tv.tv_sec = PR_IntervalToSeconds(timeout); - tv.tv_usec = PR_IntervalToMicroseconds( - timeout - PR_SecondsToInterval(tv.tv_sec)); - tvp = &tv; - } - FD_ZERO(&wd); - FD_SET((SOCKET)osfd, &wd); - if ((rv = select(osfd + 1, NULL, &wd, NULL, tvp)) == -1) { - _PR_MD_MAP_SELECT_ERROR(WSAGetLastError()); - break; - } - if (rv == 0) - { - PR_SetError(PR_IO_TIMEOUT_ERROR, 0); - return -1; + return -1; } } - else { - _PR_MD_MAP_SENDTO_ERROR(err); + else + { + _PR_MD_MAP_SENDTO_ERROR(err); return -1; - } + } } bytesSent += rv; if (fd->secret->nonblocking) { break; } - if ((rv >= 0) && (bytesSent < amount )) + if (bytesSent < amount) { - if ( timeout == PR_INTERVAL_NO_TIMEOUT ) + rv = socket_io_wait(osfd, WRITE_FD, timeout); + if (rv < 0) { - tvp = NULL; - } - else - { - tv.tv_sec = PR_IntervalToSeconds(timeout); - tv.tv_usec = PR_IntervalToMicroseconds( - timeout - PR_SecondsToInterval(tv.tv_sec)); - tvp = &tv; - } - FD_ZERO(&wd); - FD_SET((SOCKET)osfd, &wd); - if ((rv = select( osfd + 1, NULL, &wd, NULL, tvp)) == -1) { - _PR_MD_MAP_SELECT_ERROR(WSAGetLastError()); - break; - } - if (rv == 0) - { - PR_SetError(PR_IO_TIMEOUT_ERROR, 0); - return -1; + return -1; } } } @@ -463,8 +287,6 @@ _PR_MD_RECVFROM(PRFileDesc *fd, void *buf, PRInt32 amount, PRIntn flags, { PRInt32 osfd = fd->secret->md.osfd; PRInt32 rv, err; - struct timeval tv, *tvp; - fd_set rd; while ((rv = recvfrom( osfd, buf, amount, 0, (struct sockaddr *) addr, addrlen)) == -1) @@ -472,33 +294,15 @@ _PR_MD_RECVFROM(PRFileDesc *fd, void *buf, PRInt32 amount, PRIntn flags, if (((err = WSAGetLastError()) == WSAEWOULDBLOCK) && (!fd->secret->nonblocking)) { - if (timeout == PR_INTERVAL_NO_TIMEOUT) - { - tvp = NULL; - } - else + rv = socket_io_wait(osfd, READ_FD, timeout); + if ( rv < 0) { - tv.tv_sec = PR_IntervalToSeconds(timeout); - tv.tv_usec = PR_IntervalToMicroseconds( - timeout - PR_SecondsToInterval(tv.tv_sec)); - tvp = &tv; - } - FD_ZERO(&rd); - FD_SET((SOCKET)osfd, &rd); - if ((rv = select(osfd + 1, &rd, NULL, NULL, tvp)) == -1) - { - _PR_MD_MAP_SELECT_ERROR(WSAGetLastError()); return -1; - } else if (rv == 0) - { - PR_SetError(PR_IO_TIMEOUT_ERROR, 0); - rv = -1; - break; - } + } } else { - _PR_MD_MAP_RECVFROM_ERROR(err); + _PR_MD_MAP_RECVFROM_ERROR(err); break; } } @@ -546,9 +350,9 @@ _PR_MD_SHUTDOWN(PRFileDesc *fd, PRIntn how) PRInt32 rv; rv = shutdown(fd->secret->md.osfd, how); - if (rv < 0) - _PR_MD_MAP_SHUTDOWN_ERROR(WSAGetLastError()); - return rv; + if (rv < 0) + _PR_MD_MAP_SHUTDOWN_ERROR(WSAGetLastError()); + return rv; } PRStatus @@ -557,12 +361,12 @@ _PR_MD_GETSOCKNAME(PRFileDesc *fd, PRNetAddr *addr, PRUint32 *len) PRInt32 rv; rv = getsockname((SOCKET)fd->secret->md.osfd, (struct sockaddr *)addr, len); - if (rv==0) - return PR_SUCCESS; - else { - _PR_MD_MAP_GETSOCKNAME_ERROR(WSAGetLastError()); - return PR_FAILURE; - } + if (rv==0) { + return PR_SUCCESS; + } else { + _PR_MD_MAP_GETSOCKNAME_ERROR(WSAGetLastError()); + return PR_FAILURE; + } } PRStatus @@ -571,12 +375,12 @@ _PR_MD_GETPEERNAME(PRFileDesc *fd, PRNetAddr *addr, PRUint32 *len) PRInt32 rv; rv = getpeername((SOCKET)fd->secret->md.osfd, (struct sockaddr *)addr, len); - if (rv==0) - return PR_SUCCESS; - else { - _PR_MD_MAP_GETPEERNAME_ERROR(WSAGetLastError()); - return PR_FAILURE; - } + if (rv==0) { + return PR_SUCCESS; + } else { + _PR_MD_MAP_GETPEERNAME_ERROR(WSAGetLastError()); + return PR_FAILURE; + } } PRStatus @@ -585,12 +389,12 @@ _PR_MD_GETSOCKOPT(PRFileDesc *fd, PRInt32 level, PRInt32 optname, char* optval, PRInt32 rv; rv = getsockopt((SOCKET)fd->secret->md.osfd, level, optname, optval, optlen); - if (rv==0) - return PR_SUCCESS; - else { - _PR_MD_MAP_GETSOCKOPT_ERROR(WSAGetLastError()); - return PR_FAILURE; - } + if (rv==0) { + return PR_SUCCESS; + } else { + _PR_MD_MAP_GETSOCKOPT_ERROR(WSAGetLastError()); + return PR_FAILURE; + } } PRStatus @@ -599,16 +403,210 @@ _PR_MD_SETSOCKOPT(PRFileDesc *fd, PRInt32 level, PRInt32 optname, const char* op PRInt32 rv; rv = setsockopt((SOCKET)fd->secret->md.osfd, level, optname, optval, optlen); - if (rv==0) - return PR_SUCCESS; - else { - _PR_MD_MAP_SETSOCKOPT_ERROR(WSAGetLastError()); - return PR_FAILURE; - } + if (rv==0) { + return PR_SUCCESS; + } else { + _PR_MD_MAP_SETSOCKOPT_ERROR(WSAGetLastError()); + return PR_FAILURE; + } } void _MD_MakeNonblock(PRFileDesc *f) { - return; // do nothing! + return; /* do nothing */ } + + + +/* + * socket_io_wait -- + * + * Wait for socket i/o, periodically checking for interrupt. + * + * This function returns 1 on success. On failure, it returns + * -1 and sets the error codes. It never returns 0. + */ +#define _PR_INTERRUPT_CHECK_INTERVAL_SECS 5 + +static PRInt32 socket_io_wait( + PRInt32 osfd, + PRInt32 fd_type, + PRIntervalTime timeout) +{ + PRInt32 rv = -1; + struct timeval tv; + PRThread *me = _PR_MD_CURRENT_THREAD(); + PRIntervalTime elapsed, remaining; + fd_set rd_wr, ex; + int err, len; + + switch (timeout) { + case PR_INTERVAL_NO_WAIT: + PR_SetError(PR_IO_TIMEOUT_ERROR, 0); + break; + case PR_INTERVAL_NO_TIMEOUT: + /* + * This is a special case of the 'default' case below. + * Please see the comments there. + */ + tv.tv_sec = _PR_INTERRUPT_CHECK_INTERVAL_SECS; + tv.tv_usec = 0; + FD_ZERO(&rd_wr); + FD_ZERO(&ex); + do { + FD_SET(osfd, &rd_wr); + FD_SET(osfd, &ex); + switch( fd_type ) + { + case READ_FD: + rv = _MD_SELECT(osfd + 1, &rd_wr, NULL, NULL, &tv); + break; + case WRITE_FD: + rv = _MD_SELECT(osfd + 1, NULL, &rd_wr, NULL, &tv); + break; + case CONNECT_FD: + rv = _MD_SELECT(osfd + 1, NULL, &rd_wr, &ex, &tv); + break; + default: + PR_ASSERT(0); + break; + } /* end switch() */ + if (rv == -1 ) + { + _PR_MD_MAP_SELECT_ERROR(WSAGetLastError()); + break; + } + if ( rv > 0 && fd_type == CONNECT_FD ) + { + /* + * Call Sleep(0) to work around a Winsock timing bug. + */ + Sleep(0); + if (FD_ISSET((SOCKET)osfd, &ex)) + { + len = sizeof(err); + if (getsockopt(osfd, SOL_SOCKET, SO_ERROR, + (char *) &err, &len) == SOCKET_ERROR) + { + _PR_MD_MAP_GETSOCKOPT_ERROR(WSAGetLastError()); + return -1; + } + if (err != 0) + _PR_MD_MAP_CONNECT_ERROR(err); + else + PR_SetError(PR_UNKNOWN_ERROR, 0); + return -1; + } + if (FD_ISSET((SOCKET)osfd, &rd_wr)) + { + /* it's connected */ + return 1; + } + PR_ASSERT(0); + } + if (_PR_PENDING_INTERRUPT(me)) { + me->flags &= ~_PR_INTERRUPT; + PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); + rv = -1; + break; + } + } while (rv == 0); + break; + default: + remaining = timeout; + FD_ZERO(&rd_wr); + FD_ZERO(&ex); + do { + /* + * We block in _MD_SELECT for at most + * _PR_INTERRUPT_CHECK_INTERVAL_SECS seconds, + * so that there is an upper limit on the delay + * before the interrupt bit is checked. + */ + tv.tv_sec = PR_IntervalToSeconds(remaining); + if (tv.tv_sec > _PR_INTERRUPT_CHECK_INTERVAL_SECS) { + tv.tv_sec = _PR_INTERRUPT_CHECK_INTERVAL_SECS; + tv.tv_usec = 0; + } else { + tv.tv_usec = PR_IntervalToMicroseconds( + remaining - + PR_SecondsToInterval(tv.tv_sec)); + } + FD_SET(osfd, &rd_wr); + FD_SET(osfd, &ex); + switch( fd_type ) + { + case READ_FD: + rv = _MD_SELECT(osfd + 1, &rd_wr, NULL, NULL, &tv); + break; + case WRITE_FD: + rv = _MD_SELECT(osfd + 1, NULL, &rd_wr, NULL, &tv); + break; + case CONNECT_FD: + rv = _MD_SELECT(osfd + 1, NULL, &rd_wr, &ex, &tv); + break; + default: + PR_ASSERT(0); + break; + } /* end switch() */ + if (rv == -1) + { + _PR_MD_MAP_SELECT_ERROR(WSAGetLastError()); + break; + } + if ( rv > 0 && fd_type == CONNECT_FD ) + { + /* + * Call Sleep(0) to work around a Winsock timing bug. + */ + Sleep(0); + if (FD_ISSET((SOCKET)osfd, &ex)) + { + len = sizeof(err); + if (getsockopt(osfd, SOL_SOCKET, SO_ERROR, + (char *) &err, &len) == SOCKET_ERROR) + { + _PR_MD_MAP_GETSOCKOPT_ERROR(WSAGetLastError()); + return -1; + } + if (err != 0) + _PR_MD_MAP_CONNECT_ERROR(err); + else + PR_SetError(PR_UNKNOWN_ERROR, 0); + return -1; + } + if (FD_ISSET((SOCKET)osfd, &rd_wr)) + { + /* it's connected */ + return 1; + } + PR_ASSERT(0); + } + if (_PR_PENDING_INTERRUPT(me)) { + me->flags &= ~_PR_INTERRUPT; + PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); + rv = -1; + break; + } + /* + * We loop again if _MD_SELECT timed out and the + * timeout deadline has not passed yet. + */ + if (rv == 0 ) + { + elapsed = PR_SecondsToInterval(tv.tv_sec) + + PR_MicrosecondsToInterval(tv.tv_usec); + if (elapsed >= remaining) { + PR_SetError(PR_IO_TIMEOUT_ERROR, 0); + rv = -1; + break; + } else { + remaining = remaining - elapsed; + } + } + } while (rv == 0 ); + break; + } + return(rv); +} /* end socket_io_wait() */ diff --git a/pr/src/md/windows/w95thred.c b/pr/src/md/windows/w95thred.c index 41da9922..89103bb2 100644 --- a/pr/src/md/windows/w95thred.c +++ b/pr/src/md/windows/w95thred.c @@ -242,3 +242,16 @@ _PR_MD_RESUME_THREAD(PRThread *thread) } } +PRThread* +_MD_CURRENT_THREAD(void) +{ +PRThread *thread; + + thread = _MD_GET_ATTACHED_THREAD(); + + if (NULL == thread) { + thread = _PRI_AttachThread( + PR_USER_THREAD, PR_PRIORITY_NORMAL, NULL, 0); + } + PR_ASSERT(thread != NULL); +} diff --git a/pr/src/md/windows/win32_errors.c b/pr/src/md/windows/win32_errors.c index 884d8ce1..1899a1be 100644 --- a/pr/src/md/windows/win32_errors.c +++ b/pr/src/md/windows/win32_errors.c @@ -17,9 +17,24 @@ */ #include "prerror.h" +#include "prlog.h" #include <errno.h> #include <windows.h> +/* + * On Win32, we map three kinds of error codes: + * - GetLastError(): for Win32 functions + * - WSAGetLastError(): for Winsock functions + * - errno: for standard C library functions + * + * We do not check for WSAEINPROGRESS and WSAEINTR because we do not + * use blocking Winsock 1.1 calls. + * + * Except for the 'socket' call, we do not check for WSAEINITIALISED. + * It is assumed that if Winsock is not initialized, that fact will + * be detected at the time we create new sockets. + */ + void _MD_win32_map_opendir_error(PRInt32 err) { switch (err) { @@ -121,9 +136,11 @@ void _MD_win32_map_delete_error(PRInt32 err) break; case ERROR_DRIVE_LOCKED: case ERROR_LOCKED: - case ERROR_SHARING_VIOLATION: PR_SetError(PR_FILE_IS_LOCKED_ERROR, err); break; + case ERROR_SHARING_VIOLATION: + PR_SetError(PR_FILE_IS_BUSY_ERROR, err); + break; default: PR_SetError(PR_UNKNOWN_ERROR, err); break; @@ -350,6 +367,7 @@ void _MD_win32_map_read_error(PRInt32 err) case ERROR_INVALID_HANDLE: PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); break; + case ERROR_NOACCESS: case ERROR_INVALID_ADDRESS: PR_SetError(PR_ACCESS_FAULT_ERROR, err); break; @@ -370,21 +388,14 @@ void _MD_win32_map_read_error(PRInt32 err) break; case ERROR_DRIVE_LOCKED: case ERROR_LOCKED: - case ERROR_SHARING_VIOLATION: PR_SetError(PR_FILE_IS_LOCKED_ERROR, err); break; + case ERROR_SHARING_VIOLATION: + PR_SetError(PR_FILE_IS_BUSY_ERROR, err); + break; case ERROR_NETNAME_DELETED: PR_SetError(PR_CONNECT_RESET_ERROR, err); break; - case WSAEBADF: - PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); - break; - case WSAENOTSOCK: - PR_SetError(PR_NOT_SOCKET_ERROR, err); - break; - case WSAEFAULT: - PR_SetError(PR_ACCESS_FAULT_ERROR, err); - break; default: PR_SetError(PR_UNKNOWN_ERROR, err); break; @@ -421,9 +432,11 @@ void _MD_win32_map_transmitfile_error(PRInt32 err) break; case ERROR_DRIVE_LOCKED: case ERROR_LOCKED: - case ERROR_SHARING_VIOLATION: PR_SetError(PR_FILE_IS_LOCKED_ERROR, err); break; + case ERROR_SHARING_VIOLATION: + PR_SetError(PR_FILE_IS_BUSY_ERROR, err); + break; case ERROR_FILENAME_EXCED_RANGE: PR_SetError(PR_NAME_TOO_LONG_ERROR, err); break; @@ -463,6 +476,9 @@ void _MD_win32_map_write_error(PRInt32 err) case ERROR_STACK_OVERFLOW: PR_SetError(PR_ACCESS_FAULT_ERROR, err); break; + case ERROR_INVALID_PARAMETER: + PR_SetError(PR_INVALID_ARGUMENT_ERROR, err); + break; case ERROR_DISK_CORRUPT: case ERROR_DISK_OPERATION_FAILED: case ERROR_FILE_CORRUPT: @@ -472,9 +488,11 @@ void _MD_win32_map_write_error(PRInt32 err) break; case ERROR_DRIVE_LOCKED: case ERROR_LOCKED: - case ERROR_SHARING_VIOLATION: PR_SetError(PR_FILE_IS_LOCKED_ERROR, err); break; + case ERROR_SHARING_VIOLATION: + PR_SetError(PR_FILE_IS_BUSY_ERROR, err); + break; case ERROR_NOT_ENOUGH_MEMORY: case ERROR_OUTOFMEMORY: case ERROR_INVALID_USER_BUFFER: @@ -490,28 +508,6 @@ void _MD_win32_map_write_error(PRInt32 err) case ERROR_NETNAME_DELETED: PR_SetError(PR_CONNECT_RESET_ERROR, err); break; - case WSAEBADF: - PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); - break; - case WSAENOTSOCK: - PR_SetError(PR_NOT_SOCKET_ERROR, err); - break; - case WSAEMSGSIZE: - case WSAEINVAL: - PR_SetError(PR_INVALID_ARGUMENT_ERROR, err); - break; - case WSAENOBUFS: - PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, err); - break; - case WSAECONNREFUSED: - PR_SetError(PR_CONNECT_REFUSED_ERROR, err); - break; - case WSAEISCONN: - PR_SetError(PR_IS_CONNECTED_ERROR, err); - break; - case WSAEFAULT: - PR_SetError(PR_ACCESS_FAULT_ERROR, err); - break; default: PR_SetError(PR_UNKNOWN_ERROR, err); break; @@ -559,6 +555,9 @@ void _MD_win32_map_fsync_error(PRInt32 err) } } +/* + * For both CloseHandle() and closesocket(). + */ void _MD_win32_map_close_error(PRInt32 err) { switch (err) { @@ -572,6 +571,15 @@ void _MD_win32_map_close_error(PRInt32 err) case ERROR_PATH_BUSY: PR_SetError(PR_IO_ERROR, err); break; + case WSAENOTSOCK: + PR_SetError(PR_NOT_SOCKET_ERROR, err); + break; + case WSAENETDOWN: + PR_SetError(PR_NETWORK_DOWN_ERROR, err); + break; + case WSAEWOULDBLOCK: + PR_SetError(PR_WOULD_BLOCK_ERROR, err); + break; default: PR_SetError(PR_UNKNOWN_ERROR, err); break; @@ -580,18 +588,32 @@ void _MD_win32_map_close_error(PRInt32 err) void _MD_win32_map_socket_error(PRInt32 err) { + PR_ASSERT(err != WSANOTINITIALISED); switch (err) { + case WSAENETDOWN: + PR_SetError(PR_NETWORK_DOWN_ERROR, err); + break; case WSAEPROTONOSUPPORT: PR_SetError(PR_PROTOCOL_NOT_SUPPORTED_ERROR, err); break; case WSAEACCES: PR_SetError(PR_NO_ACCESS_RIGHTS_ERROR, err); break; + case WSAEMFILE: + PR_SetError(PR_PROC_DESC_TABLE_FULL_ERROR, err); + break; case ERROR_NOT_ENOUGH_MEMORY: case ERROR_OUTOFMEMORY: case WSAENOBUFS: PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, err); break; + case WSAEAFNOSUPPORT: + PR_SetError(PR_ADDRESS_NOT_SUPPORTED_ERROR, err); + break; + case WSAEPROTOTYPE: + case WSAESOCKTNOSUPPORT: + PR_SetError(PR_INVALID_ARGUMENT_ERROR, err); + break; default: PR_SetError(PR_UNKNOWN_ERROR, err); break; @@ -604,8 +626,8 @@ void _MD_win32_map_recv_error(PRInt32 err) case WSAEWOULDBLOCK: PR_SetError(PR_WOULD_BLOCK_ERROR, err); break; - case WSAEBADF: - PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); + case WSAENETDOWN: + PR_SetError(PR_NETWORK_DOWN_ERROR, err); break; case WSAENOTSOCK: PR_SetError(PR_NOT_SOCKET_ERROR, err); @@ -613,9 +635,30 @@ void _MD_win32_map_recv_error(PRInt32 err) case WSAEFAULT: PR_SetError(PR_ACCESS_FAULT_ERROR, err); break; + case WSAENOTCONN: + PR_SetError(PR_NOT_CONNECTED_ERROR, err); + break; + case WSAESHUTDOWN: + PR_SetError(PR_SOCKET_SHUTDOWN_ERROR, err); + break; + case WSAEMSGSIZE: + PR_SetError(PR_BUFFER_OVERFLOW_ERROR, err); + break; + case WSAECONNRESET: case ERROR_NETNAME_DELETED: PR_SetError(PR_CONNECT_RESET_ERROR, err); break; + case WSAEINVAL: + PR_SetError(PR_INVALID_ARGUMENT_ERROR, err); + break; + case WSAECONNABORTED: + case WSAETIMEDOUT: + case WSAENETRESET: + PR_SetError(PR_CONNECT_ABORTED_ERROR, err); + break; + case WSAEOPNOTSUPP: + PR_SetError(PR_OPERATION_NOT_SUPPORTED_ERROR, err); + break; default: PR_SetError(PR_UNKNOWN_ERROR, err); break; @@ -628,18 +671,39 @@ void _MD_win32_map_recvfrom_error(PRInt32 err) case WSAEWOULDBLOCK: PR_SetError(PR_WOULD_BLOCK_ERROR, err); break; - case WSAEBADF: - PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); - break; case WSAENOTSOCK: PR_SetError(PR_NOT_SOCKET_ERROR, err); break; case WSAEFAULT: PR_SetError(PR_ACCESS_FAULT_ERROR, err); break; + case WSAECONNRESET: case ERROR_NETNAME_DELETED: PR_SetError(PR_CONNECT_RESET_ERROR, err); break; + case WSAEINVAL: + PR_SetError(PR_INVALID_ARGUMENT_ERROR, err); + break; + case WSAENETDOWN: + PR_SetError(PR_NETWORK_DOWN_ERROR, err); + break; + case WSAEISCONN: + PR_SetError(PR_IS_CONNECTED_ERROR, err); + break; + case WSAENETRESET: + case WSAECONNABORTED: + case WSAETIMEDOUT: + PR_SetError(PR_CONNECT_ABORTED_ERROR, err); + break; + case WSAESHUTDOWN: + PR_SetError(PR_SOCKET_SHUTDOWN_ERROR, err); + break; + case WSAEMSGSIZE: + PR_SetError(PR_BUFFER_OVERFLOW_ERROR, err); + break; + case WSAEOPNOTSUPP: + PR_SetError(PR_OPERATION_NOT_SUPPORTED_ERROR, err); + break; default: PR_SetError(PR_UNKNOWN_ERROR, err); break; @@ -652,9 +716,6 @@ void _MD_win32_map_send_error(PRInt32 err) case WSAEWOULDBLOCK: PR_SetError(PR_WOULD_BLOCK_ERROR, err); break; - case WSAEBADF: - PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); - break; case WSAENOTSOCK: PR_SetError(PR_NOT_SOCKET_ERROR, err); break; @@ -665,18 +726,36 @@ void _MD_win32_map_send_error(PRInt32 err) case WSAENOBUFS: PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, err); break; - case WSAECONNREFUSED: - PR_SetError(PR_CONNECT_REFUSED_ERROR, err); - break; - case WSAEISCONN: - PR_SetError(PR_IS_CONNECTED_ERROR, err); + case WSAENOTCONN: + PR_SetError(PR_NOT_CONNECTED_ERROR, err); break; case WSAEFAULT: PR_SetError(PR_ACCESS_FAULT_ERROR, err); break; + case WSAECONNRESET: case ERROR_NETNAME_DELETED: PR_SetError(PR_CONNECT_RESET_ERROR, err); break; + case WSAENETDOWN: + PR_SetError(PR_NETWORK_DOWN_ERROR, err); + break; + case WSAENETRESET: + case WSAECONNABORTED: + case WSAETIMEDOUT: + PR_SetError(PR_CONNECT_ABORTED_ERROR, err); + break; + case WSAESHUTDOWN: + PR_SetError(PR_SOCKET_SHUTDOWN_ERROR, err); + break; + case WSAEHOSTUNREACH: + PR_SetError(PR_HOST_UNREACHABLE_ERROR, err); + break; + case WSAEOPNOTSUPP: + PR_SetError(PR_OPERATION_NOT_SUPPORTED_ERROR, err); + break; + case WSAEACCES: + PR_SetError(PR_NO_ACCESS_RIGHTS_ERROR, err); + break; default: PR_SetError(PR_UNKNOWN_ERROR, err); break; @@ -689,31 +768,56 @@ void _MD_win32_map_sendto_error(PRInt32 err) case WSAEWOULDBLOCK: PR_SetError(PR_WOULD_BLOCK_ERROR, err); break; - case WSAEBADF: - PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); - break; case WSAENOTSOCK: PR_SetError(PR_NOT_SOCKET_ERROR, err); break; case WSAEMSGSIZE: + case WSAEDESTADDRREQ: case WSAEINVAL: PR_SetError(PR_INVALID_ARGUMENT_ERROR, err); break; case WSAENOBUFS: PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, err); break; - case WSAECONNREFUSED: - PR_SetError(PR_CONNECT_REFUSED_ERROR, err); - break; - case WSAEISCONN: - PR_SetError(PR_IS_CONNECTED_ERROR, err); + case WSAENOTCONN: + PR_SetError(PR_NOT_CONNECTED_ERROR, err); break; case WSAEFAULT: PR_SetError(PR_ACCESS_FAULT_ERROR, err); break; + case WSAECONNRESET: case ERROR_NETNAME_DELETED: PR_SetError(PR_CONNECT_RESET_ERROR, err); break; + case WSAENETDOWN: + PR_SetError(PR_NETWORK_DOWN_ERROR, err); + break; + case WSAENETRESET: + case WSAECONNABORTED: + case WSAETIMEDOUT: + PR_SetError(PR_CONNECT_ABORTED_ERROR, err); + break; + case WSAESHUTDOWN: + PR_SetError(PR_SOCKET_SHUTDOWN_ERROR, err); + break; + case WSAEHOSTUNREACH: + PR_SetError(PR_HOST_UNREACHABLE_ERROR, err); + break; + case WSAENETUNREACH: + PR_SetError(PR_NETWORK_UNREACHABLE_ERROR, err); + break; + case WSAEAFNOSUPPORT: + PR_SetError(PR_ADDRESS_NOT_SUPPORTED_ERROR, err); + break; + case WSAEOPNOTSUPP: + PR_SetError(PR_OPERATION_NOT_SUPPORTED_ERROR, err); + break; + case WSAEACCES: + PR_SetError(PR_NO_ACCESS_RIGHTS_ERROR, err); + break; + case WSAEADDRNOTAVAIL: + PR_SetError(PR_ADDRESS_NOT_AVAILABLE_ERROR, err); + break; default: PR_SetError(PR_UNKNOWN_ERROR, err); break; @@ -726,9 +830,6 @@ void _MD_win32_map_accept_error(PRInt32 err) case WSAEWOULDBLOCK: PR_SetError(PR_WOULD_BLOCK_ERROR, err); break; - case WSAEBADF: - PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); - break; case WSAENOTSOCK: PR_SetError(PR_NOT_SOCKET_ERROR, err); break; @@ -742,7 +843,13 @@ void _MD_win32_map_accept_error(PRInt32 err) PR_SetError(PR_PROC_DESC_TABLE_FULL_ERROR, err); break; case WSAENOBUFS: - PR_SetError(PR_OUT_OF_MEMORY_ERROR, err); + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, err); + break; + case WSAENETDOWN: + PR_SetError(PR_NETWORK_DOWN_ERROR, err); + break; + case WSAEINVAL: + PR_SetError(PR_INVALID_STATE_ERROR, err); break; default: PR_SetError(PR_UNKNOWN_ERROR, err); @@ -781,9 +888,6 @@ void _MD_win32_map_connect_error(PRInt32 err) case WSAEINVAL: PR_SetError(PR_ALREADY_INITIATED_ERROR, err); break; - case WSAEBADF: - PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); - break; case WSAEADDRNOTAVAIL: PR_SetError(PR_ADDRESS_NOT_AVAILABLE_ERROR, err); break; @@ -811,6 +915,15 @@ void _MD_win32_map_connect_error(PRInt32 err) case WSAEFAULT: PR_SetError(PR_ACCESS_FAULT_ERROR, err); break; + case WSAENETDOWN: + PR_SetError(PR_NETWORK_DOWN_ERROR, err); + break; + case WSAENOBUFS: + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, err); + break; + case WSAEACCES: + PR_SetError(PR_NO_ACCESS_RIGHTS_ERROR, err); + break; default: PR_SetError(PR_UNKNOWN_ERROR, err); break; @@ -820,9 +933,6 @@ void _MD_win32_map_connect_error(PRInt32 err) void _MD_win32_map_bind_error(PRInt32 err) { switch (err) { - case WSAEBADF: - PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); - break; case WSAENOTSOCK: PR_SetError(PR_NOT_SOCKET_ERROR, err); break; @@ -835,12 +945,15 @@ void _MD_win32_map_bind_error(PRInt32 err) case WSAEADDRINUSE: PR_SetError(PR_ADDRESS_IN_USE_ERROR, err); break; - case WSAEACCES: - PR_SetError(PR_NO_ACCESS_RIGHTS_ERROR, err); - break; case WSAEINVAL: PR_SetError(PR_SOCKET_ADDRESS_IS_BOUND_ERROR, err); break; + case WSAENETDOWN: + PR_SetError(PR_NETWORK_DOWN_ERROR, err); + break; + case WSAENOBUFS: + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, err); + break; default: PR_SetError(PR_UNKNOWN_ERROR, err); break; @@ -850,15 +963,30 @@ void _MD_win32_map_bind_error(PRInt32 err) void _MD_win32_map_listen_error(PRInt32 err) { switch (err) { - case WSAEBADF: - PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); - break; case WSAENOTSOCK: PR_SetError(PR_NOT_SOCKET_ERROR, err); break; case WSAEOPNOTSUPP: PR_SetError(PR_NOT_TCP_SOCKET_ERROR, err); break; + case WSAENETDOWN: + PR_SetError(PR_NETWORK_DOWN_ERROR, err); + break; + case WSAEINVAL: + PR_SetError(PR_INVALID_STATE_ERROR, err); + break; + case WSAEISCONN: + PR_SetError(PR_IS_CONNECTED_ERROR, err); + break; + case WSAENOBUFS: + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, err); + break; + case WSAEADDRINUSE: + PR_SetError(PR_ADDRESS_IN_USE_ERROR, err); + break; + case WSAEMFILE: + PR_SetError(PR_PROC_DESC_TABLE_FULL_ERROR, err); + break; default: PR_SetError(PR_UNKNOWN_ERROR, err); break; @@ -868,15 +996,18 @@ void _MD_win32_map_listen_error(PRInt32 err) void _MD_win32_map_shutdown_error(PRInt32 err) { switch (err) { - case WSAEBADF: - PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); - break; case WSAENOTSOCK: PR_SetError(PR_NOT_SOCKET_ERROR, err); break; case WSAENOTCONN: PR_SetError(PR_NOT_CONNECTED_ERROR, err); break; + case WSAENETDOWN: + PR_SetError(PR_NETWORK_DOWN_ERROR, err); + break; + case WSAEINVAL: + PR_SetError(PR_INVALID_ARGUMENT_ERROR, err); + break; default: PR_SetError(PR_UNKNOWN_ERROR, err); break; @@ -886,17 +1017,17 @@ void _MD_win32_map_shutdown_error(PRInt32 err) void _MD_win32_map_getsockname_error(PRInt32 err) { switch (err) { - case WSAEBADF: - PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); - break; case WSAENOTSOCK: PR_SetError(PR_NOT_SOCKET_ERROR, err); break; case WSAEFAULT: PR_SetError(PR_ACCESS_FAULT_ERROR, err); break; - case WSAENOBUFS: - PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, err); + case WSAENETDOWN: + PR_SetError(PR_NETWORK_DOWN_ERROR, err); + break; + case WSAEINVAL: + PR_SetError(PR_INVALID_STATE_ERROR, err); break; default: PR_SetError(PR_UNKNOWN_ERROR, err); @@ -908,9 +1039,6 @@ void _MD_win32_map_getpeername_error(PRInt32 err) { switch (err) { - case WSAEBADF: - PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); - break; case WSAENOTSOCK: PR_SetError(PR_NOT_SOCKET_ERROR, err); break; @@ -920,8 +1048,8 @@ void _MD_win32_map_getpeername_error(PRInt32 err) case WSAEFAULT: PR_SetError(PR_ACCESS_FAULT_ERROR, err); break; - case WSAENOBUFS: - PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, err); + case WSAENETDOWN: + PR_SetError(PR_NETWORK_DOWN_ERROR, err); break; default: PR_SetError(PR_UNKNOWN_ERROR, err); @@ -932,20 +1060,18 @@ void _MD_win32_map_getpeername_error(PRInt32 err) void _MD_win32_map_getsockopt_error(PRInt32 err) { switch (err) { - case WSAEBADF: - PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); - break; case WSAENOTSOCK: PR_SetError(PR_NOT_SOCKET_ERROR, err); break; + case WSAEINVAL: case WSAENOPROTOOPT: PR_SetError(PR_INVALID_ARGUMENT_ERROR, err); break; case WSAEFAULT: PR_SetError(PR_ACCESS_FAULT_ERROR, err); break; - case WSAEINVAL: - PR_SetError(PR_BUFFER_OVERFLOW_ERROR, err); + case WSAENETDOWN: + PR_SetError(PR_NETWORK_DOWN_ERROR, err); break; default: PR_SetError(PR_UNKNOWN_ERROR, err); @@ -956,20 +1082,24 @@ void _MD_win32_map_getsockopt_error(PRInt32 err) void _MD_win32_map_setsockopt_error(PRInt32 err) { switch (err) { - case WSAEBADF: - PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); - break; case WSAENOTSOCK: PR_SetError(PR_NOT_SOCKET_ERROR, err); break; + case WSAEINVAL: case WSAENOPROTOOPT: PR_SetError(PR_INVALID_ARGUMENT_ERROR, err); break; case WSAEFAULT: PR_SetError(PR_ACCESS_FAULT_ERROR, err); break; - case WSAEINVAL: - PR_SetError(PR_BUFFER_OVERFLOW_ERROR, err); + case WSAENETDOWN: + PR_SetError(PR_NETWORK_DOWN_ERROR, err); + break; + case WSAENETRESET: + PR_SetError(PR_CONNECT_ABORTED_ERROR, err); + break; + case WSAENOTCONN: + PR_SetError(PR_NOT_CONNECTED_ERROR, err); break; default: PR_SetError(PR_UNKNOWN_ERROR, err); @@ -1066,6 +1196,9 @@ void _MD_win32_map_select_error(PRInt32 err) case WSAEFAULT: prerror = PR_ACCESS_FAULT_ERROR; break; + case WSAENETDOWN: + prerror = PR_NETWORK_DOWN_ERROR; + break; default: prerror = PR_UNKNOWN_ERROR; } @@ -1088,9 +1221,11 @@ void _MD_win32_map_lockf_error(PRInt32 err) break; case ERROR_DRIVE_LOCKED: case ERROR_LOCKED: - case ERROR_SHARING_VIOLATION: PR_SetError(PR_FILE_IS_LOCKED_ERROR, err); break; + case ERROR_SHARING_VIOLATION: + PR_SetError(PR_FILE_IS_BUSY_ERROR, err); + break; case ERROR_NOT_ENOUGH_MEMORY: case ERROR_OUTOFMEMORY: PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, err); diff --git a/pr/src/memory/prseg.c b/pr/src/memory/prseg.c index c32c5225..86399186 100644 --- a/pr/src/memory/prseg.c +++ b/pr/src/memory/prseg.c @@ -29,7 +29,7 @@ void _PR_InitSegs(void) ** This memory is not part of the malloc heap. If "vaddr" is not NULL ** then PR tries to allocate the segment at the desired virtual address. */ -PR_IMPLEMENT(PRSegment*) PR_NewSegment(PRUint32 size, void *vaddr) +PRSegment* _PR_NewSegment(PRUint32 size, void *vaddr) { PRSegment *seg; @@ -54,141 +54,8 @@ PR_IMPLEMENT(PRSegment*) PR_NewSegment(PRUint32 size, void *vaddr) /* ** Free a memory segment. */ -PR_IMPLEMENT(void) PR_DestroySegment(PRSegment *seg) +void _PR_DestroySegment(PRSegment *seg) { _PR_MD_FREE_SEGMENT(seg); PR_DELETE(seg); } - -/* XXX Fix the following to make machine-independent */ -#ifdef XP_UNIX -#include <sys/mman.h> -#endif - -#ifndef PROT_NONE -#define PROT_NONE 0 -#endif - -extern PRInt32 _pr_zero_fd; - -/* -** Attempt to grow/shrink the given segment. -*/ -PR_IMPLEMENT(PRUint32) PR_GrowSegment(PRSegment *seg, PRInt32 delta) -{ - char *oldend, *newend; -#if 0 -#ifdef XP_UNIX - int prot; - void *rv = (void *) -1; -#endif -#endif /* 0 */ - - if (!(seg->flags & _PR_SEG_VM)) { - return 0; - } - - oldend = (char*)seg->vaddr + seg->size; - if (delta > 0) { -#if 0 - - /* - * CANNOT use MAP_FIXED because it will replace any existing mappings - */ - /* Growing the segment */ - delta = ((delta + _pr_pageSize - 1) >> _pr_pageShift) << _pr_pageShift; - newend = oldend + delta; -#ifdef XP_UNIX - prot = PROT_READ|PROT_WRITE; - rv = mmap(oldend, delta, prot, -#ifdef OSF1 - /* XXX need to pick a vaddr to use */ - MAP_PRIVATE|MAP_FIXED, -#else - MAP_SHARED|MAP_FIXED, -#endif - _pr_zero_fd, 0); -#endif /* XP_UNIX */ - if (rv == (void*)-1) { - /* Can't extend the heap */ - return 0; - } - seg->size = seg->size + delta; -#endif /* 0 */ - } else if (delta < 0) { - /* Shrinking the segment */ - delta = -delta; - delta = (delta >> _pr_pageShift) << _pr_pageShift; /* trunc */ - if ((PRUint32)delta >= seg->size) { - /* XXX what to do? */ - return 0; - } - newend = oldend - delta; - if (newend < oldend) { -#ifdef XP_UNIX - (void) munmap(oldend, newend - oldend); - seg->size = seg->size + delta; -#endif - } - } - return delta; -} - -/* -** Change the mapping on a segment. -** "how" == PR_SEGMENT_NONE: the segment becomes unmapped -** "how" == PR_SEGMENT_RDONLY: the segment becomes mapped and readable -** "how" == PR_SEGMENT_RDWR: the segment becomes mapped read/write -** -** If a segment can be read then it is also possible to execute code in -** it. -*/ -PR_IMPLEMENT(void) PR_MapSegment(PRSegment *seg, PRSegmentAccess how) -{ - if (seg->access == how) return; - seg->access = how; - -#ifdef XP_UNIX -#ifndef RHAPSODY - if (seg->flags & _PR_SEG_VM) { - int prot; - switch (how) { - case PR_SEGMENT_NONE: - prot = PROT_NONE; - break; - case PR_SEGMENT_RDONLY: - prot = PROT_READ; - break; - case PR_SEGMENT_RDWR: - prot = PROT_READ|PROT_WRITE; - break; - } - (void) mprotect(seg->vaddr, seg->size, prot); - } -#endif -#endif -} - -/* -** Return the size of the segment -*/ -PR_IMPLEMENT(size_t) PR_GetSegmentSize(PRSegment *seg) -{ - return seg->size; -} - -/* -** Return the virtual address of the segment -*/ -PR_IMPLEMENT(void*) PR_GetSegmentVaddr(PRSegment *seg) -{ - return seg->vaddr; -} - -/* -** Return a segments current access rights -*/ -PR_IMPLEMENT(PRSegmentAccess) PR_GetSegmentAccess(PRSegment *seg) -{ - return seg->access; -} diff --git a/pr/src/misc/Makefile b/pr/src/misc/Makefile index 015fc259..313021c8 100644 --- a/pr/src/misc/Makefile +++ b/pr/src/misc/Makefile @@ -28,9 +28,10 @@ OPTIMIZER = endif endif -CSRCS = \ +CSRCS = \ pralarm.c \ pratom.c \ + prcountr.c \ prdtoa.c \ prenv.c \ prerror.c \ @@ -39,9 +40,11 @@ CSRCS = \ prlog2.c \ prlong.c \ prnetdb.c \ + prolock.c \ prsystem.c \ prtime.c \ prthinfo.c \ + prtrace.c \ $(NULL) TARGETS = $(OBJS) diff --git a/pr/src/misc/pratom.c b/pr/src/misc/pratom.c index 78ba8173..d69bb6b0 100644 --- a/pr/src/misc/pratom.c +++ b/pr/src/misc/pratom.c @@ -62,6 +62,20 @@ _PR_MD_ATOMIC_INCREMENT(PRInt32 *val) } PRInt32 +_PR_MD_ATOMIC_ADD(PRInt32 *ptr, PRInt32 val) +{ + PRInt32 rv; + + if (!_pr_initialized) { + _PR_ImplicitInitialization(); + } + PR_Lock(monitor); + rv = ((*ptr) += val); + PR_Unlock(monitor); + return rv; +} + +PRInt32 _PR_MD_ATOMIC_DECREMENT(PRInt32 *val) { PRInt32 rv; @@ -115,3 +129,94 @@ PR_AtomicSet(PRInt32 *val, PRInt32 newval) return _PR_MD_ATOMIC_SET(val, newval); } +PR_IMPLEMENT(PRInt32) +PR_AtomicAdd(PRInt32 *ptr, PRInt32 val) +{ + return _PR_MD_ATOMIC_ADD(ptr, val); +} +/* + * For platforms, which don't support the CAS (compare-and-swap) instruction + * (or an equivalent), the stack operations are implemented by use of PRLock + */ + +PR_IMPLEMENT(PRStack *) +PR_CreateStack(const char *stack_name) +{ +PRStack *stack; + + if (!_pr_initialized) { + _PR_ImplicitInitialization(); + } + + if ((stack = PR_NEW(PRStack)) == NULL) { + return NULL; + } + if (stack_name) { + stack->prstk_name = (char *) PR_Malloc(strlen(stack_name) + 1); + if (stack->prstk_name == NULL) { + PR_DELETE(stack); + return NULL; + } + strcpy(stack->prstk_name, stack_name); + } else + stack->prstk_name = NULL; + +#ifndef _PR_HAVE_ATOMIC_CAS + stack->prstk_lock = PR_NewLock(); + if (stack->prstk_lock == NULL) { + PR_Free(stack->prstk_name); + PR_DELETE(stack); + return NULL; + } +#endif /* !_PR_HAVE_ATOMIC_CAS */ + + stack->prstk_head.prstk_elem_next = NULL; + + return stack; +} + +PR_IMPLEMENT(PRStatus) +PR_DestroyStack(PRStack *stack) +{ + if (stack->prstk_head.prstk_elem_next != NULL) { + PR_SetError(PR_INVALID_STATE_ERROR, 0); + return PR_FAILURE; + } + + if (stack->prstk_name) + PR_Free(stack->prstk_name); +#ifndef _PR_HAVE_ATOMIC_CAS + PR_DestroyLock(stack->prstk_lock); +#endif /* !_PR_HAVE_ATOMIC_CAS */ + PR_DELETE(stack); + + return PR_SUCCESS; +} + +#ifndef _PR_HAVE_ATOMIC_CAS + +PR_IMPLEMENT(void) +PR_StackPush(PRStack *stack, PRStackElem *stack_elem) +{ + PR_Lock(stack->prstk_lock); + stack_elem->prstk_elem_next = stack->prstk_head.prstk_elem_next; + stack->prstk_head.prstk_elem_next = stack_elem; + PR_Unlock(stack->prstk_lock); + return; +} + +PR_IMPLEMENT(PRStackElem *) +PR_StackPop(PRStack *stack) +{ +PRStackElem *element; + + PR_Lock(stack->prstk_lock); + element = stack->prstk_head.prstk_elem_next; + if (element != NULL) { + stack->prstk_head.prstk_elem_next = element->prstk_elem_next; + element->prstk_elem_next = NULL; /* debugging aid */ + } + PR_Unlock(stack->prstk_lock); + return element; +} +#endif /* !_PR_HAVE_ATOMIC_CAS */ diff --git a/pr/src/misc/prcountr.c b/pr/src/misc/prcountr.c new file mode 100644 index 00000000..33e85d82 --- /dev/null +++ b/pr/src/misc/prcountr.c @@ -0,0 +1,510 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "NPL"); you may not use this file except in + * compliance with the NPL. You may obtain a copy of the NPL at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the NPL is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL + * for the specific language governing rights and limitations under the + * NPL. + * + * The Initial Developer of this code under the NPL is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All Rights + * Reserved. + */ + +/* +** prcountr.c -- NSPR Instrumentation Counters +** +** Implement the interface defined in prcountr.h +** +** Design Notes: +** +** The Counter Facility (CF) has a single anchor: qNameList. +** The anchor is a PRCList. qNameList is a list of links in QName +** structures. From qNameList any QName structure and its +** associated RName structure can be located. +** +** For each QName, a list of RName structures is anchored at +** rnLink in the QName structure. +** +** The counter itself is embedded in the RName structure. +** +** For manipulating the counter database, single lock is used to +** protect the entire list: counterLock. +** +** A PRCounterHandle, defined in prcountr.h, is really a pointer +** to a RName structure. References by PRCounterHandle are +** dead-reconed to the RName structure. The PRCounterHandle is +** "overloaded" for traversing the QName structures; only the +** function PR_FindNextQnameHandle() uses this overloading. +** +** +** ToDo (lth): decide on how to lock or atomically update +** individual counters. Candidates are: the global lock; a lock +** per RName structure; Atomic operations (Note that there are +** not adaquate atomic operations (yet) to achieve this goal). At +** this writing (6/19/98) , the update of the counter variable in +** a QName structure is unprotected. +** +*/ + +#if defined(DEBUG) || defined(FORCE_NSPR_COUNTERS) +#include "prcountr.h" +#include "prclist.h" +#include "prlock.h" +#include "prlog.h" +#include "prmem.h" +#include <string.h> + +/* +** +*/ +typedef struct QName +{ + PRCList link; + PRCList rNameList; + char name[PRCOUNTER_NAME_MAX+1]; +} QName; + +/* +** +*/ +typedef struct RName +{ + PRCList link; + QName *qName; + PRLock *lock; + volatile PRUint32 counter; + char name[PRCOUNTER_NAME_MAX+1]; + char desc[PRCOUNTER_DESC_MAX+1]; +} RName; + + +/* +** Define the Counter Facility database +*/ +static PRLock *counterLock; +static PRCList qNameList; +static PRLogModuleInfo *lm; + +/* +** _PR_CounterInitialize() -- Initialize the Counter Facility +** +*/ +static void _PR_CounterInitialize( void ) +{ + /* + ** This function should be called only once + */ + PR_ASSERT( counterLock == NULL ); + + counterLock = PR_NewLock(); + PR_INIT_CLIST( &qNameList ); + lm = PR_NewLogModule("counters"); + PR_LOG( lm, PR_LOG_DEBUG, ("PR_Counter: Initialization complete")); + + return; +} /* end _PR_CounterInitialize() */ + +/* +** PR_CreateCounter() -- Create a counter +** +** ValidateArguments +** Lock +** if (qName not already in database) +** NewQname +** if (rName already in database ) +** Assert +** else NewRname +** NewCounter +** link 'em up +** Unlock +** +*/ +PR_IMPLEMENT(PRCounterHandle) + PR_CreateCounter( + const char *qName, + const char *rName, + const char *description +) +{ + QName *qnp; + RName *rnp; + PRBool matchQname = PR_FALSE; + + /* Self initialize, if necessary */ + if ( counterLock == NULL ) + _PR_CounterInitialize(); + + /* Validate input arguments */ + PR_ASSERT( strlen(qName) <= PRCOUNTER_NAME_MAX ); + PR_ASSERT( strlen(rName) <= PRCOUNTER_NAME_MAX ); + PR_ASSERT( strlen(description) <= PRCOUNTER_DESC_MAX ); + + /* Lock the Facility */ + PR_Lock( counterLock ); + + /* Do we already have a matching QName? */ + if (!PR_CLIST_IS_EMPTY( &qNameList )) + { + qnp = (QName *) PR_LIST_HEAD( &qNameList ); + do { + if ( strcmp(qnp->name, qName) == 0) + { + matchQname = PR_TRUE; + break; + } + qnp = (QName *)PR_NEXT_LINK( &qnp->link ); + } while( qnp != (QName *)PR_LIST_HEAD( &qNameList )); + } + /* + ** If we did not find a matching QName, + ** allocate one and initialize it. + ** link it onto the qNameList. + ** + */ + if ( matchQname != PR_TRUE ) + { + qnp = PR_NEWZAP( QName ); + PR_ASSERT( qnp != NULL ); + PR_INIT_CLIST( &qnp->link ); + PR_INIT_CLIST( &qnp->rNameList ); + strcpy( qnp->name, qName ); + PR_APPEND_LINK( &qnp->link, &qNameList ); + } + + /* Do we already have a matching RName? */ + if (!PR_CLIST_IS_EMPTY( &qnp->rNameList )) + { + rnp = (RName *) PR_LIST_HEAD( &qnp->rNameList ); + do { + /* + ** No duplicate RNames are allowed within a QName + ** + */ + PR_ASSERT( strcmp(rnp->name, rName)); + rnp = (RName *)PR_NEXT_LINK( &rnp->link ); + } while( rnp != (RName *)PR_LIST_HEAD( &qnp->rNameList )); + } + + /* Get a new RName structure; initialize its members */ + rnp = PR_NEWZAP( RName ); + PR_ASSERT( rnp != NULL ); + PR_INIT_CLIST( &rnp->link ); + strcpy( rnp->name, rName ); + strcpy( rnp->desc, description ); + rnp->lock = PR_NewLock(); + if ( rnp->lock == NULL ) + { + PR_ASSERT(0); + } + + PR_APPEND_LINK( &rnp->link, &qnp->rNameList ); /* add RName to QName's rnList */ + rnp->qName = qnp; /* point the RName to the QName */ + + /* Unlock the Facility */ + PR_Unlock( counterLock ); + PR_LOG( lm, PR_LOG_DEBUG, ("PR_Counter: Create: QName: %s %p, RName: %s %p\n\t", + qName, qnp, rName, rnp )); + + return((PRCounterHandle)rnp); +} /* end PR_CreateCounter() */ + + +/* +** +*/ +PR_IMPLEMENT(void) + PR_DestroyCounter( + PRCounterHandle handle +) +{ + RName *rnp = (RName *)handle; + QName *qnp = rnp->qName; + + PR_LOG( lm, PR_LOG_DEBUG, ("PR_Counter: Deleting: QName: %s, RName: %s", + qnp->name, rnp->name)); + + /* Lock the Facility */ + PR_Lock( counterLock ); + + /* + ** Remove RName from the list of RNames in QName + ** and free RName + */ + PR_LOG( lm, PR_LOG_DEBUG, ("PR_Counter: Deleting RName: %s, %p", + rnp->name, rnp)); + PR_REMOVE_LINK( &rnp->link ); + PR_Free( rnp->lock ); + PR_DELETE( rnp ); + + /* + ** If this is the last RName within QName + ** remove QName from the qNameList and free it + */ + if ( PR_CLIST_IS_EMPTY( &qnp->rNameList ) ) + { + PR_LOG( lm, PR_LOG_DEBUG, ("PR_Counter: Deleting unused QName: %s, %p", + qnp->name, qnp)); + PR_REMOVE_LINK( &qnp->link ); + PR_DELETE( qnp ); + } + + /* Unlock the Facility */ + PR_Unlock( counterLock ); + return; +} /* end PR_DestroyCounter() */ + +/* +** +*/ +PR_IMPLEMENT(PRCounterHandle) + PR_GetCounterHandleFromName( + const char *qName, + const char *rName +) +{ + const char *qn, *rn, *desc; + PRCounterHandle qh, rh; + RName *rnp = NULL; + + PR_LOG( lm, PR_LOG_DEBUG, ("PR_Counter: GetCounterHandleFromName:\n\t" + "QName: %s, RName: %s", qName, rName )); + + qh = PR_FindNextCounterQname( NULL ); + while (qh != NULL) + { + rh = PR_FindNextCounterRname( NULL, qh ); + while ( rh != NULL ) + { + PR_GetCounterNameFromHandle( rh, &qn, &rn, &desc ); + if ( (strcmp( qName, qn ) == 0) + && (strcmp( rName, rn ) == 0 )) + { + rnp = (RName *)rh; + goto foundIt; + } + rh = PR_FindNextCounterRname( rh, qh ); + } + qh = PR_FindNextCounterQname( NULL ); + } + +foundIt: + PR_LOG( lm, PR_LOG_DEBUG, ("PR_Counter: GetConterHandleFromName: %p", rnp )); + return(rh); +} /* end PR_GetCounterHandleFromName() */ + +/* +** +*/ +PR_IMPLEMENT(void) + PR_GetCounterNameFromHandle( + PRCounterHandle handle, + const char **qName, + const char **rName, + const char **description +) +{ + RName *rnp = (RName *)handle; + QName *qnp = rnp->qName; + + *qName = qnp->name; + *rName = rnp->name; + *description = rnp->desc; + + PR_LOG( lm, PR_LOG_DEBUG, ("PR_Counter: GetConterNameFromHandle: " + "QNp: %p, RNp: %p,\n\tQName: %s, RName: %s, Desc: %s", + qnp, rnp, qnp->name, rnp->name, rnp->desc )); + + return; +} /* end PR_GetCounterNameFromHandle() */ + + +/* +** +*/ +PR_IMPLEMENT(void) + PR_IncrementCounter( + PRCounterHandle handle +) +{ + PR_Lock(((RName *)handle)->lock); + ((RName *)handle)->counter++; + PR_Unlock(((RName *)handle)->lock); + + PR_LOG( lm, PR_LOG_DEBUG, ("PR_Counter: Increment: %p, %ld", + handle, ((RName *)handle)->counter )); + + return; +} /* end PR_IncrementCounter() */ + + + +/* +** +*/ +PR_IMPLEMENT(void) + PR_DecrementCounter( + PRCounterHandle handle +) +{ + PR_Lock(((RName *)handle)->lock); + ((RName *)handle)->counter--; + PR_Unlock(((RName *)handle)->lock); + + PR_LOG( lm, PR_LOG_DEBUG, ("PR_Counter: Decrement: %p, %ld", + handle, ((RName *)handle)->counter )); + + return; +} /* end PR_DecrementCounter() */ + + +/* +** +*/ +PR_IMPLEMENT(void) + PR_AddToCounter( + PRCounterHandle handle, + PRUint32 value +) +{ + PR_Lock(((RName *)handle)->lock); + ((RName *)handle)->counter += value; + PR_Unlock(((RName *)handle)->lock); + + PR_LOG( lm, PR_LOG_DEBUG, ("PR_Counter: AddToCounter: %p, %ld", + handle, ((RName *)handle)->counter )); + + return; +} /* end PR_AddToCounter() */ + + +/* +** +*/ +PR_IMPLEMENT(void) + PR_SubtractFromCounter( + PRCounterHandle handle, + PRUint32 value +) +{ + PR_Lock(((RName *)handle)->lock); + ((RName *)handle)->counter -= value; + PR_Unlock(((RName *)handle)->lock); + + PR_LOG( lm, PR_LOG_DEBUG, ("PR_Counter: SubtractFromCounter: %p, %ld", + handle, ((RName *)handle)->counter )); + + return; +} /* end PR_SubtractFromCounter() */ + +/* +** +*/ +PR_IMPLEMENT(PRUint32) + PR_GetCounter( + PRCounterHandle handle +) +{ + PR_LOG( lm, PR_LOG_DEBUG, ("PR_Counter: GetCounter: %p, %ld", + handle, ((RName *)handle)->counter )); + + return(((RName *)handle)->counter); +} /* end PR_GetCounter() */ + +/* +** +*/ +PR_IMPLEMENT(void) + PR_SetCounter( + PRCounterHandle handle, + PRUint32 value +) +{ + ((RName *)handle)->counter = value; + + PR_LOG( lm, PR_LOG_DEBUG, ("PR_Counter: SetCounter: %p, %ld", + handle, ((RName *)handle)->counter )); + + return; +} /* end PR_SetCounter() */ + +/* +** +*/ +PR_IMPLEMENT(PRCounterHandle) + PR_FindNextCounterQname( + PRCounterHandle handle +) +{ + QName *qnp = (QName *)handle; + + if ( PR_CLIST_IS_EMPTY( &qNameList )) + qnp = NULL; + else if ( qnp == NULL ) + qnp = (QName *)PR_LIST_HEAD( &qNameList ); + else if ( PR_NEXT_LINK( &qnp->link ) == &qNameList ) + qnp = NULL; + else + qnp = (QName *)PR_NEXT_LINK( &qnp->link ); + + PR_LOG( lm, PR_LOG_DEBUG, ("PR_Counter: FindNextQname: Handle: %p, Returns: %p", + handle, qnp )); + + return((PRCounterHandle)qnp); +} /* end PR_FindNextCounterQname() */ + + +/* +** +*/ +PR_IMPLEMENT(PRCounterHandle) + PR_FindNextCounterRname( + PRCounterHandle rhandle, + PRCounterHandle qhandle +) +{ + RName *rnp = (RName *)rhandle; + QName *qnp = (QName *)qhandle; + + + if ( PR_CLIST_IS_EMPTY( &qnp->rNameList )) + rnp = NULL; + else if ( rnp == NULL ) + rnp = (RName *)PR_LIST_HEAD( &qnp->rNameList ); + else if ( PR_NEXT_LINK( &rnp->link ) == &qnp->rNameList ) + rnp = NULL; + else + rnp = (RName *)PR_NEXT_LINK( &rnp->link ); + + PR_LOG( lm, PR_LOG_DEBUG, ("PR_Counter: FindNextRname: Rhandle: %p, QHandle: %p, Returns: %p", + rhandle, qhandle, rnp )); + + return((PRCounterHandle)rnp); +} /* end PR_FindNextCounterRname() */ + + +#else /* !(defined(DEBUG) || defined(FORCE_NSPR_COUNTERS)) */ +/* +** NSPR Counters are not defined in this case +** +** +*/ +#endif /* defined(DEBUG) || defined(FORCE_NSPR_COUNTERS) */ + + + + + + + + + + + + + diff --git a/pr/src/misc/prdtoa.c b/pr/src/misc/prdtoa.c index ef3d50a0..3fadb2b1 100644 --- a/pr/src/misc/prdtoa.c +++ b/pr/src/misc/prdtoa.c @@ -1842,7 +1842,7 @@ quorem(Bigint *b, Bigint *S) */ PR_IMPLEMENT(PRStatus) -PR_dtoa(double d, int mode, int ndigits, +PR_dtoa(PRFloat64 d, int mode, int ndigits, int *decpt, int *sign, char **rve, char *buf, PRSize bufsize) { /* Arguments ndigits, decpt, sign are similar to those diff --git a/pr/src/misc/prinit.c b/pr/src/misc/prinit.c index 7c52b38b..4178e3ee 100644 --- a/pr/src/misc/prinit.c +++ b/pr/src/misc/prinit.c @@ -45,8 +45,8 @@ PRCList _pr_cpuQ = PR_INIT_STATIC_CLIST(&_pr_cpuQ); PRUint32 _pr_utid; -PRUintn _pr_userActive; -PRUintn _pr_systemActive; +PRInt32 _pr_userActive; +PRInt32 _pr_systemActive; PRUintn _pr_maxPTDs; #ifdef _PR_LOCAL_THREADS_ONLY @@ -66,29 +66,27 @@ PRLock *_pr_terminationCVLock; PRLock *_pr_sleeplock; /* used in PR_Sleep(), classic and pthreads */ static void _PR_InitCallOnce(void); -static void _PR_InitStuff(void); -/************************************************************************/ -/**************************IDENTITY AND VERSIONING***********************/ -/************************************************************************/ +PRBool _pr_initialized = PR_FALSE; + + PR_IMPLEMENT(PRBool) PR_VersionCheck(const char *importedVersion) { /* ** This is the secret handshake algorithm. Right now it requires - ** an exact match. Later it should get more tricky. + ** an exact match. Later it should get more clever. */ + if (!_pr_initialized) _PR_ImplicitInitialization(); return ((0 == strcmp(importedVersion, PR_VERSION)) ? PR_TRUE : PR_FALSE); } /* PR_VersionCheck */ -PRBool _pr_initialized = PR_FALSE; - PR_IMPLEMENT(PRBool) PR_Initialized(void) { return _pr_initialized; } -static void _PR_InitStuff() +static void _PR_InitStuff(void) { if (_pr_initialized) return; _pr_initialized = PR_TRUE; @@ -108,13 +106,14 @@ static void _PR_InitStuff() /* NOTE: These init's cannot depend on _PR_MD_CURRENT_THREAD() */ _PR_MD_EARLY_INIT(); - _PR_InitAtomic(); _PR_InitLocks(); + _PR_InitAtomic(); _PR_InitSegs(); _PR_InitStacks(); _PR_InitTPD(); _PR_InitEnv(); _PR_InitLayerCache(); + _PR_InitClock(); _pr_sleeplock = PR_NewLock(); PR_ASSERT(NULL != _pr_sleeplock); @@ -143,13 +142,13 @@ static void _PR_InitStuff() _PR_InitCMon(); _PR_InitIO(); _PR_InitNet(); - _PR_InitClock(); #ifdef PR_LOGGING _PR_InitLog(); #endif _PR_InitLinker(); _PR_InitCallOnce(); _PR_InitDtoa(); + _PR_InitMW(); _PR_MD_FINAL_INIT(); } @@ -176,6 +175,16 @@ PR_IMPLEMENT(void) PR_DisableClockInterrupts(void) #endif } +PR_IMPLEMENT(void) PR_EnableClockInterrupts(void) +{ +#if !defined(_PR_PTHREADS) + if (!_pr_initialized) { + _PR_InitStuff(); + } + _PR_MD_ENABLE_CLOCK_INTERRUPTS(); +#endif +} + PR_IMPLEMENT(void) PR_BlockClockInterrupts(void) { #if !defined(_PR_PTHREADS) @@ -285,7 +294,6 @@ PR_IMPLEMENT(PRStatus) PR_Cleanup() PR_ASSERT((NULL != me) && (me->flags & _PR_PRIMORDIAL)); if ((NULL != me) && (me->flags & _PR_PRIMORDIAL)) { - PR_LOG(_pr_thread_lm, PR_LOG_MIN, ("PR_Cleanup: shutting down NSPR")); /* @@ -303,6 +311,14 @@ PR_IMPLEMENT(PRStatus) PR_Cleanup() } PR_Unlock(_pr_activeLock); +#ifdef IRIX + _PR_MD_PRE_CLEANUP(me); + /* + * The primordial thread must now be running on the primordial cpu + */ + PR_ASSERT((_PR_IS_NATIVE_THREAD(me)) || (me->cpu->id == 0)); +#endif + #if defined(WIN16) _PR_ShutdownLinker(); #endif @@ -316,6 +332,7 @@ PR_IMPLEMENT(PRStatus) PR_Cleanup() #ifdef PR_LOGGING _PR_LogCleanup(); #endif + _PR_CleanupFdCache(); /* * This part should look like the end of _PR_NativeRunThread diff --git a/pr/src/misc/prolock.c b/pr/src/misc/prolock.c new file mode 100644 index 00000000..08123640 --- /dev/null +++ b/pr/src/misc/prolock.c @@ -0,0 +1,91 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "NPL"); you may not use this file except in + * compliance with the NPL. You may obtain a copy of the NPL at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the NPL is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL + * for the specific language governing rights and limitations under the + * NPL. + * + * The Initial Developer of this code under the NPL is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All Rights + * Reserved. + */ + +/* +** prolock.c -- NSPR Ordered Lock +** +** Implement the API defined in prolock.h +** +*/ +#if defined(DEBUG) || defined(FORCE_NSPR_COUNTERS) +#include "prolock.h" +#include "prlog.h" +#include "prerror.h" + +PR_IMPLEMENT(PROrderedLock *) + PR_CreateOrderedLock( + PRInt32 order, + const char *name +) +{ + PR_ASSERT(!"Not implemented"); /* Not implemented yet */ + PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); + return NULL; +} /* end PR_CreateOrderedLock() */ + + +PR_IMPLEMENT(void) + PR_DestroyOrderedLock( + PROrderedLock *lock +) +{ + PR_ASSERT(!"Not implemented"); /* Not implemented yet */ + PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); +} /* end PR_DestroyOrderedLock() */ + + +PR_IMPLEMENT(void) + PR_LockOrderedLock( + PROrderedLock *lock +) +{ + PR_ASSERT(!"Not implemented"); /* Not implemented yet */ + PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); +} /* end PR_LockOrderedLock() */ + + +PR_IMPLEMENT(PRStatus) + PR_UnlockOrderedLock( + PROrderedLock *lock +) +{ + PR_ASSERT(!"Not implemented"); /* Not implemented yet */ + PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); + return PR_FAILURE; +} /* end PR_UnlockOrderedLock() */ + +#else /* ! defined(FORCE_NSPR_ORDERED_LOCK) */ +/* +** NSPR Ordered Lock is not defined when !DEBUG and !FORCE_NSPR_ORDERED_LOCK +** +*/ + +#endif /* defined(FORCE_NSPR_ORDERED_LOCK */ + + + + + + + + + + + + + diff --git a/pr/src/misc/prthinfo.c b/pr/src/misc/prthinfo.c index 6f6ad1e7..e53fc3f2 100644 --- a/pr/src/misc/prthinfo.c +++ b/pr/src/misc/prthinfo.c @@ -126,13 +126,10 @@ PR_ThreadScanStackPointers(PRThread* t, /* ** Mark all of the per-thread-data items attached to this thread + ** + ** The execution environment better be accounted for otherwise it + ** will be collected */ - -#if defined(_PR_PTHREADS) -/* PR_ASSERT(!"I can't do this!"); */ -#else /* defined(_PR_PTHREADS) */ - - /* the execution environment better be accounted for otherwise it will be collected */ status = scanFun(t, (void**)&t->environment, 1, scanClosure); if (status != PR_SUCCESS) return status; @@ -143,8 +140,7 @@ PR_ThreadScanStackPointers(PRThread* t, if (status != PR_SUCCESS) return status; } -#endif /* defined(_PR_PTHREADS) */ - + return PR_SUCCESS; } @@ -173,7 +169,7 @@ PR_ScanStackPointers(PRScanStackFun scanFun, void* scanClosure) return PR_EnumerateThreads(pr_ScanStack, &data); } -PR_PUBLIC_API(PRUword) +PR_IMPLEMENT(PRUword) PR_GetStackSpaceLeft(PRThread* t) { PRThread *current = PR_CurrentThread(); diff --git a/pr/src/misc/prtime.c b/pr/src/misc/prtime.c index 59ea80d4..25bccf79 100644 --- a/pr/src/misc/prtime.c +++ b/pr/src/misc/prtime.c @@ -524,16 +524,23 @@ PR_NormalizeTime(PRExplodedTime *time, PRTimeParamFn params) #include <time.h> -#if (defined(OSF1) && !defined(OSF1V4)) || defined(HPUX10_10) \ - || defined(HPUX10_20) +#if defined(HAVE_INT_LOCALTIME_R) + +/* + * In this case we could define the macro as + * #define MT_safe_localtime(timer, result) \ + * (localtime_r(timer, result) == 0 ? result : NULL) + * I chose to compare the return value of localtime_r with -1 so + * that I can catch the cases where localtime_r returns a pointer + * to struct tm. The macro definition above would not be able to + * detect such mistakes because it is legal to compare a pointer + * with 0. + */ #define MT_safe_localtime(timer, result) \ - (localtime_r(timer, result) == 0 ? result : NULL) + (localtime_r(timer, result) == -1 ? NULL: result) -#elif (defined(SOLARIS) && defined(_REENTRANT)) || defined(IRIX) \ - || (defined(AIX) && !defined(AIX4_1) && defined(_THREAD_SAFE)) \ - || defined(OSF1V4) \ - || defined(HPUX10_30) || defined(HPUX11) +#elif defined(HAVE_POINTER_LOCALTIME_R) #define MT_safe_localtime localtime_r @@ -1623,12 +1630,12 @@ PR_FormatTime(char *buf, int buflen, const char *fmt, const PRExplodedTime *tm) a.tm_isdst = tm->tm_params.tp_dst_offset ? 1 : 0; /* - * On SunOS 4, struct tm has two additional fields: tm_zone - * and tm_gmtoff. The following code attempts to obtain values for - * these two fields. + * On some platforms, for example SunOS 4, struct tm has two additional + * fields: tm_zone and tm_gmtoff. The following code attempts to obtain + * values for these two fields. */ -#if defined(SUNOS4) || defined(MKLINUX) || (__GLIBC__ >= 2) +#if defined(SUNOS4) || (__GLIBC__ >= 2) if (mktime(&a) == -1) { PR_snprintf(buf, buflen, "can't get timezone"); return 0; diff --git a/pr/src/misc/prtrace.c b/pr/src/misc/prtrace.c new file mode 100644 index 00000000..c2a64b6c --- /dev/null +++ b/pr/src/misc/prtrace.c @@ -0,0 +1,912 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "NPL"); you may not use this file except in + * compliance with the NPL. You may obtain a copy of the NPL at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the NPL is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL + * for the specific language governing rights and limitations under the + * NPL. + * + * The Initial Developer of this code under the NPL is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All Rights + * Reserved. + */ + +/* +** prtrace.c -- NSPR Trace Instrumentation +** +** Implement the API defined in prtrace.h +** +** +** +*/ + +#if defined (DEBUG) || defined (FORCE_NSPR_TRACE) +#include <string.h> +#include "prtrace.h" +#include "prclist.h" +#include "prlock.h" +#include "prcvar.h" +#include "prio.h" +#include "prlog.h" +#include "prenv.h" +#include "prmem.h" +#include "prerror.h" + + +#define DEFAULT_TRACE_BUFSIZE ( 1024 * 1024 ) +#define DEFAULT_BUFFER_SEGMENTS 2 + +/* +** Enumerate states in a RName structure +*/ +typedef enum TraceState +{ + Running = 1, + Suspended = 2 +} TraceState; + +/* +** Define QName structure +*/ +typedef struct QName +{ + PRCList link; + PRCList rNameList; + char name[PRTRACE_NAME_MAX+1]; +} QName; + +/* +** Define RName structure +*/ +typedef struct RName +{ + PRCList link; + PRLock *lock; + QName *qName; + TraceState state; + char name[PRTRACE_NAME_MAX+1]; + char desc[PRTRACE_DESC_MAX+1]; +} RName; + + +/* +** The Trace Facility database +** +*/ +static PRLogModuleInfo *lm; + +static PRLock *traceLock; /* Facility Lock */ +static PRCList qNameList; /* anchor to all QName structures */ +static TraceState traceState = Running; + +/* +** in-memory trace buffer controls +*/ +static PRTraceEntry *tBuf; /* pointer to buffer */ +static PRInt32 bufSize; /* size of buffer, in bytes, rounded up to sizeof(PRTraceEntry) */ +static volatile PRInt32 next; /* index to next PRTraceEntry */ +static PRInt32 last; /* index of highest numbered trace entry */ + +/* +** Real-time buffer capture controls +*/ +static PRInt32 fetchLastSeen = 0; +static PRBool fetchLostData = PR_FALSE; + +/* +** Buffer write-to-file controls +*/ +static PRLock *logLock; /* Sync lock */ +static PRCondVar *logCVar; /* Sync Condidtion Variable */ +/* +** Inter-thread state communication. +** Controling thread writes to logOrder under protection of logCVar +** the logging thread reads logOrder and sets logState on Notify. +** +** logSegments, logCount, logLostData must be read and written under +** protection of logLock, logCVar. +** +*/ +static enum LogState +{ + LogNotRunning, /* Initial state */ + LogReset, /* Causes logger to re-calc controls */ + LogActive, /* Logging in progress, set only by log thread */ + LogSuspend, /* Suspend Logging */ + LogResume, /* Resume Logging => LogActive */ + LogStop /* Stop the log thread */ +} logOrder, logState, localState; /* controlling state variables */ +static PRInt32 logSegments; /* Number of buffer segments */ +static PRInt32 logEntries; /* number of Trace Entries in the buffer */ +static PRInt32 logEntriesPerSegment; /* number of PRTraceEntries per buffer segment */ +static PRInt32 logSegSize; /* size of buffer segment */ +static PRInt32 logCount; /* number of segments pending output */ +static PRInt32 logLostData; /* number of lost log buffer segments */ + +/* +** end Trace Database +** +*/ + +/* +** _PR_InitializeTrace() -- Initialize the trace facility +*/ +static void NewTraceBuffer( PRInt32 size ) +{ + /* + ** calculate the size of the buffer + ** round down so that each segment has the same number of + ** trace entries + */ + logSegments = DEFAULT_BUFFER_SEGMENTS; + logEntries = size / sizeof(PRTraceEntry); + logEntriesPerSegment = logEntries / logSegments; + logEntries = logSegments * logEntriesPerSegment; + bufSize = logEntries * sizeof(PRTraceEntry); + logSegSize = logEntriesPerSegment * sizeof(PRTraceEntry); + PR_ASSERT( bufSize != 0); + PR_LOG( lm, PR_LOG_ERROR, + ("NewTraceBuffer: logSegments: %ld, logEntries: %ld, logEntriesPerSegment: %ld, logSegSize: %ld", + logSegments, logEntries, logEntriesPerSegment, logSegSize )); + + + tBuf = PR_Malloc( bufSize ); + if ( tBuf == NULL ) + { + PR_LOG( lm, PR_LOG_ERROR, + ("PRTrace: Failed to get trace buffer")); + PR_ASSERT( 0 ); + } + else + { + PR_LOG( lm, PR_LOG_NOTICE, + ("PRTrace: Got trace buffer of size: %ld, at %p", bufSize, tBuf)); + } + + next = 0; + last = logEntries -1; + logCount = 0; + logLostData = PR_TRUE; /* not really on first call */ + logOrder = LogReset; + +} /* end NewTraceBuffer() */ + +/* +** _PR_InitializeTrace() -- Initialize the trace facility +*/ +static void _PR_InitializeTrace( void ) +{ + /* The lock pointer better be null on this call */ + PR_ASSERT( traceLock == NULL ); + + traceLock = PR_NewLock(); + PR_ASSERT( traceLock != NULL ); + + PR_Lock( traceLock ); + + PR_INIT_CLIST( &qNameList ); + + lm = PR_NewLogModule("trace"); + + bufSize = DEFAULT_TRACE_BUFSIZE; + NewTraceBuffer( bufSize ); + + /* Initialize logging controls */ + logLock = PR_NewLock(); + logCVar = PR_NewCondVar( logLock ); + + PR_Unlock( traceLock ); + return; +} /* end _PR_InitializeTrace() */ + +/* +** Create a Trace Handle +*/ +PR_IMPLEMENT(PRTraceHandle) + PR_CreateTrace( + const char *qName, /* QName for this trace handle */ + const char *rName, /* RName for this trace handle */ + const char *description /* description for this trace handle */ +) +{ + QName *qnp; + RName *rnp; + PRBool matchQname = PR_FALSE; + + /* Self initialize, if necessary */ + if ( traceLock == NULL ) + _PR_InitializeTrace(); + + /* Validate input arguments */ + PR_ASSERT( strlen(qName) <= PRTRACE_NAME_MAX ); + PR_ASSERT( strlen(rName) <= PRTRACE_NAME_MAX ); + PR_ASSERT( strlen(description) <= PRTRACE_DESC_MAX ); + + PR_LOG( lm, PR_LOG_DEBUG, + ("PRTRACE: CreateTrace: Qname: %s, RName: %s", qName, rName)); + + /* Lock the Facility */ + PR_Lock( traceLock ); + + /* Do we already have a matching QName? */ + if (!PR_CLIST_IS_EMPTY( &qNameList )) + { + qnp = (QName *) PR_LIST_HEAD( &qNameList ); + do { + if ( strcmp(qnp->name, qName) == 0) + { + matchQname = PR_TRUE; + break; + } + qnp = (QName *)PR_NEXT_LINK( &qnp->link ); + } while( qnp != (QName *)PR_LIST_HEAD( &qNameList )); + } + /* + ** If we did not find a matching QName, + ** allocate one and initialize it. + ** link it onto the qNameList. + ** + */ + if ( matchQname != PR_TRUE ) + { + qnp = PR_NEWZAP( QName ); + PR_ASSERT( qnp != NULL ); + PR_INIT_CLIST( &qnp->link ); + PR_INIT_CLIST( &qnp->rNameList ); + strcpy( qnp->name, qName ); + PR_APPEND_LINK( &qnp->link, &qNameList ); + } + + /* Do we already have a matching RName? */ + if (!PR_CLIST_IS_EMPTY( &qnp->rNameList )) + { + rnp = (RName *) PR_LIST_HEAD( &qnp->rNameList ); + do { + /* + ** No duplicate RNames are allowed within a QName + ** + */ + PR_ASSERT( strcmp(rnp->name, rName)); + rnp = (RName *)PR_NEXT_LINK( &rnp->link ); + } while( rnp != (RName *)PR_LIST_HEAD( &qnp->rNameList )); + } + + /* Get a new RName structure; initialize its members */ + rnp = PR_NEWZAP( RName ); + PR_ASSERT( rnp != NULL ); + PR_INIT_CLIST( &rnp->link ); + strcpy( rnp->name, rName ); + strcpy( rnp->desc, description ); + rnp->lock = PR_NewLock(); + rnp->state = Running; + if ( rnp->lock == NULL ) + { + PR_ASSERT(0); + } + + PR_APPEND_LINK( &rnp->link, &qnp->rNameList ); /* add RName to QName's rnList */ + rnp->qName = qnp; /* point the RName to the QName */ + + /* Unlock the Facility */ + PR_Unlock( traceLock ); + PR_LOG( lm, PR_LOG_DEBUG, ("PRTrace: Create: QName: %s %p, RName: %s %p\n\t", + qName, qnp, rName, rnp )); + + return((PRTraceHandle)rnp); +} /* end PR_CreateTrace() */ + +/* +** +*/ +PR_IMPLEMENT(void) + PR_DestroyTrace( + PRTraceHandle handle /* Handle to be destroyed */ +) +{ + RName *rnp = (RName *)handle; + QName *qnp = rnp->qName; + + PR_LOG( lm, PR_LOG_DEBUG, ("PRTrace: Deleting: QName: %s, RName: %s", + qnp->name, rnp->name)); + + /* Lock the Facility */ + PR_Lock( traceLock ); + + /* + ** Remove RName from the list of RNames in QName + ** and free RName + */ + PR_LOG( lm, PR_LOG_DEBUG, ("PRTrace: Deleting RName: %s, %p", + rnp->name, rnp)); + PR_REMOVE_LINK( &rnp->link ); + PR_Free( rnp->lock ); + PR_DELETE( rnp ); + + /* + ** If this is the last RName within QName + ** remove QName from the qNameList and free it + */ + if ( PR_CLIST_IS_EMPTY( &qnp->rNameList ) ) + { + PR_LOG( lm, PR_LOG_DEBUG, ("PRTrace: Deleting unused QName: %s, %p", + qnp->name, qnp)); + PR_REMOVE_LINK( &qnp->link ); + PR_DELETE( qnp ); + } + + /* Unlock the Facility */ + PR_Unlock( traceLock ); + return; +} /* end PR_DestroyTrace() */ + +/* +** Create a TraceEntry in the trace buffer +*/ +PR_IMPLEMENT(void) + PR_Trace( + PRTraceHandle handle, /* use this trace handle */ + PRUint32 userData0, /* User supplied data word 0 */ + PRUint32 userData1, /* User supplied data word 1 */ + PRUint32 userData2, /* User supplied data word 2 */ + PRUint32 userData3, /* User supplied data word 3 */ + PRUint32 userData4, /* User supplied data word 4 */ + PRUint32 userData5, /* User supplied data word 5 */ + PRUint32 userData6, /* User supplied data word 6 */ + PRUint32 userData7 /* User supplied data word 7 */ +) +{ + PRTraceEntry *tep; + PRInt32 mark; + + if ( (traceState == Suspended ) + || ( ((RName *)handle)->state == Suspended )) + return; + + /* + ** Get the next trace entry slot w/ minimum delay + */ + PR_Lock( traceLock ); + + tep = &tBuf[next++]; + if ( next > last ) + next = 0; + if ( fetchLostData == PR_FALSE && next == fetchLastSeen ) + fetchLostData = PR_TRUE; + + mark = next; + + PR_Unlock( traceLock ); + + /* + ** We have a trace entry. Fill it in. + */ + tep->thread = PR_GetCurrentThread(); + tep->handle = handle; + tep->time = PR_Now(); + tep->userData[0] = userData0; + tep->userData[1] = userData1; + tep->userData[2] = userData2; + tep->userData[3] = userData3; + tep->userData[4] = userData4; + tep->userData[5] = userData5; + tep->userData[6] = userData6; + tep->userData[7] = userData7; + + /* When buffer segment is full, signal trace log thread to run */ + if (( mark % logEntriesPerSegment) == 0 ) + { + PR_Lock( logLock ); + logCount++; + PR_NotifyCondVar( logCVar ); + PR_Unlock( logLock ); + /* + ** Gh0D! This is awful! + ** Anyway, to minimize lost trace data segments, + ** I inserted the PR_Sleep(0) to cause a context switch + ** so that the log thread could run. + ** I know, it perturbs the universe and may cause + ** funny things to happen in the optimized builds. + ** Take it out, loose data; leave it in risk Heisenberg. + */ + /* PR_Sleep(0); */ + } + + return; +} /* end PR_Trace() */ + +/* +** +*/ +PR_IMPLEMENT(void) + PR_SetTraceOption( + PRTraceOption command, /* One of the enumerated values */ + void *value /* command value or NULL */ +) +{ + RName * rnp; + + switch ( command ) + { + case PRTraceBufSize : + PR_Lock( traceLock ); + PR_Free( tBuf ); + bufSize = *(PRInt32 *)value; + NewTraceBuffer( bufSize ); + PR_Unlock( traceLock ); + PR_LOG( lm, PR_LOG_DEBUG, + ("PRSetTraceOption: PRTraceBufSize: %ld", bufSize)); + break; + + case PRTraceEnable : + rnp = *(RName **)value; + rnp->state = Running; + PR_LOG( lm, PR_LOG_DEBUG, + ("PRSetTraceOption: PRTraceEnable: %p", rnp)); + break; + + case PRTraceDisable : + rnp = *(RName **)value; + rnp->state = Suspended; + PR_LOG( lm, PR_LOG_DEBUG, + ("PRSetTraceOption: PRTraceDisable: %p", rnp)); + break; + + case PRTraceSuspend : + traceState = Suspended; + PR_LOG( lm, PR_LOG_DEBUG, + ("PRSetTraceOption: PRTraceSuspend")); + break; + + case PRTraceResume : + traceState = Running; + PR_LOG( lm, PR_LOG_DEBUG, + ("PRSetTraceOption: PRTraceResume")); + break; + + case PRTraceSuspendRecording : + PR_Lock( logLock ); + logOrder = LogSuspend; + PR_NotifyCondVar( logCVar ); + PR_Unlock( logLock ); + PR_LOG( lm, PR_LOG_DEBUG, + ("PRSetTraceOption: PRTraceSuspendRecording")); + break; + + case PRTraceResumeRecording : + PR_LOG( lm, PR_LOG_DEBUG, + ("PRSetTraceOption: PRTraceResumeRecording")); + if ( logState != LogSuspend ) + break; + PR_Lock( logLock ); + logOrder = LogResume; + PR_NotifyCondVar( logCVar ); + PR_Unlock( logLock ); + break; + + case PRTraceStopRecording : + PR_Lock( logLock ); + logOrder = LogStop; + PR_NotifyCondVar( logCVar ); + PR_Unlock( logLock ); + PR_LOG( lm, PR_LOG_DEBUG, + ("PRSetTraceOption: PRTraceStopRecording")); + break; + + case PRTraceLockHandles : + PR_LOG( lm, PR_LOG_DEBUG, + ("PRSetTraceOption: PRTraceLockTraceHandles")); + PR_Lock( traceLock ); + break; + + case PRTraceUnLockHandles : + PR_LOG( lm, PR_LOG_DEBUG, + ("PRSetTraceOption: PRTraceUnLockHandles")); + PR_Lock( traceLock ); + break; + + default: + PR_LOG( lm, PR_LOG_ERROR, + ("PRSetTraceOption: Invalid command %ld", command )); + PR_ASSERT( 0 ); + break; + } /* end switch() */ + return; +} /* end PR_SetTraceOption() */ + +/* +** +*/ +PR_IMPLEMENT(void) + PR_GetTraceOption( + PRTraceOption command, /* One of the enumerated values */ + void *value /* command value or NULL */ +) +{ + switch ( command ) + { + case PRTraceBufSize : + *((PRInt32 *)value) = bufSize; + PR_LOG( lm, PR_LOG_DEBUG, + ("PRGetTraceOption: PRTraceBufSize: %ld", bufSize )); + break; + + default: + PR_LOG( lm, PR_LOG_ERROR, + ("PRGetTraceOption: Invalid command %ld", command )); + PR_ASSERT( 0 ); + break; + } /* end switch() */ + return; +} /* end PR_GetTraceOption() */ + +/* +** +*/ +PR_IMPLEMENT(PRTraceHandle) + PR_GetTraceHandleFromName( + const char *qName, /* QName search argument */ + const char *rName /* RName search argument */ +) +{ + const char *qn, *rn, *desc; + PRTraceHandle qh, rh; + RName *rnp = NULL; + + PR_LOG( lm, PR_LOG_DEBUG, ("PRTrace: GetTraceHandleFromName:\n\t" + "QName: %s, RName: %s", qName, rName )); + + qh = PR_FindNextTraceQname( NULL ); + while (qh != NULL) + { + rh = PR_FindNextTraceRname( NULL, qh ); + while ( rh != NULL ) + { + PR_GetTraceNameFromHandle( rh, &qn, &rn, &desc ); + if ( (strcmp( qName, qn ) == 0) + && (strcmp( rName, rn ) == 0 )) + { + rnp = (RName *)rh; + goto foundIt; + } + rh = PR_FindNextTraceRname( rh, qh ); + } + qh = PR_FindNextTraceQname( NULL ); + } + +foundIt: + PR_LOG( lm, PR_LOG_DEBUG, ("PR_Counter: GetConterHandleFromName: %p", rnp )); + return(rh); +} /* end PR_GetTraceHandleFromName() */ + +/* +** +*/ +PR_IMPLEMENT(void) + PR_GetTraceNameFromHandle( + PRTraceHandle handle, /* handle as search argument */ + const char **qName, /* pointer to associated QName */ + const char **rName, /* pointer to associated RName */ + const char **description /* pointer to associated description */ +) +{ + RName *rnp = (RName *)handle; + QName *qnp = rnp->qName; + + *qName = qnp->name; + *rName = rnp->name; + *description = rnp->desc; + + PR_LOG( lm, PR_LOG_DEBUG, ("PRTrace: GetConterNameFromHandle: " + "QNp: %p, RNp: %p,\n\tQName: %s, RName: %s, Desc: %s", + qnp, rnp, qnp->name, rnp->name, rnp->desc )); + + return; +} /* end PR_GetTraceNameFromHandle() */ + +/* +** +*/ +PR_IMPLEMENT(PRTraceHandle) + PR_FindNextTraceQname( + PRTraceHandle handle +) +{ + QName *qnp = (QName *)handle; + + if ( PR_CLIST_IS_EMPTY( &qNameList )) + qnp = NULL; + else if ( qnp == NULL ) + qnp = (QName *)PR_LIST_HEAD( &qNameList ); + else if ( PR_NEXT_LINK( &qnp->link ) == &qNameList ) + qnp = NULL; + else + qnp = (QName *)PR_NEXT_LINK( &qnp->link ); + + PR_LOG( lm, PR_LOG_DEBUG, ("PRTrace: FindNextQname: Handle: %p, Returns: %p", + handle, qnp )); + + return((PRTraceHandle)qnp); +} /* end PR_FindNextTraceQname() */ + +/* +** +*/ +PR_IMPLEMENT(PRTraceHandle) + PR_FindNextTraceRname( + PRTraceHandle rhandle, + PRTraceHandle qhandle +) +{ + RName *rnp = (RName *)rhandle; + QName *qnp = (QName *)qhandle; + + + if ( PR_CLIST_IS_EMPTY( &qnp->rNameList )) + rnp = NULL; + else if ( rnp == NULL ) + rnp = (RName *)PR_LIST_HEAD( &qnp->rNameList ); + else if ( PR_NEXT_LINK( &rnp->link ) == &qnp->rNameList ) + rnp = NULL; + else + rnp = (RName *)PR_NEXT_LINK( &rnp->link ); + + PR_LOG( lm, PR_LOG_DEBUG, ("PRTrace: FindNextRname: Rhandle: %p, QHandle: %p, Returns: %p", + rhandle, qhandle, rnp )); + + return((PRTraceHandle)rnp); +} /* end PR_FindNextTraceRname() */ + +/* +** +*/ +static PRFileDesc * InitializeRecording( void ) +{ + char *logFileName; + PRFileDesc *logFile; + + /* Self initialize, if necessary */ + if ( traceLock == NULL ) + _PR_InitializeTrace(); + + PR_LOG( lm, PR_LOG_DEBUG, + ("PR_RecordTraceEntries: begins")); + + logLostData = 0; /* reset at entry */ + logState = LogReset; + + /* Get the filename for the logfile from the environment */ + logFileName = PR_GetEnv( "NSPR_TRACE_LOG" ); + if ( logFileName == NULL ) + { + PR_LOG( lm, PR_LOG_ERROR, + ("RecordTraceEntries: Environment variable not defined. Exiting")); + return NULL; + } + + /* Open the logfile */ + logFile = PR_Open( logFileName, PR_WRONLY | PR_CREATE_FILE, 0666 ); + if ( logFile == NULL ) + { + PR_LOG( lm, PR_LOG_ERROR, + ("RecordTraceEntries: Cannot open %s as trace log file. OS error: %ld", + logFileName, PR_GetOSError())); + return NULL; + } + return logFile; +} /* end InitializeRecording() */ + +/* +** +*/ +static void ProcessOrders( void ) +{ + switch ( logOrder ) + { + case LogReset : + logOrder = logState = localState; + PR_LOG( lm, PR_LOG_DEBUG, + ("RecordTraceEntries: LogReset")); + break; + + case LogSuspend : + localState = logOrder = logState = LogSuspend; + PR_LOG( lm, PR_LOG_DEBUG, + ("RecordTraceEntries: LogSuspend")); + break; + + case LogResume : + localState = logOrder = logState = LogActive; + PR_LOG( lm, PR_LOG_DEBUG, + ("RecordTraceEntries: LogResume")); + break; + + case LogStop : + logOrder = logState = LogStop; + PR_LOG( lm, PR_LOG_DEBUG, + ("RecordTraceEntries: LogStop")); + break; + + default : + PR_LOG( lm, PR_LOG_ERROR, + ("RecordTraceEntries: Invalid logOrder: %ld", logOrder )); + PR_ASSERT( 0 ); + break; + } /* end switch() */ + return ; +} /* end ProcessOrders() */ + +/* +** +*/ +static void WriteTraceSegment( PRFileDesc *logFile, void *buf, PRInt32 amount ) +{ + PRInt32 rc; + + + PR_LOG( lm, PR_LOG_ERROR, + ("WriteTraceSegment: Buffer: %p, Amount: %ld", buf, amount)); + rc = PR_Write( logFile, buf , amount ); + if ( rc == -1 ) + PR_LOG( lm, PR_LOG_ERROR, + ("RecordTraceEntries: PR_Write() failed. Error: %ld", PR_GetError() )); + else if ( rc != amount ) + PR_LOG( lm, PR_LOG_ERROR, + ("RecordTraceEntries: PR_Write() Tried to write: %ld, Wrote: %ld", amount, rc)); + else + PR_LOG( lm, PR_LOG_DEBUG, + ("RecordTraceEntries: PR_Write(): Buffer: %p, bytes: %ld", buf, amount)); + + return; +} /* end WriteTraceSegment() */ + +/* +** +*/ +PR_IMPLEMENT(void) + PR_RecordTraceEntries( + void +) +{ + PRFileDesc *logFile; + PRInt32 lostSegments; + PRInt32 currentSegment = 0; + void *buf; + PRBool doWrite; + + logFile = InitializeRecording(); + if ( logFile == NULL ) + { + PR_LOG( lm, PR_LOG_DEBUG, + ("PR_RecordTraceEntries: Failed to initialize")); + return; + } + + /* Do this until told to stop */ + while ( logState != LogStop ) + { + + PR_Lock( logLock ); + + while ( (logCount == 0) && ( logOrder == logState ) ) + PR_WaitCondVar( logCVar, PR_INTERVAL_NO_TIMEOUT ); + + /* Handle state transitions */ + if ( logOrder != logState ) + ProcessOrders(); + + /* recalculate local controls */ + if ( logCount ) + { + lostSegments = logCount - logSegments; + if ( lostSegments > 0 ) + { + logLostData += ( logCount - logSegments ); + logCount = (logCount % logSegments); + currentSegment = logCount; + PR_LOG( lm, PR_LOG_DEBUG, + ("PR_RecordTraceEntries: LostData segments: %ld", logLostData)); + } + else + { + logCount--; + } + + buf = tBuf + ( logEntriesPerSegment * currentSegment ); + if (++currentSegment >= logSegments ) + currentSegment = 0; + doWrite = PR_TRUE; + } + else + doWrite = PR_FALSE; + + PR_Unlock( logLock ); + + if ( doWrite == PR_TRUE ) + { + if ( localState != LogSuspend ) + WriteTraceSegment( logFile, buf, logSegSize ); + else + PR_LOG( lm, PR_LOG_DEBUG, + ("RecordTraceEntries: PR_Write(): is suspended" )); + } + + } /* end while(logState...) */ + + PR_Close( logFile ); + PR_LOG( lm, PR_LOG_DEBUG, + ("RecordTraceEntries: exiting")); + return; +} /* end PR_RecordTraceEntries() */ + +/* +** +*/ +PR_IMPLEMENT(PRIntn) + PR_GetTraceEntries( + PRTraceEntry *buffer, /* where to write output */ + PRInt32 count, /* number to get */ + PRInt32 *found /* number you got */ +) +{ + PRInt32 rc; + PRInt32 copied = 0; + + PR_Lock( traceLock ); + + /* + ** Depending on where the LastSeen and Next indices are, + ** copy the trace buffer in one or two pieces. + */ + PR_LOG( lm, PR_LOG_ERROR, + ("PR_GetTraceEntries: Next: %ld, LastSeen: %ld", next, fetchLastSeen)); + + if ( fetchLastSeen <= next ) + { + while (( count-- > 0 ) && (fetchLastSeen < next )) + { + *(buffer + copied++) = *(tBuf + fetchLastSeen++); + } + PR_LOG( lm, PR_LOG_ERROR, + ("PR_GetTraceEntries: Copied: %ld, LastSeen: %ld", copied, fetchLastSeen)); + } + else /* copy in 2 parts */ + { + while ( count-- > 0 && fetchLastSeen <= last ) + { + *(buffer + copied++) = *(tBuf + fetchLastSeen++); + } + fetchLastSeen = 0; + + PR_LOG( lm, PR_LOG_ERROR, + ("PR_GetTraceEntries: Copied: %ld, LastSeen: %ld", copied, fetchLastSeen)); + + while ( count-- > 0 && fetchLastSeen < next ) + { + *(buffer + copied++) = *(tBuf + fetchLastSeen++); + } + PR_LOG( lm, PR_LOG_ERROR, + ("PR_GetTraceEntries: Copied: %ld, LastSeen: %ld", copied, fetchLastSeen)); + } + + *found = copied; + rc = ( fetchLostData == PR_TRUE )? 1 : 0; + fetchLostData = PR_FALSE; + + PR_Unlock( traceLock ); + return rc; +} /* end PR_GetTraceEntries() */ + +#else /* !defined(FORCE_NSPR_TRACE) */ +/* +** The trace facility is not defined when !DEBUG and !FORCE_NSPR_TRACE +** +*/ + +#endif /* defined(FORCE_NSPR_TRACE) */ + +/* end prtrace.c */ diff --git a/pr/src/prvrsion.c b/pr/src/prvrsion.c new file mode 100644 index 00000000..588669d7 --- /dev/null +++ b/pr/src/prvrsion.c @@ -0,0 +1,65 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "NPL"); you may not use this file except in + * compliance with the NPL. You may obtain a copy of the NPL at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the NPL is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL + * for the specific language governing rights and limitations under the + * NPL. + * + * The Initial Developer of this code under the NPL is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All Rights + * Reserved. + */ + +#include "prinit.h" +#include "prvrsion.h" + +/************************************************************************/ +/**************************IDENTITY AND VERSIONING***********************/ +/************************************************************************/ +#include "_pr_bld.h" +#if !defined(_BUILD_TIME) +#define _BUILD_TIME 0 +#endif +#if !defined(_BUILD_STRING) +#define _BUILD_STRING "" +#endif +#if !defined(_PRODUCTION) +#define _PRODUCTION "" +#endif + +static PRVersionDescription prVersionDescription_libnsrp21 = +{ + /* version */ 2, /* this is the only one supported */ + /* buildTime */ _BUILD_TIME, /* usecs since midnight 1/1/1970 GMT */ + /* buildTimeString */ _BUILD_STRING, /* ditto, but human readable */ + /* vMajor */ PR_VMAJOR, /* NSPR's version number */ + /* vMinor */ PR_VMINOR, /* and minor version */ + /* vPatch */ PR_VPATCH, /* and patch */ + /* beta */ PR_BETA, /* beta build boolean */ +#if defined(DEBUG) + /* debug */ PR_TRUE, /* a debug build */ +#else + /* debug */ PR_FALSE, /* an optomized build */ +#endif + /* special */ PR_FALSE, /* they're all special, but ... */ + /* filename */ _PRODUCTION, /* the produced library name */ + /* description */ "Portable runtime", /* what we are */ + /* security */ "N/A", /* not applicable here */ + /* copywrite */ "Copyright (c) 1998 Netscape Communications Corporation. All Rights Reserved", + /* comment */ "License information: http://www.mozilla.org/NPL/", + /* specialString */ "" +}; + +PR_IMPLEMENT(const PRVersionDescription*) libVersionPoint(void) +{ + return &prVersionDescription_libnsrp21; +} /* versionEntryPointType */ + +/* prvrsion.c */ + diff --git a/pr/src/pthreads/ptio.c b/pr/src/pthreads/ptio.c index fbfa5a6d..e813b91d 100644 --- a/pr/src/pthreads/ptio.c +++ b/pr/src/pthreads/ptio.c @@ -41,7 +41,7 @@ /* Linux (except glibc) and FreeBSD don't have poll */ #if !(defined(LINUX) && !(defined(__GLIBC__) && __GLIBC__ >= 2)) \ && !defined(FREEBSD) -#include <poll.h> +#include <sys/poll.h> #endif #ifdef AIX /* To pick up sysconf() */ @@ -75,7 +75,7 @@ #elif defined(IRIX) || (defined(AIX) && !defined(AIX4_1)) \ || defined(OSF1) || defined(SOLARIS) \ || defined(HPUX10_30) || defined(HPUX11) || defined(LINUX) \ - || defined(FREEBSD) || defined(NETBSD) + || defined(FREEBSD) || defined(NETBSD) || defined(OPENBSD) #define _PRSelectFdSetArg_t fd_set * #else #error "Cannot determine architecture" @@ -87,9 +87,6 @@ static pthread_condattr_t _pt_cvar_attr; static PRLock *_pr_flock_lock; /* For PR_LockFile() etc. */ static PRLock *_pr_rename_lock; /* For PR_Rename() */ -extern struct _PT_Bookeeping pt_book; /* defined in ptthread.c */ -extern PRIntn pt_schedpriv; /* defined in ptthread.c */ - /**************************************************************************/ /* These two functions are only used in assertions. */ @@ -125,89 +122,6 @@ static PRBool IsValidNetAddrLen(const PRNetAddr *addr, PRInt32 addr_len) #endif /* DEBUG */ /*****************************************************************************/ -/*****************************************************************************/ -/************************** File descriptor caching **************************/ -/*****************************************************************************/ -/*****************************************************************************/ - -typedef struct _PT_Fd_Cache -{ - PRLock *ml; - PRIntn count; - PRIntn limit; - PRFileDesc *fd; -} _PT_Fd_Cache; -static _PT_Fd_Cache pt_fd_cache; - -/* -** Get a FileDescriptor from the cache if one exists. If not allocate -** a new one from the heap. -*/ -static PRFileDesc *pt_Getfd(void) -{ - PRFileDesc *fd; - do - { - fd = pt_fd_cache.fd; /* quick, unsafe check */ - if (NULL == fd) - { - fd = PR_NEWZAP(PRFileDesc); - if (NULL == fd) goto finished; - fd->secret = PR_NEWZAP(PRFilePrivate); - if (NULL == fd->secret) - { - PR_DELETE(fd); - goto finished; - } - } - else - { - PRFilePrivate *secret; - PR_Lock(pt_fd_cache.ml); - fd = pt_fd_cache.fd; /* safer extraction */ - if (NULL != fd) - { - pt_fd_cache.count -= 1; - pt_fd_cache.fd = fd->higher; - fd->higher = NULL; - } - PR_Unlock(pt_fd_cache.ml); - secret = fd->secret; - memset(fd, 0, sizeof(PRFileDesc)); - memset(secret, 0, sizeof(PRFilePrivate)); - fd->secret = secret; - } - } while (NULL == fd); -finished: - return fd; -} /* pt_Getfd */ - -/* -** Return a file descriptor to the cache unless there are too many in -** there already. If put in cache, clear the fields first. -*/ -static void pt_Putfd(PRFileDesc *fd) -{ - PR_ASSERT(_PR_FILEDESC_CLOSED == fd->secret->state); - PR_ASSERT(pt_fd_cache.count < pt_fd_cache.limit); - - fd->secret->state = _PR_FILEDESC_FREED; - if (pt_fd_cache.count > pt_fd_cache.limit) - { - PR_DELETE(fd->secret); - PR_DELETE(fd); - } - else - { - PR_Lock(pt_fd_cache.ml); - pt_fd_cache.count += 1; - fd->higher = pt_fd_cache.fd; - pt_fd_cache.fd = fd; - PR_Unlock(pt_fd_cache.ml); - } -} /* pt_Putfd */ - -/*****************************************************************************/ /************************* I/O Continuation machinery ************************/ /*****************************************************************************/ @@ -302,14 +216,15 @@ static struct pt_TimedQueue PTDebug pt_debug; /* this is shared between several modules */ -PR_IMPLEMENT(PTDebug) PT_GetStats() { return pt_debug; } +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; - PTDebug stats = PT_GetStats(); /* a copy */ + PT_GetStats(&stats); /* a copy */ PR_ExplodeTime(stats.timeStarted, PR_LocalTimeParameters, &tod); (void)PR_FormatTime(buffer, sizeof(buffer), "%T", &tod); @@ -574,6 +489,7 @@ static void pt_ContinuationThreadInternal(pt_Continuation *my_op) PRIntn pollingListNeeded; /* # entries needed this time */ static struct pollfd *pollingList = 0; /* list built for polling */ static PRIntn pollingSlotsAllocated = 0;/* # entries available in list */ + static pt_Continuation **pollingOps = 0;/* list paralleling polling list */ PR_Unlock(pt_tq.ml); /* don't need that silly lock for a bit */ @@ -599,15 +515,24 @@ static void pt_ContinuationThreadInternal(pt_Continuation *my_op) * We are not holding the pt_tq.ml lock now, so more items may * get added to pt_tq during this window of time. We hope * that 10 more spaces in the polling list should be enough. + * + * The space allocated is for both a vector that parallels the + * polling list, providing pointers directly into the operation's + * table and the polling list itself. There is a guard element + * between the two structures. */ pollingListNeeded += 10; if (pollingListNeeded > pollingSlotsAllocated) { - if (NULL != pollingList) PR_DELETE(pollingList); - pollingList = (struct pollfd*)PR_MALLOC( - pollingListNeeded * sizeof(struct pollfd)); - PR_ASSERT(NULL != pollingList); + if (NULL != pollingOps) PR_Free(pollingOps); + pollingOps = (pt_Continuation**)PR_Malloc( + sizeof(pt_Continuation**) + pollingListNeeded * + (sizeof(struct pollfd) + sizeof(pt_Continuation*))); + PR_ASSERT(NULL != pollingOps); pollingSlotsAllocated = pollingListNeeded; + pollingOps[pollingSlotsAllocated] = (pt_Continuation*)-1; + pollingList = (struct pollfd*)(&pollingOps[pollingSlotsAllocated + 1]); + } #if defined(DEBUG) @@ -662,6 +587,8 @@ static void pt_ContinuationThreadInternal(pt_Continuation *my_op) #endif break; } + PR_ASSERT((pt_Continuation*)-1 == pollingOps[pollingSlotsAllocated]); + pollingOps[pollingListUsed] = op; pollingList[pollingListUsed].revents = 0; pollingList[pollingListUsed].fd = op->arg1.osfd; pollingList[pollingListUsed].events = op->event; @@ -694,16 +621,18 @@ static void pt_ContinuationThreadInternal(pt_Continuation *my_op) * the end of the list. That means that more items got added * to the list than we anticipated. So, forget this iteration, * go around the horn again. + * * One would hope this doesn't happen all that often. */ if (NULL != op) continue; /* make it rethink things */ + PR_ASSERT((pt_Continuation*)-1 == pollingOps[pollingSlotsAllocated]); + rv = poll(pollingList, pollingListUsed, msecs); if ((-1 == rv) && ((errno == EINTR) || (errno == EAGAIN))) continue; /* go around the loop again */ - PR_Lock(pt_tq.ml); if (rv > 0) { /* @@ -718,42 +647,45 @@ static void pt_ContinuationThreadInternal(pt_Continuation *my_op) * the polling list. */ - op = pt_tq.head; for (pollIndex = 0; pollIndex < pollingListUsed; ++pollIndex) { - PR_ASSERT(NULL != op); - if (0 != pollingList[pollIndex].revents) + PRIntn fd = pollingList[pollIndex].fd; + PRInt16 events = pollingList[pollIndex].events; + PRInt16 revents = pollingList[pollIndex].revents; + + op = pollingOps[pollIndex]; /* this is the operation */ + + /* (ref: Bug #153459) + ** In case of POLLERR we let the operation retry in hope + ** of getting a more definitive OS error. + */ + if ((revents & POLLNVAL) /* busted in all cases */ + || ((events & POLLOUT) && (revents & POLLHUP))) /* write op & hup */ { - /* - * This one wants attention. Redo the operation. - * We know that there can only be more elements - * in the op list than we knew about when we created - * the poll list. Therefore, we might have to skip - * a few ops to find the right one to operate on. - */ - while ((pollingList[pollIndex].fd != op->arg1.osfd) - || (pollingList[pollIndex].events != op->event)) - { - PR_ASSERT(NULL != op->next); /* it has to be in there */ - op = op->next; /* keep advancing down the list */ - } - - /* - * Skip over all those not in progress. They'll be - * pruned next time we build a polling list. Call - * the continuation function. If it reports completion, - * finish off the operation. - */ - if ((pt_continuation_pending == op->status) - && (op->function(op, pollingList[pollIndex].revents))) - { - next_op = pt_FinishTimedInternal(op); - if (op == my_op) goto recycle; - else op = next_op; - } - continue; + PR_Lock(pt_tq.ml); + op->result.code = -1; + if (POLLNVAL & revents) op->syserrno = EBADF; + else if (POLLHUP & revents) op->syserrno = EPIPE; + (void)pt_FinishTimedInternal(op); + if (op == my_op) goto recycle; + PR_Unlock(pt_tq.ml); + } + else if ((0 != revents) + && (pt_continuation_pending == op->status) + && (op->function(op, revents))) + { + /* + * Only good?(?) revents left. Operations not pending + * will be pruned next time we build a list. This operation + * will be pruned if the continueation indicates it is + * finished. + */ + + PR_Lock(pt_tq.ml); + (void)pt_FinishTimedInternal(op); + if (op == my_op) goto recycle; + PR_Unlock(pt_tq.ml); } - op = op->next; /* progress to next operation */ } } @@ -763,6 +695,7 @@ static void pt_ContinuationThreadInternal(pt_Continuation *my_op) * wire are lucky, but none the less, valid. */ now = PR_IntervalNow(); + PR_Lock(pt_tq.ml); while ((NULL != pt_tq.head) && (PR_INTERVAL_NO_TIMEOUT != pt_tq.head->timeout)) { @@ -783,9 +716,11 @@ static void pt_ContinuationThreadInternal(pt_Continuation *my_op) */ if (op == my_op) goto recycle; /* exit w/o unlocking */ } - PR_Unlock(pt_tq.ml); /* unlock and go back around again */ + PR_Unlock(pt_tq.ml); } + PR_NOT_REACHED("This is a while(true) loop /w no breaks"); + recycle: /* ** Recycling the continuation thread. @@ -805,6 +740,7 @@ recycle: ** the lock held as well. Seems odd, doesn't it? */ + /* $$$ should this be called with the lock held? $$$ */ PR_SetThreadPriority(pt_tq.thread, priority); /* reset back to caller's */ PR_ASSERT((NULL == pt_tq.head) == (0 == pt_tq.op_count)); @@ -827,7 +763,6 @@ recycle: static PRIntn pt_Continue(pt_Continuation *op) { - PRIntn rc; PRStatus rv; PRThread *self = PR_GetCurrentThread(); /* lazy allocation of the thread's cv */ @@ -944,8 +879,13 @@ static PRBool pt_recv_cont(pt_Continuation *op, PRInt16 revents) * not (and probably will not) satisfy the request. The only * error we continue is EWOULDBLOCK|EAGAIN. */ +#if defined(SOLARIS) + op->result.code = read( + op->arg1.osfd, op->arg2.buffer, op->arg3.amount); +#else op->result.code = recv( op->arg1.osfd, op->arg2.buffer, op->arg3.amount, op->arg4.flags); +#endif op->syserrno = errno; return ((-1 == op->result.code) && (EWOULDBLOCK == op->syserrno || EAGAIN == op->syserrno)) ? @@ -954,6 +894,7 @@ static PRBool pt_recv_cont(pt_Continuation *op, PRInt16 revents) static PRBool pt_send_cont(pt_Continuation *op, PRInt16 revents) { + PRIntn bytes; /* * We want to write the entire amount out, no matter how many * tries it takes. Keep advancing the buffer and the decrementing @@ -961,8 +902,12 @@ static PRBool pt_send_cont(pt_Continuation *op, PRInt16 revents) * (which should be the original amount) when finished (or an * error). */ - PRIntn bytes = send( +#if defined(SOLARIS) + bytes = write(op->arg1.osfd, op->arg2.buffer, op->arg3.amount); +#else + bytes = send( op->arg1.osfd, op->arg2.buffer, op->arg3.amount, op->arg4.flags); +#endif op->syserrno = errno; if (bytes > 0) /* this is progress */ { @@ -980,6 +925,7 @@ static PRBool pt_send_cont(pt_Continuation *op, PRInt16 revents) static PRBool pt_write_cont(pt_Continuation *op, PRInt16 revents) { + PRIntn bytes; /* * We want to write the entire amount out, no matter how many * tries it takes. Keep advancing the buffer and the decrementing @@ -987,8 +933,7 @@ static PRBool pt_write_cont(pt_Continuation *op, PRInt16 revents) * (which should be the original amount) when finished (or an * error). */ - PRIntn bytes = write( - op->arg1.osfd, op->arg2.buffer, op->arg3.amount); + bytes = write(op->arg1.osfd, op->arg2.buffer, op->arg3.amount); op->syserrno = errno; if (bytes > 0) /* this is progress */ { @@ -1006,6 +951,8 @@ static PRBool pt_write_cont(pt_Continuation *op, PRInt16 revents) static PRBool pt_writev_cont(pt_Continuation *op, PRInt16 revents) { + PRIntn bytes; + struct iovec *iov = (struct iovec*)op->arg2.buffer; /* * Same rules as write, but continuing seems to be a bit more * complicated. As the number of bytes sent grows, we have to @@ -1013,8 +960,7 @@ static PRBool pt_writev_cont(pt_Continuation *op, PRInt16 revents) * modify an individual vector parms or we might have to eliminate * a pair altogether. */ - struct iovec *iov = (struct iovec*)op->arg2.buffer; - PRIntn bytes = writev(op->arg1.osfd, iov, op->arg3.amount); + bytes = writev(op->arg1.osfd, iov, op->arg3.amount); op->syserrno = errno; if (bytes > 0) /* this is progress */ { @@ -1116,11 +1062,6 @@ static PRBool pt_hpux_transmitfile_cont(pt_Continuation *op, PRInt16 revents) void _PR_InitIO() { PRIntn rv; - _pr_stdin = pt_SetMethods(0, PR_DESC_FILE); - _pr_stdout = pt_SetMethods(1, PR_DESC_FILE); - _pr_stderr = pt_SetMethods(2, PR_DESC_FILE); - - PR_ASSERT(_pr_stdin && _pr_stdout && _pr_stderr); pt_tq.ml = PR_NewLock(); PR_ASSERT(NULL != pt_tq.ml); @@ -1138,11 +1079,14 @@ void _PR_InitIO() _pr_flock_lock = PR_NewLock(); PR_ASSERT(NULL != _pr_flock_lock); _pr_rename_lock = PR_NewLock(); - PR_ASSERT(NULL != _pr_rename_lock); + PR_ASSERT(NULL != _pr_rename_lock); + + _PR_InitFdCache(); /* do that */ - pt_fd_cache.ml = PR_NewLock(); - PR_ASSERT(NULL != pt_fd_cache.ml); - pt_fd_cache.limit = FD_SETSIZE; + _pr_stdin = pt_SetMethods(0, PR_DESC_FILE); + _pr_stdout = pt_SetMethods(1, PR_DESC_FILE); + _pr_stderr = pt_SetMethods(2, PR_DESC_FILE); + PR_ASSERT(_pr_stdin && _pr_stdout && _pr_stderr); } /* _PR_InitIO */ PR_IMPLEMENT(PRFileDesc*) PR_GetSpecialFD(PRSpecialFD osfd) @@ -1194,9 +1138,9 @@ static void pt_MapError(void (*mapper)(PRIntn), PRIntn syserrno) static PRStatus pt_Close(PRFileDesc *fd) { - PRIntn syserrno, rv = 0; - if ((NULL == fd) || (NULL == fd->secret) || - (_PR_FILEDESC_OPEN != fd->secret->state)) + if ((NULL == fd) || (NULL == fd->secret) + || ((_PR_FILEDESC_OPEN != fd->secret->state) + && (_PR_FILEDESC_CLOSED != fd->secret->state))) { PR_SetError(PR_BAD_DESCRIPTOR_ERROR, 0); return PR_FAILURE; @@ -1205,17 +1149,14 @@ static PRStatus pt_Close(PRFileDesc *fd) if (_PR_FILEDESC_OPEN == fd->secret->state) { + if (-1 == close(fd->secret->md.osfd)) + { + pt_MapError(_PR_MD_MAP_CLOSE_ERROR, errno); + return PR_FAILURE; + } fd->secret->state = _PR_FILEDESC_CLOSED; - rv = close(fd->secret->md.osfd); - syserrno = errno; - } - - pt_Putfd(fd); - if (-1 == rv) - { - pt_MapError(_PR_MD_MAP_CLOSE_ERROR, syserrno); - return PR_FAILURE; } + _PR_Putfd(fd); return PR_SUCCESS; } /* pt_Close */ @@ -1223,7 +1164,7 @@ static PRInt32 pt_Read(PRFileDesc *fd, void *buf, PRInt32 amount) { PRInt32 syserrno, bytes = -1; - if (pt_TestAbort()) return PR_FAILURE; + if (pt_TestAbort()) return bytes; bytes = read(fd->secret->md.osfd, buf, amount); syserrno = errno; @@ -1251,7 +1192,7 @@ static PRInt32 pt_Write(PRFileDesc *fd, const void *buf, PRInt32 amount) PRInt32 syserrno, bytes = -1; PRBool fNeedContinue = PR_FALSE; - if (pt_TestAbort()) return PR_FAILURE; + if (pt_TestAbort()) return bytes; bytes = write(fd->secret->md.osfd, buf, amount); syserrno = errno; @@ -1381,38 +1322,53 @@ static PRInt32 pt_Writev( static PRInt32 pt_Seek(PRFileDesc *fd, PRInt32 offset, PRSeekWhence whence) { - PRIntn how; - off_t pos = -1; - - if (pt_TestAbort()) return pos; - - switch (whence) - { - case PR_SEEK_SET: how = SEEK_SET; break; - case PR_SEEK_CUR: how = SEEK_CUR; break; - case PR_SEEK_END: how = SEEK_END; break; - default: - PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); - return pos; - } - pos = lseek(fd->secret->md.osfd, offset, how); - if (pos == -1) - pt_MapError(_PR_MD_MAP_LSEEK_ERROR, errno); - return pos; + return _PR_MD_LSEEK(fd, offset, whence); } /* pt_Seek */ static PRInt64 pt_Seek64(PRFileDesc *fd, PRInt64 offset, PRSeekWhence whence) { - PRInt64 on; - PRInt32 off, position = -1; - LL_L2I(off, offset); /* possible loss of bits */ - LL_I2L(on, off); /* get back original or notice we didn't */ - if (LL_EQ(on, offset)) position = pt_Seek(fd, off, whence); - LL_I2L(on, position); /* might not have worked */ - return on; + return _PR_MD_LSEEK64(fd, offset, whence); } /* pt_Seek64 */ -static PRInt32 pt_Available(PRFileDesc *fd) +static PRInt32 pt_Available_f(PRFileDesc *fd) +{ + PRInt32 result, cur, end; + + cur = _PR_MD_LSEEK(fd, 0, PR_SEEK_CUR); + + if (cur >= 0) + end = _PR_MD_LSEEK(fd, 0, PR_SEEK_END); + + if ((cur < 0) || (end < 0)) { + return -1; + } + + result = end - cur; + _PR_MD_LSEEK(fd, cur, PR_SEEK_SET); + + return result; +} /* pt_Available_f */ + +static PRInt64 pt_Available64_f(PRFileDesc *fd) +{ + PRInt64 result, cur, end; + PRInt64 minus_one; + + LL_I2L(minus_one, -1); + cur = _PR_MD_LSEEK64(fd, LL_ZERO, PR_SEEK_CUR); + + if (LL_GE_ZERO(cur)) + end = _PR_MD_LSEEK64(fd, LL_ZERO, PR_SEEK_END); + + if (!LL_GE_ZERO(cur) || !LL_GE_ZERO(end)) return minus_one; + + LL_SUB(result, end, cur); + (void)_PR_MD_LSEEK64(fd, cur, PR_SEEK_SET); + + return result; +} /* pt_Available64_f */ + +static PRInt32 pt_Available_s(PRFileDesc *fd) { PRInt32 rv, bytes = -1; if (pt_TestAbort()) return bytes; @@ -1422,71 +1378,32 @@ static PRInt32 pt_Available(PRFileDesc *fd) if (rv == -1) pt_MapError(_PR_MD_MAP_SOCKETAVAILABLE_ERROR, errno); return bytes; -} /* pt_Available */ +} /* pt_Available_s */ -static PRInt64 pt_Available64(PRFileDesc *fd) +static PRInt64 pt_Available64_s(PRFileDesc *fd) { PRInt64 rv; - PRInt32 avail = pt_Available(fd); - LL_I2L(rv, avail); + LL_I2L(rv, pt_Available_s(fd)); return rv; -} /* pt_Available64 */ - -static PRStatus pt_Synch(PRFileDesc *fd) -{ - return (NULL == fd) ? PR_FAILURE : PR_SUCCESS; -} /* pt_Synch */ +} /* pt_Available64_s */ static PRStatus pt_FileInfo(PRFileDesc *fd, PRFileInfo *info) { - PRInt32 rv; - struct stat sb; - PRInt64 s, s2us; - - if ((rv = fstat(fd->secret->md.osfd, &sb)) == 0 ) - { - if (info) - { - if (S_IFREG & sb.st_mode) - info->type = PR_FILE_FILE ; - else if (S_IFDIR & sb.st_mode) - info->type = PR_FILE_DIRECTORY; - else - info->type = PR_FILE_OTHER; - info->size = sb.st_size; -#if defined(IRIX) && defined(HAVE_LONG_LONG) - info->modifyTime = (PR_USEC_PER_SEC * (PRInt64)sb.st_mtim.tv_sec); - info->creationTime = (PR_USEC_PER_SEC * (PRInt64)sb.st_ctim.tv_sec); - info->modifyTime = (PR_USEC_PER_SEC * (PRInt64)sb.st_mtime); - info->creationTime = (PR_USEC_PER_SEC * (PRInt64)sb.st_ctime); -#else - LL_I2L(s, sb.st_mtime); - LL_I2L(s2us, PR_USEC_PER_SEC); - LL_MUL(s, s, s2us); - info->modifyTime = s; - LL_I2L(s, sb.st_ctime); - LL_MUL(s, s, s2us); - info->creationTime = s; -#endif - } - } - return (0 == rv) ? PR_SUCCESS : PR_FAILURE; + PRInt32 rv = _PR_MD_GETOPENFILEINFO(fd, info); + return (-1 == rv) ? PR_FAILURE : PR_SUCCESS; } /* pt_FileInfo */ static PRStatus pt_FileInfo64(PRFileDesc *fd, PRFileInfo64 *info) { - PRFileInfo info32; - PRStatus rv = pt_FileInfo(fd, &info32); - if (PR_SUCCESS == rv) - { - info->type = info32.type; - info->creationTime = info32.creationTime; - info->modifyTime = info32.modifyTime; - LL_I2L(info->size, info32.size); - } - return rv; + PRInt32 rv = _PR_MD_GETOPENFILEINFO64(fd, info); + return (-1 == rv) ? PR_FAILURE : PR_SUCCESS; } /* pt_FileInfo64 */ +static PRStatus pt_Synch(PRFileDesc *fd) +{ + return (NULL == fd) ? PR_FAILURE : PR_SUCCESS; +} /* pt_Synch */ + static PRStatus pt_Fsync(PRFileDesc *fd) { PRIntn rv = -1; @@ -1598,11 +1515,16 @@ static PRFileDesc* pt_Accept( if (osfd < 0) goto failed; } } -#ifdef AIX +#ifdef _PR_HAVE_SOCKADDR_LEN /* mask off the first byte of struct sockaddr (the length field) */ if (addr) - addr->inet.family &= 0x00ff; + { + *((unsigned char *) addr) = 0; +#ifdef IS_LITTLE_ENDIAN + addr->raw.family = ntohs(addr->raw.family); #endif + } +#endif /* _PR_HAVE_SOCKADDR_LEN */ newfd = pt_SetMethods(osfd, PR_DESC_SOCKET_TCP); if (newfd == NULL) close(osfd); /* $$$ whoops! this doesn't work $$$ */ else @@ -1696,9 +1618,15 @@ static PRInt32 pt_Recv( { PRInt32 syserrno, bytes = -1; - if (pt_TestAbort()) return PR_FAILURE; + if (pt_TestAbort()) return bytes; + /* recv() is a much slower call on pre-2.6 Solaris than read(). */ +#if defined(SOLARIS) + PR_ASSERT(0 == flags); + bytes = read(fd->secret->md.osfd, buf, amount); +#else bytes = recv(fd->secret->md.osfd, buf, amount, flags); +#endif syserrno = errno; if ((bytes == -1) && (syserrno == EWOULDBLOCK || syserrno == EAGAIN) @@ -1744,9 +1672,19 @@ static PRInt32 pt_Send( #define PT_SENDBUF_CAST #endif - if (pt_TestAbort()) return PR_FAILURE; + if (pt_TestAbort()) return bytes; + /* + * On pre-2.6 Solaris, send() is much slower than write(). + * On 2.6 and beyond, with in-kernel sockets, send() and + * write() are fairly equivalent in performance. + */ +#if defined(SOLARIS) + PR_ASSERT(0 == flags); + bytes = write(fd->secret->md.osfd, PT_SENDBUF_CAST buf, amount); +#else bytes = send(fd->secret->md.osfd, PT_SENDBUF_CAST buf, amount, flags); +#endif syserrno = errno; if ( (bytes >= 0) && (bytes < amount) && (!fd->secret->nonblocking) ) @@ -1801,7 +1739,7 @@ static PRInt32 pt_SendTo( PRInt32 syserrno, bytes = -1; PRBool fNeedContinue = PR_FALSE; - if (pt_TestAbort()) return PR_FAILURE; + if (pt_TestAbort()) return bytes; PR_ASSERT(IsValidNetAddr(addr) == PR_TRUE); bytes = sendto( @@ -1841,7 +1779,7 @@ static PRInt32 pt_RecvFrom(PRFileDesc *fd, void *buf, PRInt32 amount, PRInt32 syserrno, bytes = -1; pt_SockLen addr_len = sizeof(PRNetAddr); - if (pt_TestAbort()) return PR_FAILURE; + if (pt_TestAbort()) return bytes; bytes = recvfrom( fd->secret->md.osfd, buf, amount, flags, @@ -1869,10 +1807,19 @@ static PRInt32 pt_RecvFrom(PRFileDesc *fd, void *buf, PRInt32 amount, bytes = pt_Continue(&op); syserrno = op.syserrno; } -#ifdef AIX - /* mask off the first byte of struct sockaddr (the length field) */ - if (addr) addr->inet.family &= 0x00ff; +#ifdef _PR_HAVE_SOCKADDR_LEN + if (bytes >= 0) + { + /* mask off the first byte of struct sockaddr (the length field) */ + if (addr) + { + *((unsigned char *) addr) = 0; +#ifdef IS_LITTLE_ENDIAN + addr->raw.family = ntohs(addr->raw.family); #endif + } + } +#endif /* _PR_HAVE_SOCKADDR_LEN */ if (bytes < 0) pt_MapError(_PR_MD_MAP_RECVFROM_ERROR, syserrno); return bytes; @@ -1974,6 +1921,12 @@ static PRInt32 pt_TransmitFile( PRInt32 hlen, PRTransmitFileFlags flags, PRIntervalTime timeout) { if (pt_TestAbort()) return -1; + /* The socket must be in blocking mode. */ + if (sd->secret->nonblocking) + { + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + return -1; + } #ifdef HPUX11 return pt_HPUXTransmitFile(sd, fd, headers, hlen, flags, timeout); @@ -1993,31 +1946,30 @@ static PRInt32 pt_AcceptRead( PRInt32 rv = -1; PRNetAddr remote; PRFileDesc *accepted = NULL; - PRIntervalTime start, elapsed; if (pt_TestAbort()) return rv; - - if (PR_INTERVAL_NO_TIMEOUT != timeout) start = PR_IntervalNow(); - if ((accepted = PR_Accept(sd, &remote, timeout)) == NULL) return rv; - - if (PR_INTERVAL_NO_TIMEOUT != timeout) + /* The socket must be in blocking mode. */ + if (sd->secret->nonblocking) { - elapsed = (PRIntervalTime) (PR_IntervalNow() - start); - if (elapsed > timeout) - { - PR_SetError(PR_IO_TIMEOUT_ERROR, 0); - goto failed; - } - else timeout = timeout - elapsed; + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + return rv; } + /* + ** The timeout does not apply to the accept portion of the + ** operation - it waits indefinitely. + */ + accepted = PR_Accept(sd, &remote, PR_INTERVAL_NO_TIMEOUT); + if (NULL == accepted) return rv; + rv = PR_Recv(accepted, buf, amount, 0, timeout); if (rv >= 0) { /* copy the new info out where caller can see it */ - *nd = accepted; - *raddr = (PRNetAddr *)((char*)buf + amount); + PRPtrdiff aligned = (PRPtrdiff)buf + amount + sizeof(void*) - 1; + *raddr = (PRNetAddr*)(aligned & ~(sizeof(void*) - 1)); memcpy(*raddr, &remote, PR_NETADDR_SIZE(&remote)); + *nd = accepted; return rv; } @@ -2035,14 +1987,20 @@ static PRStatus pt_GetSockName(PRFileDesc *fd, PRNetAddr *addr) rv = getsockname( fd->secret->md.osfd, (struct sockaddr*)addr, &addr_len); -#ifdef AIX - /* mask off the first byte of struct sockaddr (the length field) */ - if (addr) addr->inet.family &= 0x00ff; -#endif if (rv == -1) { pt_MapError(_PR_MD_MAP_GETSOCKNAME_ERROR, errno); return PR_FAILURE; } else { +#ifdef _PR_HAVE_SOCKADDR_LEN + /* mask off the first byte of struct sockaddr (the length field) */ + if (addr) + { + *((unsigned char *) addr) = 0; +#ifdef IS_LITTLE_ENDIAN + addr->raw.family = ntohs(addr->raw.family); +#endif + } +#endif /* _PR_HAVE_SOCKADDR_LEN */ PR_ASSERT(IsValidNetAddr(addr) == PR_TRUE); PR_ASSERT(IsValidNetAddrLen(addr, addr_len) == PR_TRUE); return PR_SUCCESS; @@ -2059,14 +2017,20 @@ static PRStatus pt_GetPeerName(PRFileDesc *fd, PRNetAddr *addr) rv = getpeername( fd->secret->md.osfd, (struct sockaddr*)addr, &addr_len); -#ifdef AIX - /* mask off the first byte of struct sockaddr (the length field) */ - if (addr) addr->inet.family &= 0x00ff; -#endif if (rv == -1) { pt_MapError(_PR_MD_MAP_GETPEERNAME_ERROR, errno); return PR_FAILURE; } else { +#ifdef _PR_HAVE_SOCKADDR_LEN + /* mask off the first byte of struct sockaddr (the length field) */ + if (addr) + { + *((unsigned char *) addr) = 0; +#ifdef IS_LITTLE_ENDIAN + addr->raw.family = ntohs(addr->raw.family); +#endif + } +#endif /* _PR_HAVE_SOCKADDR_LEN */ PR_ASSERT(IsValidNetAddr(addr) == PR_TRUE); PR_ASSERT(IsValidNetAddrLen(addr, addr_len) == PR_TRUE); return PR_SUCCESS; @@ -2409,8 +2373,8 @@ static PRIOMethods _pr_file_methods = { pt_Close, pt_Read, pt_Write, - pt_Available, - pt_Available64, + pt_Available_f, + pt_Available64_f, pt_Fsync, pt_Seek, pt_Seek64, @@ -2440,8 +2404,8 @@ static PRIOMethods _pr_tcp_methods = { pt_Close, pt_Read, pt_Write, - pt_Available, - pt_Available64, + pt_Available_s, + pt_Available64_s, pt_Synch, (PRSeekFN)_PR_InvalidInt, (PRSeek64FN)_PR_InvalidInt64, @@ -2473,8 +2437,8 @@ static PRIOMethods _pr_udp_methods = { pt_Close, pt_Read, pt_Write, - pt_Available, - pt_Available64, + pt_Available_s, + pt_Available64_s, pt_Synch, (PRSeekFN)_PR_InvalidInt, (PRSeek64FN)_PR_InvalidInt64, @@ -2506,7 +2470,8 @@ static PRIOMethods _pr_udp_methods = { #endif #if defined(HPUX) || defined(OSF1) || defined(SOLARIS) || defined (IRIX) \ - || defined(AIX) || defined(LINUX) || defined(FREEBSD) || defined(NETBSD) + || defined(AIX) || defined(LINUX) || defined(FREEBSD) || defined(NETBSD) \ + || defined(OPENBSD) #define _PR_FCNTL_FLAGS O_NONBLOCK #else #error "Can't determine architecture" @@ -2515,7 +2480,7 @@ static PRIOMethods _pr_udp_methods = { static PRFileDesc *pt_SetMethods(PRIntn osfd, PRDescType type) { PRInt32 flags, one = 1; - PRFileDesc *fd = pt_Getfd(); + PRFileDesc *fd = _PR_Getfd(); if (fd == NULL) PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); else @@ -2566,7 +2531,7 @@ PR_IMPLEMENT(const PRIOMethods*) PR_GetUDPMethods() PR_IMPLEMENT(PRFileDesc*) PR_AllocFileDesc( PRInt32 osfd, const PRIOMethods *methods) { - PRFileDesc *fd = pt_Getfd(); + PRFileDesc *fd = _PR_Getfd(); /* * Assert that the file descriptor is small enough to fit in the @@ -2661,7 +2626,7 @@ PR_IMPLEMENT(PRFileDesc*) PR_Open(const char *name, PRIntn flags, PRIntn mode) PR_Lock(_pr_rename_lock); } - osfd = open(name, osflags, mode); + osfd = _md_iovector._open64(name, osflags, mode); syserrno = errno; if ((flags & PR_CREATE_FILE) && (NULL !=_pr_rename_lock)) @@ -2720,39 +2685,18 @@ PR_IMPLEMENT(PRStatus) PR_Access(const char *name, PRAccessHow how) PR_IMPLEMENT(PRStatus) PR_GetFileInfo(const char *fn, PRFileInfo *info) { - PRInt32 rv; - struct stat sb; - PRInt64 s, s2us; + PRInt32 rv = _PR_MD_GETFILEINFO(fn, info); + return (0 == rv) ? PR_SUCCESS : PR_FAILURE; +} /* PR_GetFileInfo */ - if (pt_TestAbort()) return PR_FAILURE; +PR_IMPLEMENT(PRStatus) PR_GetFileInfo64(const char *fn, PRFileInfo64 *info) +{ + PRInt32 rv; - if ((rv = stat(fn, &sb)) == 0 ) - { - if (info) - { - if (S_IFREG & sb.st_mode) - info->type = PR_FILE_FILE ; - else if (S_IFDIR & sb.st_mode) - info->type = PR_FILE_DIRECTORY; - else - info->type = PR_FILE_OTHER; - info->size = sb.st_size; -#if defined(IRIX) && defined(HAVE_LONG_LONG) - info->modifyTime = (PR_USEC_PER_SEC * (PRInt64)sb.st_mtim.tv_sec); - info->creationTime = (PR_USEC_PER_SEC * (PRInt64)sb.st_ctim.tv_sec); -#else - LL_I2L(s, sb.st_mtime); - LL_I2L(s2us, PR_USEC_PER_SEC); - LL_MUL(s, s, s2us); - info->modifyTime = s; - LL_I2L(s, sb.st_ctime); - LL_MUL(s, s, s2us); - info->creationTime = s; -#endif - } - } + if (!_pr_initialized) _PR_ImplicitInitialization(); + rv = _PR_MD_GETFILEINFO64(fn, info); return (0 == rv) ? PR_SUCCESS : PR_FAILURE; -} /* PR_GetFileInfo */ +} /* PR_GetFileInfo64 */ PR_IMPLEMENT(PRStatus) PR_Rename(const char *from, const char *to) { @@ -2791,8 +2735,13 @@ PR_IMPLEMENT(PRStatus) PR_CloseDir(PRDir *dir) if (NULL != dir->md.d) { - closedir(dir->md.d); + if (closedir(dir->md.d) == -1) + { + _PR_MD_MAP_CLOSEDIR_ERROR(errno); + return PR_FAILURE; + } dir->md.d = NULL; + PR_DELETE(dir); } return PR_SUCCESS; } /* PR_CloseDir */ @@ -2863,6 +2812,8 @@ PR_IMPLEMENT(PRInt32) PR_Poll( */ PRIntervalTime start, elapsed, remaining; + if (pt_TestAbort()) return -1; + if (0 == npds) PR_Sleep(timeout); else { @@ -2876,39 +2827,100 @@ PR_IMPLEMENT(PRInt32) PR_Poll( } for (index = 0; index < npds; ++index) { - PRFileDesc *bottom = pds[index].fd; - PRInt16 polling_flags = pds[index].in_flags; + PRInt16 in_flags_read = 0, in_flags_write = 0; + PRInt16 out_flags_read = 0, out_flags_write = 0; - /* 'bottom' is really 'top' until we make it the bottom */ - if (NULL != bottom) + if ((NULL != pds[index].fd) && (0 != pds[index].in_flags)) { - polling_flags = (bottom->methods->poll)( - bottom, polling_flags, &pds[index].out_flags); - - if (0 != (polling_flags & pds[index].out_flags)) - ready += 1; /* this one is ready right now */ + if (pds[index].in_flags & PR_POLL_READ) + { + in_flags_read = (pds[index].fd->methods->poll)( + pds[index].fd, + pds[index].in_flags & ~PR_POLL_WRITE, + &out_flags_read); + } + if (pds[index].in_flags & PR_POLL_WRITE) + { + in_flags_write = (pds[index].fd->methods->poll)( + pds[index].fd, + pds[index].in_flags & ~PR_POLL_READ, + &out_flags_write); + } + if ((0 != (in_flags_read & out_flags_read)) + || (0 != (in_flags_write & out_flags_write))) + { + /* this one is ready right now */ + if (0 == ready) + { + /* + * We will return without calling the system + * poll function. So zero the out_flags + * fields of all the poll descriptors before + * this one. + */ + int i; + for (i = 0; i < index; i++) + { + pds[i].out_flags = 0; + } + } + ready += 1; + pds[index].out_flags = out_flags_read | out_flags_write; + } else { /* now locate the NSPR layer at the bottom of the stack */ - bottom = PR_GetIdentitiesLayer(bottom, PR_NSPR_IO_LAYER); + PRFileDesc *bottom = PR_GetIdentitiesLayer( + pds[index].fd, PR_NSPR_IO_LAYER); PR_ASSERT(NULL != bottom); /* what to do about that? */ + pds[index].out_flags = 0; /* pre-condition */ if ((NULL != bottom) && (_PR_FILEDESC_OPEN == bottom->secret->state)) { - syspoll[index].fd = bottom->secret->md.osfd; - pds[index].out_flags = 0; /* init the result */ - syspoll[index].events = 0; - if (polling_flags & PR_POLL_READ) - syspoll[index].events |= POLLIN; - if (polling_flags & PR_POLL_WRITE) - syspoll[index].events |= POLLOUT; - if (polling_flags & PR_POLL_EXCEPT) - syspoll[index].events |= POLLPRI; + if (0 == ready) + { + syspoll[index].fd = bottom->secret->md.osfd; + syspoll[index].events = 0; + if (in_flags_read & PR_POLL_READ) + { + pds[index].out_flags |= + _PR_POLL_READ_SYS_READ; + syspoll[index].events |= POLLIN; + } + if (in_flags_read & PR_POLL_WRITE) + { + pds[index].out_flags |= + _PR_POLL_READ_SYS_WRITE; + syspoll[index].events |= POLLOUT; + } + if (in_flags_write & PR_POLL_READ) + { + pds[index].out_flags |= + _PR_POLL_WRITE_SYS_READ; + syspoll[index].events |= POLLIN; + } + if (in_flags_write & PR_POLL_WRITE) + { + pds[index].out_flags |= + _PR_POLL_WRITE_SYS_WRITE; + syspoll[index].events |= POLLOUT; + } + if (pds[index].in_flags & PR_POLL_EXCEPT) + syspoll[index].events |= POLLPRI; + } } else { + if (0 == ready) + { + int i; + for (i = 0; i < index; i++) + { + pds[i].out_flags = 0; + } + } ready += 1; /* this will cause an abrupt return */ - pds[index].out_flags = POLLNVAL; /* bogii */ + pds[index].out_flags = PR_POLL_NVAL; /* bogii */ } } } @@ -2941,6 +2953,7 @@ retry: goto retry; else if (timeout == PR_INTERVAL_NO_WAIT) ready = 0; /* don't retry, just time out */ + else { elapsed = (PRIntervalTime) (PR_IntervalNow() - start); @@ -2963,21 +2976,48 @@ retry: { for (index = 0; index < npds; ++index) { - if (pds[index].fd == NULL) continue; - PR_ASSERT(0 == pds[index].out_flags); - if (0 != syspoll[index].revents) + PRInt16 out_flags = 0; + if ((NULL != pds[index].fd) && (0 != pds[index].in_flags)) { - if (syspoll[index].revents & POLLIN) - pds[index].out_flags |= PR_POLL_READ; - if (syspoll[index].revents & POLLOUT) - pds[index].out_flags |= PR_POLL_WRITE; - if (syspoll[index].revents & POLLPRI) - pds[index].out_flags |= PR_POLL_EXCEPT; - if (syspoll[index].revents & POLLERR) - pds[index].out_flags |= PR_POLL_ERR; - if (syspoll[index].revents & POLLNVAL) - pds[index].out_flags |= PR_POLL_NVAL; + if (0 != syspoll[index].revents) + { + if (syspoll[index].revents & POLLIN) + { + if (pds[index].out_flags + & _PR_POLL_READ_SYS_READ) + { + out_flags |= PR_POLL_READ; + } + if (pds[index].out_flags + & _PR_POLL_WRITE_SYS_READ) + { + out_flags |= PR_POLL_WRITE; + } + } + if (syspoll[index].revents & POLLOUT) + { + if (pds[index].out_flags + & _PR_POLL_READ_SYS_WRITE) + { + out_flags |= PR_POLL_READ; + } + if (pds[index].out_flags + & _PR_POLL_WRITE_SYS_WRITE) + { + out_flags |= PR_POLL_WRITE; + } + } + if (syspoll[index].revents & POLLPRI) + out_flags |= PR_POLL_EXCEPT; + if (syspoll[index].revents & POLLERR) + out_flags |= PR_POLL_ERR; + if (syspoll[index].revents & POLLNVAL) + out_flags |= PR_POLL_NVAL; + if (syspoll[index].revents & POLLHUP) + out_flags |= PR_POLL_HUP; + } } + pds[index].out_flags = out_flags; } } } @@ -3281,13 +3321,13 @@ PR_IMPLEMENT(PRInt32) PR_Stat(const char *name, struct stat *buf) static PRBool unwarned = PR_TRUE; if (unwarned) unwarned = _PR_Obsolete("PR_Stat", "PR_GetFileInfo"); - if (pt_TestAbort()) return PR_FAILURE; + if (pt_TestAbort()) return -1; if (-1 == stat(name, buf)) { pt_MapError(_PR_MD_MAP_STAT_ERROR, errno); - return PR_FAILURE; + return -1; } else { - return PR_SUCCESS; + return 0; } } #endif /* ! NO_NSPR_10_SUPPORT */ diff --git a/pr/src/pthreads/ptmisc.c b/pr/src/pthreads/ptmisc.c index 669b7822..188a471a 100644 --- a/pr/src/pthreads/ptmisc.c +++ b/pr/src/pthreads/ptmisc.c @@ -32,7 +32,6 @@ void _PR_InitCPUs(void) {PT_LOG("_PR_InitCPUs")} void _MD_StartInterrupts(void) {PT_LOG("_MD_StartInterrupts")} void _PR_InitStacks(void) {PT_LOG("_PR_InitStacks")} -void _PR_InitTPD(void) {PT_LOG("_PR_InitTPD")} PR_IMPLEMENT(void) PR_SetConcurrency(PRUintn numCPUs) {PT_LOG("PR_SetConcurrency")} diff --git a/pr/src/pthreads/ptsynch.c b/pr/src/pthreads/ptsynch.c index 128486eb..b49cdc3f 100644 --- a/pr/src/pthreads/ptsynch.c +++ b/pr/src/pthreads/ptsynch.c @@ -31,6 +31,7 @@ #include <pthread.h> #include <sys/time.h> +static pthread_mutexattr_t _pt_mattr; static pthread_condattr_t _pt_cvar_attr; #if defined(DEBUG) @@ -50,7 +51,16 @@ static pthread_t pt_zero_tid; /* a null pthread_t (pthread_t is a struct void _PR_InitLocks(void) { - int rv = PTHREAD_CONDATTR_INIT(&_pt_cvar_attr); + int rv; + rv = PTHREAD_MUTEXATTR_INIT(&_pt_mattr); + PR_ASSERT(0 == rv); + +#if defined(AIX) + rv = pthread_mutexattr_setkind_np(&_pt_mattr, MUTEX_FAST_NP); + PR_ASSERT(0 == rv); +#endif + + rv = PTHREAD_CONDATTR_INIT(&_pt_cvar_attr); PR_ASSERT(0 == rv); _PR_MD_INIT_LOCKS(); } @@ -131,12 +141,7 @@ PR_IMPLEMENT(PRLock*) PR_NewLock(void) lock = PR_NEWZAP(PRLock); if (lock != NULL) { - pthread_mutexattr_t mattr; - rv = PTHREAD_MUTEXATTR_INIT(&mattr); - PR_ASSERT(0 == rv); - rv = PTHREAD_MUTEX_INIT(lock->mutex, mattr); - PR_ASSERT(0 == rv); - rv = PTHREAD_MUTEXATTR_DESTROY(&mattr); + rv = PTHREAD_MUTEX_INIT(lock->mutex, _pt_mattr); PR_ASSERT(0 == rv); } #if defined(DEBUG) @@ -399,33 +404,37 @@ PR_IMPLEMENT(PRStatus) PR_NotifyAllCondVar(PRCondVar *cvar) PR_IMPLEMENT(PRMonitor*) PR_NewMonitor(void) { - PRMonitor *ml; + PRMonitor *mon; + PRCondVar *cvar; if (!_pr_initialized) _PR_ImplicitInitialization(); - ml = PR_NEWZAP(PRMonitor); - if (ml != NULL) + cvar = PR_NEWZAP(PRCondVar); + if (NULL == cvar) + { + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + return NULL; + } + mon = PR_NEWZAP(PRMonitor); + if (mon != NULL) { int rv; - pthread_mutexattr_t mattr; - rv = PTHREAD_MUTEXATTR_INIT(&mattr); - PR_ASSERT(0 == rv); - rv += PTHREAD_MUTEX_INIT(ml->lock.mutex, mattr); - PR_ASSERT(0 == rv); - rv += PTHREAD_MUTEXATTR_DESTROY(&mattr); + rv = PTHREAD_MUTEX_INIT(mon->lock.mutex, _pt_mattr); PR_ASSERT(0 == rv); - rv += PTHREAD_COND_INIT(ml->cvar.cv, _pt_cvar_attr); + mon->cvar = cvar; + rv = PTHREAD_COND_INIT(mon->cvar->cv, _pt_cvar_attr); PR_ASSERT(0 == rv); - ml->entryCount = 0; - ml->cvar.lock = &ml->lock; + mon->entryCount = 0; + mon->cvar->lock = &mon->lock; if (0 != rv) { - PR_DELETE(ml); - ml = NULL; + PR_DELETE(mon); + PR_DELETE(cvar); + mon = NULL; } } - return ml; + return mon; } /* PR_NewMonitor */ PR_IMPLEMENT(PRMonitor*) PR_NewNamedMonitor(const char* name) @@ -439,7 +448,7 @@ PR_IMPLEMENT(void) PR_DestroyMonitor(PRMonitor *mon) { int rv; PR_ASSERT(mon != NULL); - rv = pthread_cond_destroy(&mon->cvar.cv); PR_ASSERT(0 == rv); + PR_DestroyCondVar(mon->cvar); rv = pthread_mutex_destroy(&mon->lock.mutex); PR_ASSERT(0 == rv); #if defined(DEBUG) memset(mon, 0xaf, sizeof(PRMonitor)); @@ -539,7 +548,7 @@ PR_IMPLEMENT(PRStatus) PR_Wait(PRMonitor *mon, PRIntervalTime timeout) PTHREAD_COPY_THR_HANDLE(mon->owner, saved_owner); PTHREAD_ZERO_THR_HANDLE(mon->owner); - rv = PR_WaitCondVar(&mon->cvar, timeout); + rv = PR_WaitCondVar(mon->cvar, timeout); /* reinstate the intresting information */ mon->entryCount = saved_entries; @@ -558,7 +567,7 @@ PR_IMPLEMENT(PRStatus) PR_Notify(PRMonitor *mon) /* and it better be by us */ PR_ASSERT(pthread_equal(mon->owner, pthread_self())); - pt_PostNotifyToCvar(&mon->cvar, PR_FALSE); + pt_PostNotifyToCvar(mon->cvar, PR_FALSE); return PR_SUCCESS; } /* PR_Notify */ @@ -573,7 +582,7 @@ PR_IMPLEMENT(PRStatus) PR_NotifyAll(PRMonitor *mon) /* and it better be by us */ PR_ASSERT(pthread_equal(mon->owner, pthread_self())); - pt_PostNotifyToCvar(&mon->cvar, PR_TRUE); + pt_PostNotifyToCvar(mon->cvar, PR_TRUE); return PR_SUCCESS; } /* PR_NotifyAll */ diff --git a/pr/src/pthreads/ptthread.c b/pr/src/pthreads/ptthread.c index d3b7679f..bea53f56 100644 --- a/pr/src/pthreads/ptthread.c +++ b/pr/src/pthreads/ptthread.c @@ -29,6 +29,7 @@ #include "prpdce.h" #include <pthread.h> +#include <unistd.h> #include <string.h> #include <signal.h> @@ -38,18 +39,33 @@ * EPERM means that privilege is not available. */ -PRIntn pt_schedpriv; +static PRIntn pt_schedpriv = 0; extern PRLock *_pr_sleeplock; -struct _PT_Bookeeping pt_book = {0}; +static struct _PT_Bookeeping +{ + PRLock *ml; /* a lock to protect ourselves */ + PRCondVar *cv; /* used to signal global things */ + PRInt32 system, user; /* a count of the two different types */ + PRUintn this_many; /* number of threads allowed for exit */ + pthread_key_t key; /* private private data key */ + pthread_key_t highwater; /* ordinal value of next key to be allocated */ + PRThread *first, *last; /* list of threads we know about */ +#if defined(_PR_DCETHREADS) || defined(_POSIX_THREAD_PRIORITY_SCHEDULING) + PRInt32 minPrio, maxPrio; /* range of scheduling priorities */ +#endif +} pt_book = {0}; +static void _pt_thread_death(void *arg); static void init_pthread_gc_support(void); +#if defined(_PR_DCETHREADS) || defined(_POSIX_THREAD_PRIORITY_SCHEDULING) static PRIntn pt_PriorityMap(PRThreadPriority pri) { return pt_book.minPrio + pri * (pt_book.maxPrio - pt_book.minPrio) / PR_PRIORITY_LAST; } +#endif /* ** Initialize a stack for a native pthread thread @@ -156,23 +172,73 @@ static void *_pt_root(void *arg) } PR_Unlock(pt_book.ml); - /* last chance to delete this puppy if the thread is detached */ - if (detached) + /* + * Here we set the pthread's backpointer to the PRThread to NULL. + * Otherwise the desctructor would get called eagerly as the thread + * returns to the pthread runtime. The joining thread would them be + * the proud possessor of a dangling reference. However, this is the + * last chance to delete the object if the thread is detached, so + * just let the destuctor do the work. + */ + if (PR_FALSE == detached) { - if (NULL != thred->io_cv) - PR_DestroyCondVar(thred->io_cv); - PR_DELETE(thred->stack); -#if defined(DEBUG) - memset(thred, 0xaf, sizeof(PRThread)); -#endif - PR_DELETE(thred); + rv = pthread_setspecific(pt_book.key, NULL); + PR_ASSERT(0 == rv); } - rv = pthread_setspecific(pt_book.key, NULL); - PR_ASSERT(0 == rv); return NULL; } /* _pt_root */ +static PRThread* pt_AttachThread(void) +{ + PRThread *thred = NULL; + void *privateData = NULL; + + /* + * NSPR must have been initialized when PR_AttachThread is called. + * We cannot have PR_AttachThread call implicit initialization + * because if multiple threads call PR_AttachThread simultaneously, + * NSPR may be initialized more than once. + * We can't call PR_SetError() either. + */ + if (!_pr_initialized) return NULL; + + /* + * If the thread is already known, it will have a non-NULL value + * in its private data. If that's the case, simply suppress the + * attach and note an error. + */ + PTHREAD_GETSPECIFIC(pt_book.key, privateData); + if (NULL != privateData) + { + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + return NULL; + } + thred = PR_NEWZAP(PRThread); + if (NULL == thred) PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + else + { + int rv; + + thred->priority = PR_PRIORITY_NORMAL; + thred->id = pthread_self(); + rv = pthread_setspecific(pt_book.key, thred); + PR_ASSERT(0 == rv); + + thred->state = PT_THREAD_GLOBAL | PT_THREAD_FOREIGN; + PR_Lock(pt_book.ml); + + /* then put it into the list */ + thred->prev = pt_book.last; + pt_book.last->next = thred; + thred->next = NULL; + pt_book.last = thred; + PR_Unlock(pt_book.ml); + + } + return thred; /* may be NULL */ +} /* pt_AttachThread */ + static PRThread* _PR_CreateThread( PRThreadType type, void (*start)(void *arg), void *arg, PRThreadPriority priority, PRThreadScope scope, @@ -194,11 +260,11 @@ static PRThread* _PR_CreateThread( if (EPERM != pt_schedpriv) { -#if !defined(_PR_DCETHREADS) && !defined(FREEBSD) && !defined(NETBSD) +#if !defined(_PR_DCETHREADS) && defined(_POSIX_THREAD_PRIORITY_SCHEDULING) struct sched_param schedule; #endif -#if !defined(FREEBSD) && !defined(NETBSD) +#if defined(_POSIX_THREAD_PRIORITY_SCHEDULING) rv = pthread_attr_setinheritsched(&tattr, PTHREAD_EXPLICIT_SCHED); PR_ASSERT(0 == rv); #endif @@ -208,7 +274,7 @@ static PRThread* _PR_CreateThread( #if defined(_PR_DCETHREADS) rv = pthread_attr_setprio(&tattr, pt_PriorityMap(priority)); PR_ASSERT(0 == rv); -#elif !defined(FREEBSD) && !defined(NETBSD) +#elif defined(_POSIX_THREAD_PRIORITY_SCHEDULING) rv = pthread_attr_getschedparam(&tattr, &schedule); PR_ASSERT(0 == rv); schedule.sched_priority = pt_PriorityMap(priority); @@ -228,21 +294,8 @@ static PRThread* _PR_CreateThread( PR_ASSERT(0 == rv); #endif /* !defined(_PR_DCETHREADS) */ - /* - * HPUX only supports PTHREAD_SCOPE_SYSTEM. - * IRIX only supports PTHREAD_SCOPE_PROCESS. - * OSF1 only supports PTHREAD_SCOPE_PROCESS. - * AIX only supports PTHREAD_SCOPE_SYSTEM. - */ -#if defined(SOLARIS) - rv = pthread_attr_setscope(&tattr, - ((PR_GLOBAL_THREAD == scope) ? - PTHREAD_SCOPE_SYSTEM : PTHREAD_SCOPE_PROCESS)); - PR_ASSERT(0 == rv); -#endif - #if defined(IRIX) - if ((16 * 1024) > stackSize) stackSize = (16 * 1024); /* IRIX minimum */ + if ((32 * 1024) > stackSize) stackSize = (32 * 1024); /* IRIX minimum */ else #endif if (0 == stackSize) stackSize = (64 * 1024); /* default == 64K */ @@ -255,7 +308,12 @@ static PRThread* _PR_CreateThread( #endif thred = PR_NEWZAP(PRThread); - if (thred != NULL) + if (NULL == thred) + { + PR_SetError(PR_OUT_OF_MEMORY_ERROR, errno); + goto done; + } + else { pthread_t id; @@ -273,7 +331,9 @@ static PRThread* _PR_CreateThread( thred->stack = PR_NEWZAP(PRThreadStack); if (thred->stack == NULL) { - PR_DELETE(thred); /* all that work ... poof! */ + PRIntn oserr = errno; + PR_Free(thred); /* all that work ... poof! */ + PR_SetError(PR_OUT_OF_MEMORY_ERROR, oserr); thred = NULL; /* and for what? */ goto done; } @@ -281,24 +341,45 @@ static PRThread* _PR_CreateThread( thred->stack->thr = thred; #ifdef PT_NO_SIGTIMEDWAIT - pthread_mutex_init(&thred->suspendResumeMutex,NULL); - pthread_cond_init(&thred->suspendResumeCV,NULL); + pthread_mutex_init(&thred->suspendResumeMutex,NULL); + pthread_cond_init(&thred->suspendResumeCV,NULL); #endif - /* make the thread counted to the rest of the runtime */ - PR_Lock(pt_book.ml); - if (thred->state & PT_THREAD_SYSTEM) - pt_book.system += 1; - else pt_book.user += 1; - PR_Unlock(pt_book.ml); + /* make the thread counted to the rest of the runtime */ + PR_Lock(pt_book.ml); + if (PR_SYSTEM_THREAD == type) + pt_book.system += 1; + else pt_book.user += 1; + PR_Unlock(pt_book.ml); /* * We pass a pointer to a local copy (instead of thred->id) * to pthread_create() because who knows what wacky things * pthread_create() may be doing to its argument. */ - if (PTHREAD_CREATE(&id, tattr, _pt_root, thred) != 0) + rv = PTHREAD_CREATE(&id, tattr, _pt_root, thred); + +#if !defined(_PR_DCETHREADS) + if (EPERM == rv) + { + /* Remember that we don't have thread scheduling privilege. */ + pt_schedpriv = EPERM; + PR_LOG(_pr_thread_lm, PR_LOG_MIN, + ("_PR_CreateThread: no thread scheduling privilege")); + /* Try creating the thread again without setting priority. */ + rv = pthread_attr_setinheritsched(&tattr, PTHREAD_INHERIT_SCHED); + PR_ASSERT(0 == rv); + rv = PTHREAD_CREATE(&id, tattr, _pt_root, thred); + } +#endif + + if (0 != rv) { +#if defined(_PR_DCETHREADS) + PRIntn oserr = errno; +#else + PRIntn oserr = rv; +#endif PR_Lock(pt_book.ml); if (thred->state & PT_THREAD_SYSTEM) pt_book.system -= 1; @@ -306,8 +387,9 @@ static PRThread* _PR_CreateThread( PR_NotifyAllCondVar(pt_book.cv); PR_Unlock(pt_book.ml); - PR_DELETE(thred->stack); - PR_DELETE(thred); /* all that work ... poof! */ + PR_Free(thred->stack); + PR_Free(thred); /* all that work ... poof! */ + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, oserr); thred = NULL; /* and for what? */ goto done; } @@ -370,61 +452,10 @@ PR_IMPLEMENT(void) SetExecutionEnvironment(PRThread *thred, void *env) PR_IMPLEMENT(PRThread*) PR_AttachThread( PRThreadType type, PRThreadPriority priority, PRThreadStack *stack) { - PRThread *thred = NULL; - void *privateData = NULL; - - /* - * NSPR must have been initialized when PR_AttachThread is called. - * We cannot have PR_AttachThread call implicit initialization - * because if multiple threads call PR_AttachThread simultaneously, - * NSPR may be initialized more than once. - */ - if (!_pr_initialized) { - /* Since NSPR is not initialized, we cannot call PR_SetError. */ - return NULL; - } - - PTHREAD_GETSPECIFIC(pt_book.key, privateData); - if (NULL != privateData) - { - PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); - return NULL; - } - thred = PR_NEWZAP(PRThread); - if (NULL == thred) PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); - else - { - int rv; - - if ((PRIntn)PR_PRIORITY_FIRST > (PRIntn)priority) - priority = PR_PRIORITY_FIRST; - else if ((PRIntn)PR_PRIORITY_LAST < (PRIntn)priority) - priority = PR_PRIORITY_LAST; - - thred->priority = priority; - thred->id = pthread_self(); - rv = pthread_setspecific(pt_book.key, thred); - PR_ASSERT(0 == rv); - - PR_Lock(pt_book.ml); - if (PR_SYSTEM_THREAD == type) - { - pt_book.system += 1; - thred->state |= PT_THREAD_SYSTEM; - } - else pt_book.user += 1; - - /* then put it into the list */ - thred->prev = pt_book.last; - pt_book.last->next = thred; - thred->next = NULL; - pt_book.last = thred; - PR_Unlock(pt_book.ml); - - } - return thred; /* may be NULL */ + return PR_GetCurrentThread(); } /* PR_AttachThread */ + PR_IMPLEMENT(PRStatus) PR_JoinThread(PRThread *thred) { int rv = -1; @@ -432,7 +463,8 @@ PR_IMPLEMENT(PRStatus) PR_JoinThread(PRThread *thred) PR_ASSERT(thred != NULL); if ((0xafafafaf == thred->state) - || (PT_THREAD_DETACHED & thred->state)) + || (PT_THREAD_DETACHED == (PT_THREAD_DETACHED & thred->state)) + || (PT_THREAD_FOREIGN == (PT_THREAD_FOREIGN & thred->state))) { /* * This might be a bad address, but if it isn't, the state should @@ -440,65 +472,44 @@ PR_IMPLEMENT(PRStatus) PR_JoinThread(PRThread *thred) * deleted. However, the client that called join on a detached * thread deserves all the rath I can muster.... */ - PR_SetError(PR_ILLEGAL_ACCESS_ERROR, 0); + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); PR_LogPrint( "PR_JoinThread: 0x%X not joinable | already smashed\n", thred); - PR_ASSERT((0xafafafaf == thred->state) - || (PT_THREAD_DETACHED & thred->state)); + PR_ASSERT(!"Illegal thread join attempt"); } else { pthread_t id = thred->id; rv = pthread_join(id, &result); PR_ASSERT(rv == 0 && result == NULL); - if (0 != rv) - PR_SetError(PR_UNKNOWN_ERROR, errno); - if (NULL != thred->io_cv) - PR_DestroyCondVar(thred->io_cv); - PR_DELETE(thred->stack); -#if defined(DEBUG) - memset(thred, 0xaf, sizeof(PRThread)); -#endif - PR_DELETE(thred); + if (0 == rv) + { + _pt_thread_death(thred); + } + else + { + PRErrorCode prerror; + switch (rv) + { + case EINVAL: /* not a joinable thread */ + case ESRCH: /* no thread with given ID */ + prerror = PR_INVALID_ARGUMENT_ERROR; + break; + case EDEADLK: /* a thread joining with itself */ + prerror = PR_DEADLOCK_ERROR; + break; + default: + prerror = PR_UNKNOWN_ERROR; + break; + } + PR_SetError(prerror, rv); + } } return (0 == rv) ? PR_SUCCESS : PR_FAILURE; } /* PR_JoinThread */ -PR_IMPLEMENT(void) PR_DetachThread() -{ - void *tmp; - PTHREAD_GETSPECIFIC(pt_book.key, tmp); - PR_ASSERT(NULL != tmp); - - if (NULL != tmp) - { - int rv; - PRThread *thred = (PRThread*)tmp; - - PR_Lock(pt_book.ml); - if (thred->state & PT_THREAD_SYSTEM) - pt_book.system -= 1; - else if (--pt_book.user == pt_book.this_many) - PR_NotifyAllCondVar(pt_book.cv); - thred->prev->next = thred->next; - if (NULL == thred->next) - pt_book.last = thred->prev; - else - thred->next->prev = thred->prev; - PR_Unlock(pt_book.ml); - - if (NULL != thred->io_cv) - PR_DestroyCondVar(thred->io_cv); - rv = pthread_setspecific(pt_book.key, NULL); - PR_ASSERT(0 == rv); - PR_DELETE(thred->stack); -#if defined(DEBUG) - memset(thred, 0xaf, sizeof(PRThread)); -#endif - PR_DELETE(thred); - } -} /* PR_DetachThread */ +PR_IMPLEMENT(void) PR_DetachThread() { } /* PR_DetachThread */ PR_IMPLEMENT(PRThread*) PR_GetCurrentThread() { @@ -507,14 +518,14 @@ PR_IMPLEMENT(PRThread*) PR_GetCurrentThread() if (!_pr_initialized) _PR_ImplicitInitialization(); PTHREAD_GETSPECIFIC(pt_book.key, thred); + if (NULL == thred) thred = pt_AttachThread(); PR_ASSERT(NULL != thred); return (PRThread*)thred; } /* PR_GetCurrentThread */ PR_IMPLEMENT(PRThreadScope) PR_GetThreadScope(const PRThread *thred) { - return (thred->state & PT_THREAD_GLOBAL) ? - PR_GLOBAL_THREAD : PR_LOCAL_THREAD; + return PR_GLOBAL_THREAD; } /* PR_GetThreadScope() */ PR_IMPLEMENT(PRThreadType) PR_GetThreadType(const PRThread *thred) @@ -550,7 +561,7 @@ PR_IMPLEMENT(void) PR_SetThreadPriority(PRThread *thred, PRThreadPriority newPri rv = pthread_setprio(thred->id, pt_PriorityMap(newPri)); /* pthread_setprio returns the old priority */ PR_ASSERT(-1 != rv); -#elif !defined(FREEBSD) && !defined(NETBSD) +#elif defined(_POSIX_THREAD_PRIORITY_SCHEDULING) if (EPERM != pt_schedpriv) { int policy; @@ -560,13 +571,20 @@ PR_IMPLEMENT(void) PR_SetThreadPriority(PRThread *thred, PRThreadPriority newPri PR_ASSERT(0 == rv); schedule.sched_priority = pt_PriorityMap(newPri); rv = pthread_setschedparam(thred->id, policy, &schedule); - PR_ASSERT(0 == rv); + PR_ASSERT(0 == rv || EPERM == rv); + if (EPERM == rv) + { + pt_schedpriv = EPERM; + PR_LOG(_pr_thread_lm, PR_LOG_MIN, + ("PR_SetThreadPriority: no thread scheduling privilege")); + } } #endif thred->priority = newPri; } /* PR_SetThreadPriority */ +#if 0 PR_IMPLEMENT(PRStatus) PR_NewThreadPrivateIndex( PRUintn *newIndex, PRThreadPrivateDTOR destructor) { @@ -611,6 +629,7 @@ PR_IMPLEMENT(void*) PR_GetThreadPrivate(PRUintn index) PTHREAD_GETSPECIFIC((pthread_key_t)index, result); return result; } /* PR_GetThreadPrivate */ +#endif PR_IMPLEMENT(PRStatus) PR_Interrupt(PRThread *thred) { @@ -675,27 +694,54 @@ PR_IMPLEMENT(PRStatus) PR_Sleep(PRIntervalTime ticks) } else { - PRCondVar *cv = PR_NewCondVar(_pr_sleeplock); + PRCondVar *cv; + PRIntervalTime timein; + + timein = PR_IntervalNow(); + cv = PR_NewCondVar(_pr_sleeplock); PR_ASSERT(cv != NULL); PR_Lock(_pr_sleeplock); - rv = PR_WaitCondVar(cv, ticks); + do + { + PRIntervalTime now = PR_IntervalNow(); + PRIntervalTime delta = now - timein; + if (delta > ticks) break; + rv = PR_WaitCondVar(cv, ticks - delta); + } while (PR_SUCCESS == rv); PR_Unlock(_pr_sleeplock); PR_DestroyCondVar(cv); } return rv; } /* PR_Sleep */ +static void _pt_thread_death(void *arg) +{ + PRThread *thred = (PRThread*)arg; + _PR_DestroyThreadPrivate(thred); + if (NULL != thred->errorString) + PR_Free(thred->errorString); + if (NULL != thred->io_cv) + PR_DestroyCondVar(thred->io_cv); + PR_Free(thred->stack); +#if defined(DEBUG) + memset(thred, 0xaf, sizeof(PRThread)); +#endif /* defined(DEBUG) */ + PR_Free(thred); +} /* _pt_thread_death */ + void _PR_InitThreads( PRThreadType type, PRThreadPriority priority, PRUintn maxPTDs) { int rv; PRThread *thred; +#if defined(_PR_DCETHREADS) || defined(_POSIX_THREAD_PRIORITY_SCHEDULING) /* ** These might be function evaluations */ pt_book.minPrio = PT_PRIO_MIN; pt_book.maxPrio = PT_PRIO_MAX; +#endif PR_ASSERT(NULL == pt_book.ml); pt_book.ml = PR_NewLock(); @@ -709,7 +755,7 @@ void _PR_InitThreads( thred->priority = priority; thred->id = pthread_self(); - thred->state |= (PT_THREAD_DETACHED | PT_THREAD_PRIMORD); + thred->state = (PT_THREAD_DETACHED | PT_THREAD_PRIMORD); if (PR_SYSTEM_THREAD == type) { thred->state |= PT_THREAD_SYSTEM; @@ -737,13 +783,17 @@ void _PR_InitThreads( * threads delete the objects in Join. * * NB: The destructor logic seems to have a bug so it isn't used. + * NBB: Oh really? I'm going to give it a spin - AOF 19 June 1998. + * More info - the problem is that pthreads calls the destructor + * eagerly as the thread returns from its root, rather than lazily + * after the thread is joined. Therefore, threads that are joining + * and holding PRThread references are actually holding pointers to + * nothing. */ - rv = PTHREAD_KEY_CREATE(&pt_book.key, NULL); + rv = PTHREAD_KEY_CREATE(&pt_book.key, _pt_thread_death); PR_ASSERT(0 == rv); rv = pthread_setspecific(pt_book.key, thred); - PR_ASSERT(0 == rv); - - pt_schedpriv = PT_PRIVCHECK(); + PR_ASSERT(0 == rv); PR_SetThreadPriority(thred, priority); /* @@ -751,7 +801,7 @@ void _PR_InitThreads( * conflict with the use of these two signals in our GC support. * So we don't know how to support GC on Linux pthreads. */ -#if !defined(LINUX) && !defined(FREEBSD) && !defined(NETBSD) +#if !defined(LINUX) && !defined(FREEBSD) && !defined(NETBSD) && !defined(OPENBSD) init_pthread_gc_support(); #endif @@ -769,6 +819,10 @@ PR_IMPLEMENT(PRStatus) PR_Cleanup() PR_WaitCondVar(pt_book.cv, PR_INTERVAL_NO_TIMEOUT); PR_Unlock(pt_book.ml); + _PR_LogCleanup(); + /* Close all the fd's before calling _PR_CleanupFdCache */ + _PR_CleanupFdCache(); + /* * I am not sure if it's safe to delete the cv and lock here, * since there may still be "system" threads around. If this @@ -780,8 +834,7 @@ PR_IMPLEMENT(PRStatus) PR_Cleanup() PR_DestroyCondVar(pt_book.cv); pt_book.cv = NULL; PR_DestroyLock(pt_book.ml); pt_book.ml = NULL; } - PR_DELETE(me->stack); - PR_DELETE(me); + _pt_thread_death(me); return PR_SUCCESS; } return PR_FAILURE; @@ -792,6 +845,15 @@ PR_IMPLEMENT(void) PR_ProcessExit(PRIntn status) _exit(status); } +PR_IMPLEMENT(PRUint32) PR_GetThreadID(PRThread *thred) +{ +#if defined(_PR_DCETHREADS) + return (PRUint32)&thred->id; /* this is really a sham! */ +#else + return (PRUint32)thred->id; /* and I don't know what they will do with it */ +#endif +} + /* * $$$ * The following two thread-to-processor affinity functions are not @@ -1036,7 +1098,7 @@ static void suspend_signal_handler(PRIntn sig) pthread_cond_signal(&me->suspendResumeCV); while (me->suspend & PT_THREAD_SUSPENDED) { -#if !defined(FREEBSD) && !defined(NETBSD) /*XXX*/ +#if !defined(FREEBSD) && !defined(NETBSD) && !defined(OPENBSD) /*XXX*/ PRIntn rv; sigwait(&sigwait_set, &rv); #endif diff --git a/pr/src/threads/Makefile b/pr/src/threads/Makefile index 91ad0aaa..755d9928 100644 --- a/pr/src/threads/Makefile +++ b/pr/src/threads/Makefile @@ -35,10 +35,12 @@ endif endif ifdef USE_PTHREADS -CSRCS = prcmon.c \ +CSRCS = \ + prcmon.c \ + prtpd.c \ $(NULL) else -CSRCS = \ +CSRCS = \ prcmon.c \ prdump.c \ prmon.c \ diff --git a/pr/src/threads/combined/prucpu.c b/pr/src/threads/combined/prucpu.c index 99ad4d83..e50e9702 100644 --- a/pr/src/threads/combined/prucpu.c +++ b/pr/src/threads/combined/prucpu.c @@ -145,6 +145,8 @@ static _PRCPU *_PR_CreateCPU(PRThread *thread, PRBool needQueue) PR_DELETE(cpu); return NULL; } + cpu->idle_thread->cpu = cpu; + cpu->idle_thread->no_sched = 0; cpu->thread = thread; @@ -206,7 +208,7 @@ static void PR_CALLBACK _PR_CPU_Idle(void *_cpu) cpu->idle_thread = me; if (_MD_LAST_THREAD()) _MD_LAST_THREAD()->no_sched = 0; - if (!_PR_IS_NATIVE_THREAD(me)) _PR_SET_INTSOFF(0); + if (!_PR_IS_NATIVE_THREAD(me)) _PR_MD_SET_INTSOFF(0); while(1) { PRInt32 is; PRIntervalTime timeout; diff --git a/pr/src/threads/combined/prucv.c b/pr/src/threads/combined/prucv.c index bf2bd551..41eb62f2 100644 --- a/pr/src/threads/combined/prucv.c +++ b/pr/src/threads/combined/prucv.c @@ -157,7 +157,7 @@ void _PR_NotifyLockedThread (PRThread *thread) PRStatus _PR_WaitCondVar( PRThread *thread, PRCondVar *cvar, PRLock *lock, PRIntervalTime timeout) { - intn is; + PRIntn is; PRStatus rv = PR_SUCCESS; PR_ASSERT(thread == _PR_MD_CURRENT_THREAD()); @@ -336,7 +336,6 @@ void _PR_ClockInterrupt(void) if (elapsed < thread->sleep) { thread->sleep -= elapsed; _PR_SLEEPQMAX(thread->cpu) -= elapsed; - PR_ASSERT((PRInt32)(thread->sleep) >= 0); _PR_SLEEPQ_UNLOCK(cpu); break; } diff --git a/pr/src/threads/combined/prustack.c b/pr/src/threads/combined/prustack.c index 09690806..4e0053f6 100644 --- a/pr/src/threads/combined/prustack.c +++ b/pr/src/threads/combined/prustack.c @@ -77,7 +77,7 @@ PRThreadStack *_PR_NewStack(PRUint32 stackSize) _PR_MD_CLEAR_STACK(ts); _pr_numFreeStacks--; - PR_DestroySegment(ts->seg); + _PR_DestroySegment(ts->seg); PR_DELETE(ts); } @@ -125,7 +125,7 @@ PRThreadStack *_PR_NewStack(PRUint32 stackSize) ** up). */ ts->allocSize = stackSize + 2*REDZONE; - ts->seg = PR_NewSegment(ts->allocSize, 0); + ts->seg = _PR_NewSegment(ts->allocSize, 0); if (!ts->seg) { PR_DELETE(ts); return NULL; @@ -133,7 +133,7 @@ PRThreadStack *_PR_NewStack(PRUint32 stackSize) } done: - ts->allocBase = ts->seg->vaddr; + ts->allocBase = (char*)ts->seg->vaddr; ts->flags = _PR_STACK_MAPPED; ts->stackSize = stackSize; diff --git a/pr/src/threads/combined/pruthr.c b/pr/src/threads/combined/pruthr.c index 2a3c38d6..bcc2e650 100644 --- a/pr/src/threads/combined/pruthr.c +++ b/pr/src/threads/combined/pruthr.c @@ -22,22 +22,22 @@ /* _pr_activeLock protects the following global variables */ PRLock *_pr_activeLock; -PRUintn _pr_primordialExitCount; /* In PR_Cleanup(), the primordial thread - * waits until all other user (non-system) - * threads have terminated before it exits. - * So whenever we decrement _pr_userActive, - * it is compared with - * _pr_primordialExitCount. - * If the primordial thread is a system - * thread, then _pr_primordialExitCount - * is 0. If the primordial thread is - * itself a user thread, then - * _pr_primordialThread is 1. - */ +PRInt32 _pr_primordialExitCount; /* In PR_Cleanup(), the primordial thread + * waits until all other user (non-system) + * threads have terminated before it exits. + * So whenever we decrement _pr_userActive, + * it is compared with + * _pr_primordialExitCount. + * If the primordial thread is a system + * thread, then _pr_primordialExitCount + * is 0. If the primordial thread is + * itself a user thread, then + * _pr_primordialThread is 1. + */ PRCondVar *_pr_primordialExitCVar; /* When _pr_userActive is decremented to - * _pr_primordialExitCount, this condition - * variable is notified. - */ + * _pr_primordialExitCount, this condition + * variable is notified. + */ PRLock *_pr_deadQLock; PRUint32 _pr_numNativeDead; @@ -80,13 +80,13 @@ void _PR_InitThreads(PRThreadType type, PRThreadPriority priority, stack = PR_NEWZAP(PRThreadStack); #ifdef HAVE_STACK_GROWING_UP stack->stackTop = (char*) ((((long)&type) >> _pr_pageShift) - << _pr_pageShift); + << _pr_pageShift); #else #if defined(SOLARIS) || defined (UNIXWARE) && defined (USR_SVR4_THREADS) stack->stackTop = (char*) &thread; #else stack->stackTop = (char*) ((((long)&type + _pr_pageSize - 1) - >> _pr_pageShift) << _pr_pageShift); + >> _pr_pageShift) << _pr_pageShift); #endif #endif #else @@ -105,13 +105,13 @@ void _PR_InitThreads(PRThreadType type, PRThreadPriority priority, if (type == PR_SYSTEM_THREAD) { thread->flags = _PR_SYSTEM; _pr_systemActive++; - _pr_primordialExitCount = 0; + _pr_primordialExitCount = 0; } else { _pr_userActive++; - _pr_primordialExitCount = 1; + _pr_primordialExitCount = 1; } - thread->no_sched = 1; - _pr_primordialExitCVar = PR_NewCondVar(_pr_activeLock); + thread->no_sched = 1; + _pr_primordialExitCVar = PR_NewCondVar(_pr_activeLock); } if (!thread) PR_Abort(); @@ -126,18 +126,18 @@ void _PR_InitThreads(PRThreadType type, PRThreadPriority priority, * _PR_MD_INIT_THREAD() */ if (_PR_MD_INIT_THREAD(thread) == PR_FAILURE) { - /* - * XXX do what? - */ - } + /* + * XXX do what? + */ + } if (_PR_IS_NATIVE_THREAD(thread)) { - PR_APPEND_LINK(&thread->active, &_PR_ACTIVE_GLOBAL_THREADQ()); - _pr_global_threads++; + PR_APPEND_LINK(&thread->active, &_PR_ACTIVE_GLOBAL_THREADQ()); + _pr_global_threads++; } else { - PR_APPEND_LINK(&thread->active, &_PR_ACTIVE_LOCAL_THREADQ()); - _pr_local_threads++; - } + PR_APPEND_LINK(&thread->active, &_PR_ACTIVE_LOCAL_THREADQ()); + _pr_local_threads++; + } _pr_recycleThreads = 0; _pr_deadQLock = PR_NewLock(); @@ -159,13 +159,13 @@ static void _PR_InitializeNativeStack(PRThreadStack *ts) ** Setup stackTop and stackBottom values. */ #ifdef HAVE_STACK_GROWING_UP - ts->allocBase = (char*) ((((long)&ts) >> _pr_pageShift) - << _pr_pageShift); + ts->allocBase = (char*) ((((long)&ts) >> _pr_pageShift) + << _pr_pageShift); ts->stackBottom = ts->allocBase + ts->stackSize; ts->stackTop = ts->allocBase; #else - ts->allocBase = (char*) ((((long)&ts + _pr_pageSize - 1) - >> _pr_pageShift) << _pr_pageShift); + ts->allocBase = (char*) ((((long)&ts + _pr_pageSize - 1) + >> _pr_pageShift) << _pr_pageShift); ts->stackTop = ts->allocBase; ts->stackBottom = ts->allocBase - ts->stackSize; #endif @@ -180,7 +180,7 @@ void _PR_NotifyJoinWaiters(PRThread *thread) ** Notify on our "termination" condition variable so that joining ** thread will know about our termination. Switch our context and ** come back later on to continue the cleanup. - */ + */ PR_ASSERT(thread == _PR_MD_CURRENT_THREAD()); if (thread->term != NULL) { PR_Lock(_pr_terminationCVLock); @@ -195,7 +195,7 @@ void _PR_NotifyJoinWaiters(PRThread *thread) PR_NotifyCondVar(thread->term); PR_Unlock(_pr_terminationCVLock); _PR_MD_WAIT(thread, PR_INTERVAL_NO_TIMEOUT); - PR_ASSERT(thread->state != _PR_JOIN_WAIT); + PR_ASSERT(thread->state != _PR_JOIN_WAIT); } } @@ -235,19 +235,19 @@ static void _PR_InitializeRecycledThread(PRThread *thread) PRStatus _PR_RecycleThread(PRThread *thread) { if ( _PR_IS_NATIVE_THREAD(thread) && - _PR_NUM_DEADNATIVE < _pr_recycleThreads) { + _PR_NUM_DEADNATIVE < _pr_recycleThreads) { _PR_DEADQ_LOCK; PR_APPEND_LINK(&thread->links, &_PR_DEADNATIVEQ); _PR_INC_DEADNATIVE; _PR_DEADQ_UNLOCK; - return (PR_SUCCESS); + return (PR_SUCCESS); } else if ( !_PR_IS_NATIVE_THREAD(thread) && - _PR_NUM_DEADUSER < _pr_recycleThreads) { + _PR_NUM_DEADUSER < _pr_recycleThreads) { _PR_DEADQ_LOCK; PR_APPEND_LINK(&thread->links, &_PR_DEADUSERQ); _PR_INC_DEADUSER; _PR_DEADQ_UNLOCK; - return (PR_SUCCESS); + return (PR_SUCCESS); } return (PR_FAILURE); } @@ -283,7 +283,7 @@ _PR_DecrActiveThreadCount(PRThread *thread) ** Detach thread structure */ static void -_PR_DetachThread(PRThread *thread) +_PR_DestroyThread(PRThread *thread) { _MD_FREE_LOCK(&thread->threadLock); PR_DELETE(thread); @@ -293,40 +293,40 @@ void _PR_NativeDestroyThread(PRThread *thread) { if(thread->term) { - PR_DestroyCondVar(thread->term); + PR_DestroyCondVar(thread->term); thread->term = 0; } PR_DELETE(thread->stack); - _PR_DetachThread(thread); + _PR_DestroyThread(thread); } void _PR_UserDestroyThread(PRThread *thread) { if(thread->term) { - PR_DestroyCondVar(thread->term); - thread->term = 0; + PR_DestroyCondVar(thread->term); + thread->term = 0; + } + if (NULL != thread->privateData) + { + PR_ASSERT(0 != thread->tpdLength); + PR_DELETE(thread->privateData); + thread->privateData = NULL; + thread->tpdLength = 0; } - if (NULL != thread->privateData) - { - PR_ASSERT(0 != thread->tpdLength); - PR_DELETE(thread->privateData); - thread->privateData = NULL; - thread->tpdLength = 0; - } _MD_FREE_LOCK(&thread->threadLock); if (thread->threadAllocatedOnStack == 1) { - _PR_MD_CLEAN_THREAD(thread); - /* - * Because the no_sched field is set, this thread/stack will - * will not be re-used until the flag is cleared by the thread - * we will context switch to. - */ - _PR_FreeStack(thread->stack); + _PR_MD_CLEAN_THREAD(thread); + /* + * Because the no_sched field is set, this thread/stack will + * will not be re-used until the flag is cleared by the thread + * we will context switch to. + */ + _PR_FreeStack(thread->stack); } else { #ifdef WINNT - _PR_MD_CLEAN_THREAD(thread); + _PR_MD_CLEAN_THREAD(thread); #else /* * This assertion does not apply to NT. On NT, every fiber, @@ -347,38 +347,38 @@ _PR_UserDestroyThread(PRThread *thread) */ void _PR_NativeRunThread(void *arg) { - PRThread *thread = (PRThread *)arg; + PRThread *thread = (PRThread *)arg; _PR_MD_SET_CURRENT_THREAD(thread); _PR_MD_SET_CURRENT_CPU(NULL); - /* Set up the thread stack information */ - _PR_InitializeNativeStack(thread->stack); + /* Set up the thread stack information */ + _PR_InitializeNativeStack(thread->stack); - /* Set up the thread md information */ - if (_PR_MD_INIT_THREAD(thread) == PR_FAILURE) { - /* - * thread failed to initialize itself, possibly due to - * failure to allocate per-thread resources - */ - return; - } + /* Set up the thread md information */ + if (_PR_MD_INIT_THREAD(thread) == PR_FAILURE) { + /* + * thread failed to initialize itself, possibly due to + * failure to allocate per-thread resources + */ + return; + } while(1) { thread->state = _PR_RUNNING; - if ( !_PR_IS_NATIVE_THREAD(thread)) _PR_SET_INTSOFF(0); + if ( !_PR_IS_NATIVE_THREAD(thread)) _PR_MD_SET_INTSOFF(0); - /* - * Add to list of active threads - */ - PR_Lock(_pr_activeLock); - PR_APPEND_LINK(&thread->active, &_PR_ACTIVE_GLOBAL_THREADQ()); - _pr_global_threads++; - PR_Unlock(_pr_activeLock); + /* + * Add to list of active threads + */ + PR_Lock(_pr_activeLock); + PR_APPEND_LINK(&thread->active, &_PR_ACTIVE_GLOBAL_THREADQ()); + _pr_global_threads++; + PR_Unlock(_pr_activeLock); - (*thread->startFunc)(thread->arg); + (*thread->startFunc)(thread->arg); /* * The following two assertions are meant for NT asynch io. @@ -397,15 +397,15 @@ void _PR_NativeRunThread(void *arg) */ PR_ASSERT(thread->io_suspended == PR_FALSE); - /* - * remove thread from list of active threads - */ + /* + * remove thread from list of active threads + */ PR_Lock(_pr_activeLock); PR_REMOVE_LINK(&thread->active); - _pr_global_threads--; + _pr_global_threads--; PR_Unlock(_pr_activeLock); - PR_LOG(_pr_thread_lm, PR_LOG_MIN, ("thread exiting")); + PR_LOG(_pr_thread_lm, PR_LOG_MIN, ("thread exiting")); /* All done, time to go away */ _PR_CleanupThread(thread); @@ -417,21 +417,21 @@ void _PR_NativeRunThread(void *arg) thread->state = _PR_DEAD_STATE; if (!_pr_recycleThreads || (_PR_RecycleThread(thread) == - PR_FAILURE)) { - /* - * thread not recycled - * platform-specific thread exit processing - * - for stuff like releasing native-thread resources, etc. - */ - _PR_MD_EXIT_THREAD(thread); - /* - * Free memory allocated for the thread - */ - _PR_NativeDestroyThread(thread); - /* - * thread gone, cannot de-reference thread now - */ - return; + PR_FAILURE)) { + /* + * thread not recycled + * platform-specific thread exit processing + * - for stuff like releasing native-thread resources, etc. + */ + _PR_MD_EXIT_THREAD(thread); + /* + * Free memory allocated for the thread + */ + _PR_NativeDestroyThread(thread); + /* + * thread gone, cannot de-reference thread now + */ + return; } /* Now wait for someone to activate us again... */ @@ -445,7 +445,7 @@ static void _PR_UserRunThread(void) PRIntn is; if (_MD_LAST_THREAD()) - _MD_LAST_THREAD()->no_sched = 0; + _MD_LAST_THREAD()->no_sched = 0; #ifdef HAVE_CUSTOM_USER_THREADS if (thread->stack == NULL) { @@ -456,17 +456,17 @@ static void _PR_UserRunThread(void) while(1) { /* Run thread main */ - if ( !_PR_IS_NATIVE_THREAD(thread)) _PR_SET_INTSOFF(0); - - /* - * Add to list of active threads - */ - if (!(thread->flags & _PR_IDLE_THREAD)) { - PR_Lock(_pr_activeLock); - PR_APPEND_LINK(&thread->active, &_PR_ACTIVE_LOCAL_THREADQ()); - _pr_local_threads++; - PR_Unlock(_pr_activeLock); - } + if ( !_PR_IS_NATIVE_THREAD(thread)) _PR_MD_SET_INTSOFF(0); + + /* + * Add to list of active threads + */ + if (!(thread->flags & _PR_IDLE_THREAD)) { + PR_Lock(_pr_activeLock); + PR_APPEND_LINK(&thread->active, &_PR_ACTIVE_LOCAL_THREADQ()); + _pr_local_threads++; + PR_Unlock(_pr_activeLock); + } (*thread->startFunc)(thread->arg); @@ -488,33 +488,33 @@ static void _PR_UserRunThread(void) PR_ASSERT(thread->io_suspended == PR_FALSE); PR_Lock(_pr_activeLock); - /* - * remove thread from list of active threads - */ - if (!(thread->flags & _PR_IDLE_THREAD)) { - PR_REMOVE_LINK(&thread->active); - _pr_local_threads--; - } - PR_Unlock(_pr_activeLock); + /* + * remove thread from list of active threads + */ + if (!(thread->flags & _PR_IDLE_THREAD)) { + PR_REMOVE_LINK(&thread->active); + _pr_local_threads--; + } + PR_Unlock(_pr_activeLock); PR_LOG(_pr_thread_lm, PR_LOG_MIN, ("thread exiting")); /* All done, time to go away */ _PR_CleanupThread(thread); - _PR_INTSOFF(is); + _PR_INTSOFF(is); _PR_NotifyJoinWaiters(thread); - _PR_DecrActiveThreadCount(thread); + _PR_DecrActiveThreadCount(thread); thread->state = _PR_DEAD_STATE; if (!_pr_recycleThreads || (_PR_RecycleThread(thread) == - PR_FAILURE)) { + PR_FAILURE)) { /* ** Destroy the thread resources */ - _PR_UserDestroyThread(thread); + _PR_UserDestroyThread(thread); } /* @@ -542,55 +542,53 @@ void _PR_SetThreadPriority(PRThread *thread, PRThreadPriority newPri) } if (!_PR_IS_NATIVE_THREAD(me)) - _PR_INTSOFF(is); + _PR_INTSOFF(is); _PR_THREAD_LOCK(thread); if (newPri != thread->priority) { - PRUintn oldPri; - _PRCPU *cpu = thread->cpu; + _PRCPU *cpu = thread->cpu; - oldPri = thread->priority; - switch (thread->state) { - case _PR_RUNNING: - /* Change my priority */ + switch (thread->state) { + case _PR_RUNNING: + /* Change my priority */ _PR_RUNQ_LOCK(cpu); - thread->priority = newPri; - if (_PR_RUNQREADYMASK(cpu) >> (newPri + 1)) { - if (!_PR_IS_NATIVE_THREAD(me)) + thread->priority = newPri; + if (_PR_RUNQREADYMASK(cpu) >> (newPri + 1)) { + if (!_PR_IS_NATIVE_THREAD(me)) _PR_SET_RESCHED_FLAG(); - } + } _PR_RUNQ_UNLOCK(cpu); - break; + break; - case _PR_RUNNABLE: + case _PR_RUNNABLE: - _PR_RUNQ_LOCK(cpu); + _PR_RUNQ_LOCK(cpu); /* Move to different runQ */ _PR_DEL_RUNQ(thread); thread->priority = newPri; PR_ASSERT(!(thread->flags & _PR_IDLE_THREAD)); _PR_ADD_RUNQ(thread, cpu, newPri); - _PR_RUNQ_UNLOCK(cpu); + _PR_RUNQ_UNLOCK(cpu); if (newPri > me->priority) { - if (!_PR_IS_NATIVE_THREAD(me)) - _PR_SET_RESCHED_FLAG(); + if (!_PR_IS_NATIVE_THREAD(me)) + _PR_SET_RESCHED_FLAG(); } - break; + break; - case _PR_LOCK_WAIT: - case _PR_COND_WAIT: - case _PR_IO_WAIT: - case _PR_SUSPENDED: + case _PR_LOCK_WAIT: + case _PR_COND_WAIT: + case _PR_IO_WAIT: + case _PR_SUSPENDED: - thread->priority = newPri; - break; - } + thread->priority = newPri; + break; + } } _PR_THREAD_UNLOCK(thread); if (!_PR_IS_NATIVE_THREAD(me)) - _PR_INTSON(is); + _PR_INTSON(is); } /* @@ -605,7 +603,7 @@ static void _PR_Suspend(PRThread *thread) PR_ASSERT(!_PR_IS_NATIVE_THREAD(thread) || (!thread->cpu)); if (!_PR_IS_NATIVE_THREAD(me)) - _PR_INTSOFF(is); + _PR_INTSOFF(is); _PR_THREAD_LOCK(thread); switch (thread->state) { case _PR_RUNNABLE: @@ -617,21 +615,21 @@ static void _PR_Suspend(PRThread *thread) _PR_MISCQ_LOCK(thread->cpu); _PR_ADD_SUSPENDQ(thread, thread->cpu); _PR_MISCQ_UNLOCK(thread->cpu); - } else { - /* - * Only LOCAL threads are suspended by _PR_Suspend - */ - PR_ASSERT(0); - } + } else { + /* + * Only LOCAL threads are suspended by _PR_Suspend + */ + PR_ASSERT(0); + } thread->state = _PR_SUSPENDED; break; case _PR_RUNNING: - /* - * The thread being suspended should be a LOCAL thread with - * _pr_numCPUs == 1. Hence, the thread cannot be in RUNNING state - */ - PR_ASSERT(0); + /* + * The thread being suspended should be a LOCAL thread with + * _pr_numCPUs == 1. Hence, the thread cannot be in RUNNING state + */ + PR_ASSERT(0); break; case _PR_LOCK_WAIT: @@ -639,7 +637,7 @@ static void _PR_Suspend(PRThread *thread) case _PR_COND_WAIT: if (_PR_IS_NATIVE_THREAD(thread)) { _PR_MD_SUSPEND_THREAD(thread); - } + } thread->flags |= _PR_SUSPENDING; break; @@ -676,12 +674,12 @@ static void _PR_Resume(PRThread *thread) _PR_RUNQ_UNLOCK(thread->cpu); if (pri > _PR_MD_CURRENT_THREAD()->priority) { - if (!_PR_IS_NATIVE_THREAD(me)) - _PR_SET_RESCHED_FLAG(); + if (!_PR_IS_NATIVE_THREAD(me)) + _PR_SET_RESCHED_FLAG(); } - } else { - PR_ASSERT(0); - } + } else { + PR_ASSERT(0); + } break; case _PR_IO_WAIT: @@ -692,7 +690,7 @@ static void _PR_Resume(PRThread *thread) case _PR_LOCK_WAIT: { - PRLock *wLock = thread->wait.lock; + PRLock *wLock = thread->wait.lock; thread->flags &= ~_PR_SUSPENDING; @@ -704,25 +702,25 @@ static void _PR_Resume(PRThread *thread) break; } case _PR_RUNNABLE: - break; + break; case _PR_RUNNING: - /* - * The thread being suspended should be a LOCAL thread with - * _pr_numCPUs == 1. Hence, the thread cannot be in RUNNING state - */ - PR_ASSERT(0); - break; + /* + * The thread being suspended should be a LOCAL thread with + * _pr_numCPUs == 1. Hence, the thread cannot be in RUNNING state + */ + PR_ASSERT(0); + break; default: - /* - * thread should have been in one of the above-listed blocked states - * (_PR_JOIN_WAIT, _PR_IO_WAIT, _PR_UNBORN, _PR_DEAD_STATE) - */ + /* + * thread should have been in one of the above-listed blocked states + * (_PR_JOIN_WAIT, _PR_IO_WAIT, _PR_UNBORN, _PR_DEAD_STATE) + */ PR_Abort(); } _PR_THREAD_UNLOCK(thread); if (!_PR_IS_NATIVE_THREAD(me)) - _PR_INTSON(is); + _PR_INTSON(is); } @@ -747,7 +745,7 @@ static PRThread *get_thread(_PRCPU *cpu, PRBool *wakeup_cpus) } thread = NULL; for (pri = priMax; pri >= priMin ; pri-- ) { - if (r & (1 << pri)) { + if (r & (1 << pri)) { for (qp = _PR_RUNQ(cpu)[pri].next; qp != &_PR_RUNQ(cpu)[pri]; qp = qp->next) { @@ -756,30 +754,40 @@ static PRThread *get_thread(_PRCPU *cpu, PRBool *wakeup_cpus) * skip non-schedulable threads */ PR_ASSERT(!(thread->flags & _PR_IDLE_THREAD)); - if (thread->no_sched){ + if (thread->no_sched) { thread = NULL; - /* - * Need to wakeup cpus to avoid missing a - * runnable thread - * Waking up all CPU's need happen only once. - */ + /* + * Need to wakeup cpus to avoid missing a + * runnable thread + * Waking up all CPU's need happen only once. + */ - *wakeup_cpus = PR_TRUE; + *wakeup_cpus = PR_TRUE; + continue; + } else if (thread->flags & _PR_BOUND_THREAD) { + /* + * Thread bound to cpu 0 + */ + + thread = NULL; +#ifdef IRIX + _PR_MD_WAKEUP_PRIMORDIAL_CPU(); +#endif continue; } else if (thread->io_pending == PR_TRUE) { - /* - * A thread that is blocked for I/O needs to run - * on the same cpu on which it was blocked. This is because - * the cpu's ioq is accessed without lock protection and scheduling - * the thread on a different cpu would preclude this optimization. - */ + /* + * A thread that is blocked for I/O needs to run + * on the same cpu on which it was blocked. This is because + * the cpu's ioq is accessed without lock protection and scheduling + * the thread on a different cpu would preclude this optimization. + */ thread = NULL; - continue; + continue; } else { /* Pull thread off of its run queue */ _PR_DEL_RUNQ(thread); _PR_RUNQ_UNLOCK(cpu); - return(thread); + return(thread); } } } @@ -802,7 +810,7 @@ static PRThread *get_thread(_PRCPU *cpu, PRBool *wakeup_cpus) void _PR_Schedule(void) { PRThread *thread, *me = _PR_MD_CURRENT_THREAD(); - _PRCPU *cpu = me->cpu; + _PRCPU *cpu = _PR_MD_CURRENT_CPU(); PRIntn pri; PRUint32 r; PRCList *qp; @@ -824,22 +832,22 @@ void _PR_Schedule(void) _PR_RUNQ_LOCK(cpu); /* * if we are in SuspendAll mode, can schedule only the thread - * that called PR_SuspendAll + * that called PR_SuspendAll * * The thread may be ready to run now, after completing an I/O * operation, for example */ if ((thread = suspendAllThread) != 0) { - if ((!(thread->no_sched)) && (thread->state == _PR_RUNNABLE)) { + if ((!(thread->no_sched)) && (thread->state == _PR_RUNNABLE)) { /* Pull thread off of its run queue */ _PR_DEL_RUNQ(thread); _PR_RUNQ_UNLOCK(cpu); goto found_thread; - } else { + } else { thread = NULL; _PR_RUNQ_UNLOCK(cpu); goto idle_thread; - } + } } r = _PR_RUNQREADYMASK(cpu); if (r==0) { @@ -852,7 +860,7 @@ void _PR_Schedule(void) } thread = NULL; for (pri = priMax; pri >= priMin ; pri-- ) { - if (r & (1 << pri)) { + if (r & (1 << pri)) { for (qp = _PR_RUNQ(cpu)[pri].next; qp != &_PR_RUNQ(cpu)[pri]; qp = qp->next) { @@ -880,25 +888,25 @@ void _PR_Schedule(void) #if !defined(_PR_LOCAL_THREADS_ONLY) && defined(XP_UNIX) - wakeup_cpus = PR_FALSE; + wakeup_cpus = PR_FALSE; _PR_CPU_LIST_LOCK(); for (qp = _PR_CPUQ().next; qp != &_PR_CPUQ(); qp = qp->next) { - if (cpu != _PR_CPU_PTR(qp)) { - if ((thread = get_thread(_PR_CPU_PTR(qp), &wakeup_cpus)) - != NULL) { - thread->cpu = cpu; - _PR_CPU_LIST_UNLOCK(); - if (wakeup_cpus == PR_TRUE) - _PR_MD_WAKEUP_CPUS(); - goto found_thread; - } - } + if (cpu != _PR_CPU_PTR(qp)) { + if ((thread = get_thread(_PR_CPU_PTR(qp), &wakeup_cpus)) + != NULL) { + thread->cpu = cpu; + _PR_CPU_LIST_UNLOCK(); + if (wakeup_cpus == PR_TRUE) + _PR_MD_WAKEUP_CPUS(); + goto found_thread; + } + } } _PR_CPU_LIST_UNLOCK(); - if (wakeup_cpus == PR_TRUE) - _PR_MD_WAKEUP_CPUS(); + if (wakeup_cpus == PR_TRUE) + _PR_MD_WAKEUP_CPUS(); -#endif /* _PR_LOCAL_THREADS_ONLY */ +#endif /* _PR_LOCAL_THREADS_ONLY */ idle_thread: /* @@ -909,11 +917,11 @@ idle_thread: found_thread: PR_ASSERT((me == thread) || ((thread->state == _PR_RUNNABLE) && - (!(thread->no_sched)))); + (!(thread->no_sched)))); /* Resume the thread */ PR_LOG(_pr_sched_lm, PR_LOG_MAX, - ("switching to %d[%p]", thread->id, thread)); + ("switching to %d[%p]", thread->id, thread)); PR_ASSERT(thread->state != _PR_RUNNING); thread->state = _PR_RUNNING; @@ -921,6 +929,7 @@ found_thread: * resource, and by the time we got here another real native thread had * already given us the resource and put us back on the runqueue */ + PR_ASSERT(thread->cpu == _PR_MD_CURRENT_CPU()); if (thread != me) _PR_MD_RESTORE_CONTEXT(thread); #if 0 @@ -962,9 +971,9 @@ _PR_AttachThread(PRThreadType type, PRThreadPriority priority, thread->state = _PR_RUNNING; PR_INIT_CLIST(&thread->lockList); if (_MD_NEW_LOCK(&thread->threadLock) == PR_FAILURE) { - PR_DELETE(thread); - return 0; - } + PR_DELETE(thread); + return 0; + } return thread; } @@ -975,12 +984,12 @@ _PR_AttachThread(PRThreadType type, PRThreadPriority priority, PR_IMPLEMENT(PRThread*) _PR_NativeCreateThread(PRThreadType type, - void (*start)(void *arg), - void *arg, - PRThreadPriority priority, - PRThreadScope scope, - PRThreadState state, - PRUint32 stackSize, + void (*start)(void *arg), + void *arg, + PRThreadPriority priority, + PRThreadScope scope, + PRThreadState state, + PRUint32 stackSize, PRUint32 flags) { #if defined(XP_MAC) @@ -993,7 +1002,7 @@ _PR_NativeCreateThread(PRThreadType type, if (thread) { PR_Lock(_pr_activeLock); - thread->flags = (flags | _PR_GLOBAL_SCOPE); + thread->flags = (flags | _PR_GLOBAL_SCOPE); thread->id = ++_pr_utid; if (type == PR_SYSTEM_THREAD) { thread->flags |= _PR_SYSTEM; @@ -1019,28 +1028,28 @@ _PR_NativeCreateThread(PRThreadType type, */ if (state == PR_JOINABLE_THREAD) { thread->term = PR_NewCondVar(_pr_terminationCVLock); - if (thread->term == NULL) { - PR_DELETE(thread->stack); - goto done; - } + if (thread->term == NULL) { + PR_DELETE(thread->stack); + goto done; + } } - thread->state = _PR_RUNNING; + thread->state = _PR_RUNNING; if (_PR_MD_CREATE_THREAD(thread, _PR_NativeRunThread, priority, scope,state,stackSize) == PR_SUCCESS) { return thread; } if (thread->term) { PR_DestroyCondVar(thread->term); - thread->term = NULL; - } - PR_DELETE(thread->stack); + thread->term = NULL; + } + PR_DELETE(thread->stack); } done: if (thread) { - _PR_DecrActiveThreadCount(thread); - _PR_DetachThread(thread); + _PR_DecrActiveThreadCount(thread); + _PR_DestroyThread(thread); } return NULL; } @@ -1048,12 +1057,12 @@ done: /************************************************************************/ PR_IMPLEMENT(PRThread*) _PR_CreateThread(PRThreadType type, - void (*start)(void *arg), - void *arg, - PRThreadPriority priority, - PRThreadScope scope, - PRThreadState state, - PRUint32 stackSize, + void (*start)(void *arg), + void *arg, + PRThreadPriority priority, + PRThreadScope scope, + PRThreadState state, + PRUint32 stackSize, PRUint32 flags) { PRThread *me; @@ -1065,35 +1074,35 @@ PR_IMPLEMENT(PRThread*) _PR_CreateThread(PRThreadType type, PRIntn useRecycled = 0; PRBool status; - /* - First, pin down the priority. Not all compilers catch passing out of - range enum here. If we let bad values thru, priority queues won't work. - */ + /* + First, pin down the priority. Not all compilers catch passing out of + range enum here. If we let bad values thru, priority queues won't work. + */ if (priority > PR_PRIORITY_LAST) { priority = PR_PRIORITY_LAST; } else if (priority < PR_PRIORITY_FIRST) { priority = PR_PRIORITY_FIRST; } - + if (!_pr_initialized) _PR_ImplicitInitialization(); if (! (flags & _PR_IDLE_THREAD)) - me = _PR_MD_CURRENT_THREAD(); + me = _PR_MD_CURRENT_THREAD(); -#if defined(_PR_GLOBAL_THREADS_ONLY) +#if defined(_PR_GLOBAL_THREADS_ONLY) scope = PR_GLOBAL_THREAD; #endif native = ((scope == PR_GLOBAL_THREAD) && _PR_IS_NATIVE_THREAD_SUPPORTED()); - _PR_ADJUST_STACKSIZE(stackSize); + _PR_ADJUST_STACKSIZE(stackSize); if (native) { - /* - * clear the IDLE_THREAD flag which applies to LOCAL - * threads only - */ - flags &= ~_PR_IDLE_THREAD; + /* + * clear the IDLE_THREAD flag which applies to LOCAL + * threads only + */ + flags &= ~_PR_IDLE_THREAD; flags |= _PR_GLOBAL_SCOPE; if (_PR_NUM_DEADNATIVE > 0) { _PR_DEADQ_LOCK; @@ -1109,33 +1118,31 @@ PR_IMPLEMENT(PRThread*) _PR_CreateThread(PRThreadType type, _PR_InitializeRecycledThread(thread); thread->startFunc = start; thread->arg = arg; - PR_Lock(_pr_activeLock); - thread->flags = (flags | _PR_GLOBAL_SCOPE); - if (type == PR_SYSTEM_THREAD) { - thread->flags |= _PR_SYSTEM; - _pr_systemActive++; - } else { - _pr_userActive++; - } - PR_Unlock(_pr_activeLock); - - if (state == PR_JOINABLE_THREAD) { - if (!thread->term) - thread->term = PR_NewCondVar(_pr_terminationCVLock); - } - else { - if(thread->term) { - PR_DestroyCondVar(thread->term); - thread->term = 0; - } - } + thread->flags = (flags | _PR_GLOBAL_SCOPE); + if (type == PR_SYSTEM_THREAD) + { + thread->flags |= _PR_SYSTEM; + PR_AtomicIncrement(&_pr_systemActive); + } + else PR_AtomicIncrement(&_pr_userActive); + + if (state == PR_JOINABLE_THREAD) { + if (!thread->term) + thread->term = PR_NewCondVar(_pr_terminationCVLock); + } + else { + if(thread->term) { + PR_DestroyCondVar(thread->term); + thread->term = 0; + } + } thread->priority = priority; - _PR_MD_SET_PRIORITY(&(thread->md), priority); - /* XXX what about stackSize? */ - thread->state = _PR_RUNNING; + _PR_MD_SET_PRIORITY(&(thread->md), priority); + /* XXX what about stackSize? */ + thread->state = _PR_RUNNING; _PR_MD_WAKEUP_WAITER(thread); - return thread; + return thread; } } thread = _PR_NativeCreateThread(type, start, arg, priority, @@ -1156,7 +1163,7 @@ PR_IMPLEMENT(PRThread*) _PR_CreateThread(PRThreadType type, while( ptr != &_PR_DEADUSERQ ) { thread = _PR_THREAD_PTR(ptr); if ((thread->stack->stackSize >= stackSize) && - (!thread->no_sched)) { + (!thread->no_sched)) { PR_REMOVE_LINK(&thread->links); _PR_DEC_DEADUSER; break; @@ -1173,15 +1180,15 @@ PR_IMPLEMENT(PRThread*) _PR_CreateThread(PRThreadType type, thread->startFunc = start; thread->arg = arg; thread->priority = priority; - if (state == PR_JOINABLE_THREAD) { - if (!thread->term) - thread->term = PR_NewCondVar(_pr_terminationCVLock); - } else { - if(thread->term) { - PR_DestroyCondVar(thread->term); - thread->term = 0; - } - } + if (state == PR_JOINABLE_THREAD) { + if (!thread->term) + thread->term = PR_NewCondVar(_pr_terminationCVLock); + } else { + if(thread->term) { + PR_DestroyCondVar(thread->term); + thread->term = 0; + } + } useRecycled++; } } @@ -1191,31 +1198,31 @@ PR_IMPLEMENT(PRThread*) _PR_CreateThread(PRThreadType type, stack = _PR_NewStack(stackSize); if (!stack) { PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); - return 0; + return 0; } - stack->thr = thread; /* Allocate thread object and per-thread data off the top of the stack*/ top = stack->stackTop; #ifdef HAVE_STACK_GROWING_UP thread = (PRThread*) top; top = top + sizeof(PRThread); - /* - * Make stack 64-byte aligned - */ + /* + * Make stack 64-byte aligned + */ if ((PRUptrdiff)top & 0x3f) { top = (char*)(((PRUptrdiff)top + 0x40) & ~0x3f); } #else top = top - sizeof(PRThread); thread = (PRThread*) top; - /* - * Make stack 64-byte aligned - */ + /* + * Make stack 64-byte aligned + */ if ((PRUptrdiff)top & 0x3f) { top = (char*)((PRUptrdiff)top & ~0x3f); } #endif + stack->thr = thread; memset(thread, 0, sizeof(PRThread)); thread->threadAllocatedOnStack = 1; #else @@ -1229,8 +1236,6 @@ PR_IMPLEMENT(PRThread*) _PR_CreateThread(PRThreadType type, #endif /* Initialize thread */ - if (stack) - stack->thr = thread; thread->tpdLength = 0; thread->privateData = NULL; thread->stack = stack; @@ -1240,36 +1245,36 @@ PR_IMPLEMENT(PRThread*) _PR_CreateThread(PRThreadType type, PR_INIT_CLIST(&thread->lockList); if (_PR_MD_INIT_THREAD(thread) == PR_FAILURE) { - if (thread->threadAllocatedOnStack == 1) - _PR_FreeStack(thread->stack); - else { - PR_DELETE(thread); - } - PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, 0); - return NULL; - } - - if (_MD_NEW_LOCK(&thread->threadLock) == PR_FAILURE) { - if (thread->threadAllocatedOnStack == 1) - _PR_FreeStack(thread->stack); - else { - PR_DELETE(thread->privateData); - PR_DELETE(thread); - } - PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, 0); - return NULL; - } + if (thread->threadAllocatedOnStack == 1) + _PR_FreeStack(thread->stack); + else { + PR_DELETE(thread); + } + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, 0); + return NULL; + } + + if (_MD_NEW_LOCK(&thread->threadLock) == PR_FAILURE) { + if (thread->threadAllocatedOnStack == 1) + _PR_FreeStack(thread->stack); + else { + PR_DELETE(thread->privateData); + PR_DELETE(thread); + } + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, 0); + return NULL; + } _PR_MD_INIT_CONTEXT(thread, top, _PR_UserRunThread, &status); if (status == PR_FALSE) { - _MD_FREE_LOCK(&thread->threadLock); - if (thread->threadAllocatedOnStack == 1) - _PR_FreeStack(thread->stack); - else { - PR_DELETE(thread->privateData); + _MD_FREE_LOCK(&thread->threadLock); + if (thread->threadAllocatedOnStack == 1) + _PR_FreeStack(thread->stack); + else { + PR_DELETE(thread->privateData); PR_DELETE(thread); - } + } return NULL; } @@ -1279,16 +1284,16 @@ PR_IMPLEMENT(PRThread*) _PR_CreateThread(PRThreadType type, */ if (state == PR_JOINABLE_THREAD) { thread->term = PR_NewCondVar(_pr_terminationCVLock); - if (thread->term == NULL) { - _MD_FREE_LOCK(&thread->threadLock); - if (thread->threadAllocatedOnStack == 1) - _PR_FreeStack(thread->stack); - else { - PR_DELETE(thread->privateData); - PR_DELETE(thread); - } - return NULL; - } + if (thread->term == NULL) { + _MD_FREE_LOCK(&thread->threadLock); + if (thread->threadAllocatedOnStack == 1) + _PR_FreeStack(thread->stack); + else { + PR_DELETE(thread->privateData); + PR_DELETE(thread); + } + return NULL; + } } } @@ -1306,9 +1311,9 @@ PR_IMPLEMENT(PRThread*) _PR_CreateThread(PRThreadType type, /* Make thread runnable */ thread->state = _PR_RUNNABLE; - /* - * Add to list of active threads - */ + /* + * Add to list of active threads + */ PR_Unlock(_pr_activeLock); if ( (thread->flags & _PR_IDLE_THREAD) || _PR_IS_NATIVE_THREAD(me) ) @@ -1317,7 +1322,7 @@ PR_IMPLEMENT(PRThread*) _PR_CreateThread(PRThreadType type, thread->cpu = _PR_MD_CURRENT_CPU(); if ((! (thread->flags & _PR_IDLE_THREAD)) && !_PR_IS_NATIVE_THREAD(me)) - _PR_INTSOFF(is); + _PR_INTSOFF(is); if ((! (thread->flags & _PR_IDLE_THREAD)) && !_PR_IS_NATIVE_THREAD(thread)) { _PR_RUNQ_LOCK(thread->cpu); _PR_ADD_RUNQ(thread, thread->cpu, priority); @@ -1334,19 +1339,19 @@ PR_IMPLEMENT(PRThread*) _PR_CreateThread(PRThreadType type, _PR_MD_WAKEUP_WAITER(NULL); } if ((! (thread->flags & _PR_IDLE_THREAD)) && !_PR_IS_NATIVE_THREAD(me) ) - _PR_INTSON(is); + _PR_INTSON(is); } return thread; } PR_IMPLEMENT(PRThread*) PR_CreateThread(PRThreadType type, - void (*start)(void *arg), - void *arg, - PRThreadPriority priority, - PRThreadScope scope, - PRThreadState state, - PRUint32 stackSize) + void (*start)(void *arg), + void *arg, + PRThreadPriority priority, + PRThreadScope scope, + PRThreadState state, + PRUint32 stackSize) { return _PR_CreateThread(type, start, arg, priority, scope, state, stackSize, 0); @@ -1354,9 +1359,9 @@ PR_IMPLEMENT(PRThread*) PR_CreateThread(PRThreadType type, /* ** Associate a thread object with an existing native thread. -** "type" is the type of thread object to attach -** "priority" is the priority to assign to the thread -** "stack" defines the shape of the threads stack +** "type" is the type of thread object to attach +** "priority" is the priority to assign to the thread +** "stack" defines the shape of the threads stack ** ** This can return NULL if some kind of error occurs, or if memory is ** tight. @@ -1364,7 +1369,7 @@ PR_IMPLEMENT(PRThread*) PR_CreateThread(PRThreadType type, ** This call is not normally needed unless you create your own native ** thread. PR_Init does this automatically for the primordial thread. */ -PR_IMPLEMENT(PRThread*) _PRI_AttachThread(PRThreadType type, +PRThread* _PRI_AttachThread(PRThreadType type, PRThreadPriority priority, PRThreadStack *stack, PRUint32 flags) { PRThread *thread; @@ -1372,6 +1377,7 @@ PR_IMPLEMENT(PRThread*) _PRI_AttachThread(PRThreadType type, if ((thread = _PR_MD_GET_ATTACHED_THREAD()) != NULL) { return thread; } + _PR_MD_SET_CURRENT_THREAD(NULL); /* Clear out any state if this thread was attached before */ _PR_MD_SET_CURRENT_CPU(NULL); @@ -1387,7 +1393,7 @@ PR_IMPLEMENT(PRThread*) _PRI_AttachThread(PRThreadType type, if (!stack) { thread->stack = PR_NEWZAP(PRThreadStack); if (!thread->stack) { - _PR_DetachThread(thread); + _PR_DestroyThread(thread); return NULL; } thread->stack->stackSize = _MD_DEFAULT_STACK_SIZE; @@ -1396,9 +1402,9 @@ PR_IMPLEMENT(PRThread*) _PRI_AttachThread(PRThreadType type, if (_PR_MD_INIT_ATTACHED_THREAD(thread) == PR_FAILURE) { PR_DELETE(thread->stack); - _PR_DetachThread(thread); + _PR_DestroyThread(thread); return NULL; - } + } _PR_MD_SET_CURRENT_CPU(NULL); @@ -1423,34 +1429,31 @@ PR_IMPLEMENT(PRThread*) _PRI_AttachThread(PRThreadType type, PR_IMPLEMENT(PRThread*) PR_AttachThread(PRThreadType type, PRThreadPriority priority, PRThreadStack *stack) { - return _PRI_AttachThread(type, priority, stack, 0); + return PR_GetCurrentThread(); } -/* -** Detach the nspr thread from the currently executing native thread. -** The thread object will be destroyed and all related data attached -** to it. The exit procs will be invoked. -** -** This call is not normally needed unless you create your own native -** thread. PR_Exit will automatially detach the nspr thread object -** created by PR_Init for the primordial thread. -** -** This call returns after the nspr thread object is destroyed. -*/ PR_IMPLEMENT(void) PR_DetachThread(void) { - PRIntn is; +} + +void _PRI_DetachThread(void) +{ PRThread *me = _PR_MD_CURRENT_THREAD(); + if (me->flags & _PR_PRIMORDIAL) { + /* + * ignore, if primordial thread + */ + return; + } PR_ASSERT(me->flags & _PR_ATTACHED); + PR_ASSERT(_PR_IS_NATIVE_THREAD(me)); _PR_CleanupThread(me); - PR_DELETE(me->privateData); - _PR_MD_CLEAN_THREAD(me); + PR_DELETE(me->privateData); - /*XXX we need DetachCPU */ - if ( !_PR_IS_NATIVE_THREAD(me)) _PR_INTSOFF(is); _PR_DecrActiveThreadCount(me); - if ( !_PR_IS_NATIVE_THREAD(me)) _PR_FAST_INTSON(is); + + _PR_MD_CLEAN_THREAD(me); _PR_MD_SET_CURRENT_THREAD(NULL); if (!me->threadAllocatedOnStack) PR_DELETE(me->stack); @@ -1460,7 +1463,7 @@ PR_IMPLEMENT(void) PR_DetachThread(void) /* ** Wait for thread termination: -** "thread" is the target thread +** "thread" is the target thread ** ** This can return PR_FAILURE if no joinable thread could be found ** corresponding to the specified target thread. @@ -1478,10 +1481,11 @@ PR_IMPLEMENT(PRStatus) PR_JoinThread(PRThread *thread) PRThread *me = _PR_MD_CURRENT_THREAD(); if (!_PR_IS_NATIVE_THREAD(me)) - _PR_INTSOFF(is); + _PR_INTSOFF(is); term = thread->term; /* can't join a non-joinable thread */ if (term == NULL) { + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); goto ErrorExit; } @@ -1490,7 +1494,7 @@ PR_IMPLEMENT(PRStatus) PR_JoinThread(PRThread *thread) goto ErrorExit; } if (!_PR_IS_NATIVE_THREAD(me)) - _PR_INTSON(is); + _PR_INTSON(is); /* wait for the target thread's termination cv invariant */ PR_Lock (_pr_terminationCVLock); @@ -1498,14 +1502,14 @@ PR_IMPLEMENT(PRStatus) PR_JoinThread(PRThread *thread) (void) PR_WaitCondVar(term, PR_INTERVAL_NO_TIMEOUT); } (void) PR_Unlock (_pr_terminationCVLock); - + /* Remove target thread from global waiting to join Q; make it runnable again and put it back on its run Q. When it gets scheduled later in _PR_RunThread code, it will clean up its stack. - */ + */ if (!_PR_IS_NATIVE_THREAD(me)) - _PR_INTSOFF(is); + _PR_INTSOFF(is); thread->state = _PR_RUNNABLE; if ( !_PR_IS_NATIVE_THREAD(thread) ) { _PR_THREAD_LOCK(thread); @@ -1518,7 +1522,7 @@ PR_IMPLEMENT(PRStatus) PR_JoinThread(PRThread *thread) _PR_THREAD_UNLOCK(thread); } if (!_PR_IS_NATIVE_THREAD(me)) - _PR_INTSON(is); + _PR_INTSON(is); _PR_MD_WAKEUP_WAITER(thread); @@ -1533,16 +1537,16 @@ PR_IMPLEMENT(void) PR_SetThreadPriority(PRThread *thread, PRThreadPriority newPri) { - /* - First, pin down the priority. Not all compilers catch passing out of - range enum here. If we let bad values thru, priority queues won't work. - */ + /* + First, pin down the priority. Not all compilers catch passing out of + range enum here. If we let bad values thru, priority queues won't work. + */ if (newPri > PR_PRIORITY_LAST) { newPri = PR_PRIORITY_LAST; } else if (newPri < PR_PRIORITY_FIRST) { newPri = PR_PRIORITY_FIRST; } - + if ( _PR_IS_NATIVE_THREAD(thread) ) { thread->priority = newPri; _PR_MD_SET_PRIORITY(&(thread->md), newPri); @@ -1567,18 +1571,18 @@ PR_IMPLEMENT(void) PR_SuspendAll(void) suspendAllThread = _PR_MD_CURRENT_THREAD(); _PR_MD_BEGIN_SUSPEND_ALL(); for (qp = _PR_ACTIVE_LOCAL_THREADQ().next; - qp != &_PR_ACTIVE_LOCAL_THREADQ(); qp = qp->next) { - if ((me != _PR_ACTIVE_THREAD_PTR(qp)) && - (_PR_ACTIVE_THREAD_PTR(qp)->flags & _PR_GCABLE_THREAD)) { - _PR_Suspend(_PR_ACTIVE_THREAD_PTR(qp)); + qp != &_PR_ACTIVE_LOCAL_THREADQ(); qp = qp->next) { + if ((me != _PR_ACTIVE_THREAD_PTR(qp)) && + (_PR_ACTIVE_THREAD_PTR(qp)->flags & _PR_GCABLE_THREAD)) { + _PR_Suspend(_PR_ACTIVE_THREAD_PTR(qp)); PR_ASSERT((_PR_ACTIVE_THREAD_PTR(qp))->state != _PR_RUNNING); } } for (qp = _PR_ACTIVE_GLOBAL_THREADQ().next; - qp != &_PR_ACTIVE_GLOBAL_THREADQ(); qp = qp->next) { - if ((me != _PR_ACTIVE_THREAD_PTR(qp)) && - (_PR_ACTIVE_THREAD_PTR(qp)->flags & _PR_GCABLE_THREAD)) - /* PR_Suspend(_PR_ACTIVE_THREAD_PTR(qp)); */ + qp != &_PR_ACTIVE_GLOBAL_THREADQ(); qp = qp->next) { + if ((me != _PR_ACTIVE_THREAD_PTR(qp)) && + (_PR_ACTIVE_THREAD_PTR(qp)->flags & _PR_GCABLE_THREAD)) + /* PR_Suspend(_PR_ACTIVE_THREAD_PTR(qp)); */ _PR_MD_SUSPEND_THREAD(_PR_ACTIVE_THREAD_PTR(qp)); } _PR_MD_END_SUSPEND_ALL(); @@ -1598,15 +1602,15 @@ PR_IMPLEMENT(void) PR_ResumeAll(void) */ _PR_MD_BEGIN_RESUME_ALL(); for (qp = _PR_ACTIVE_LOCAL_THREADQ().next; - qp != &_PR_ACTIVE_LOCAL_THREADQ(); qp = qp->next) { - if ((me != _PR_ACTIVE_THREAD_PTR(qp)) && - (_PR_ACTIVE_THREAD_PTR(qp)->flags & _PR_GCABLE_THREAD)) - _PR_Resume(_PR_ACTIVE_THREAD_PTR(qp)); + qp != &_PR_ACTIVE_LOCAL_THREADQ(); qp = qp->next) { + if ((me != _PR_ACTIVE_THREAD_PTR(qp)) && + (_PR_ACTIVE_THREAD_PTR(qp)->flags & _PR_GCABLE_THREAD)) + _PR_Resume(_PR_ACTIVE_THREAD_PTR(qp)); } for (qp = _PR_ACTIVE_GLOBAL_THREADQ().next; - qp != &_PR_ACTIVE_GLOBAL_THREADQ(); qp = qp->next) { - if ((me != _PR_ACTIVE_THREAD_PTR(qp)) && - (_PR_ACTIVE_THREAD_PTR(qp)->flags & _PR_GCABLE_THREAD)) + qp != &_PR_ACTIVE_GLOBAL_THREADQ(); qp = qp->next) { + if ((me != _PR_ACTIVE_THREAD_PTR(qp)) && + (_PR_ACTIVE_THREAD_PTR(qp)->flags & _PR_GCABLE_THREAD)) _PR_MD_RESUME_THREAD(_PR_ACTIVE_THREAD_PTR(qp)); } _PR_MD_END_RESUME_ALL(); diff --git a/pr/src/threads/prcthr.c b/pr/src/threads/prcthr.c index 6b3c80c7..1d9fd809 100644 --- a/pr/src/threads/prcthr.c +++ b/pr/src/threads/prcthr.c @@ -86,7 +86,10 @@ PR_IMPLEMENT(PRStatus) PR_Yield() */ PR_IMPLEMENT(PRStatus) PR_Sleep(PRIntervalTime timeout) { - PRStatus rv = PR_SUCCESS; + PRStatus rv = PR_SUCCESS; + + if (!_pr_initialized) _PR_ImplicitInitialization(); + if (PR_INTERVAL_NO_WAIT == timeout) { /* @@ -129,16 +132,19 @@ PR_IMPLEMENT(PRStatus) PR_Sleep(PRIntervalTime timeout) ** but the lock and cvar used are local to the implementation ** and not visible to the caller, therefore not notifiable. */ - PRIntervalTime timein = PR_IntervalNow(); - PRCondVar *cv = PR_NewCondVar(_pr_sleeplock); + PRCondVar *cv; + PRIntervalTime timein; + timein = PR_IntervalNow(); + cv = PR_NewCondVar(_pr_sleeplock); + PR_ASSERT(cv != NULL); PR_Lock(_pr_sleeplock); - while (rv == PR_SUCCESS) + do { PRIntervalTime delta = PR_IntervalNow() - timein; if (delta > timeout) break; rv = PR_WaitCondVar(cv, timeout - delta); - } + } while (rv == PR_SUCCESS); PR_Unlock(_pr_sleeplock); PR_DestroyCondVar(cv); } @@ -366,8 +372,9 @@ PR_IMPLEMENT(PRThread*) PR_CreateThreadBound(PRThreadType type, PR_IMPLEMENT(PRThread*) PR_AttachThreadGCAble( PRThreadType type, PRThreadPriority priority, PRThreadStack *stack) { - if (!_pr_initialized) _PR_ImplicitInitialization(); - return _PRI_AttachThread(type, priority, stack, _PR_GCABLE_THREAD); + /* $$$$ not sure how to finese this one */ + PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); + return NULL; } PR_IMPLEMENT(void) PR_SetThreadGCAble() diff --git a/pr/src/threads/prtpd.c b/pr/src/threads/prtpd.c index b92ebbbb..54ce8027 100644 --- a/pr/src/threads/prtpd.c +++ b/pr/src/threads/prtpd.c @@ -44,40 +44,24 @@ #define _PR_TPD_MODULO 8 /* vectors are extended by this much */ #define _PR_TPD_LIMIT 128 /* arbitary limit on the TPD slots */ -static PRUintn _pr_tpd_highwater = 0; /* next TPD key to be assigned */ -static PRUintn _pr_tpd_length = 0; /* current length of destructor vector */ +static PRInt32 _pr_tpd_length = 0; /* current length of destructor vector */ +static PRInt32 _pr_tpd_highwater = 0; /* next TPD key to be assigned */ PRThreadPrivateDTOR *_pr_tpd_destructors = NULL; /* the destructors are associated with the keys, therefore asserting that the TPD key depicts the data's 'type' */ /* Lock protecting the index assignment of per-thread-private data table */ -#ifdef _PR_NO_PREEMPT -#define _PR_NEW_LOCK_TPINDEX() -#define _PR_FREE_LOCK_TPINDEX() -#define _PR_LOCK_TPINDEX() -#define _PR_UNLOCK_TPINDEX() -#else -#ifdef _PR_LOCAL_THREADS_ONLY -#define _PR_NEW_LOCK_TPINDEX() -#define _PR_FREE_LOCK_TPINDEX() -#define _PR_LOCK_TPINDEX() _PR_INTSOFF(_is) -#define _PR_UNLOCK_TPINDEX() _PR_INTSON(_is) -#else -static PRLock *_pr_threadPrivateIndexLock; -#define _PR_NEW_LOCK_TPINDEX() (_pr_threadPrivateIndexLock = PR_NewLock()) -#define _PR_FREE_LOCK_TPINDEX() (PR_DestroyLock(_pr_threadPrivateIndexLock)) -#define _PR_LOCK_TPINDEX() PR_Lock(_pr_threadPrivateIndexLock) -#define _PR_UNLOCK_TPINDEX() PR_Unlock(_pr_threadPrivateIndexLock) -#endif -#endif /* ** Initialize the thread private data manipulation */ void _PR_InitTPD() { - _PR_NEW_LOCK_TPINDEX(); + _pr_tpd_destructors = (PRThreadPrivateDTOR*) + PR_CALLOC(_PR_TPD_LIMIT * sizeof(PRThreadPrivateDTOR*)); + PR_ASSERT(NULL != _pr_tpd_destructors); + _pr_tpd_length = _PR_TPD_LIMIT; } /* @@ -85,8 +69,7 @@ void _PR_InitTPD() */ void _PR_CleanupTPD(void) { - _PR_FREE_LOCK_TPINDEX(); -} +} /* _PR_CleanupTPD */ /* ** This routine returns a new index for per-thread-private data table. @@ -101,8 +84,8 @@ void _PR_CleanupTPD(void) ** is NULL, and upon thread creation the value associated with all indices for ** that thread is NULL. ** -** "dtor" is the destructor function to invoke when the private -** data is destroyed +** "dtor" is the destructor function to invoke when the private +** data is destroyed ** ** Returns PR_FAILURE if the total number of indices will exceed the maximun ** allowed. @@ -112,49 +95,24 @@ PR_IMPLEMENT(PRStatus) PR_NewThreadPrivateIndex( PRUintn *newIndex, PRThreadPrivateDTOR dtor) { PRStatus rv; + PRInt32 index; if (!_pr_initialized) _PR_ImplicitInitialization(); + PR_ASSERT(NULL != newIndex); + PR_ASSERT(NULL != _pr_tpd_destructors); - if (_pr_tpd_highwater >= _PR_TPD_LIMIT) + index = PR_AtomicIncrement(&_pr_tpd_highwater); /* allocate index */ + if (_PR_TPD_LIMIT < index) { PR_SetError(PR_TPD_RANGE_ERROR, 0); - rv = PR_FAILURE; /* that's just wrong */ + rv = PR_FAILURE; /* that's just wrong */ } else { - PRThreadPrivateDTOR *old = NULL; - PRIntn _is; - - _PR_LOCK_TPINDEX(); - if (_pr_tpd_highwater >= _pr_tpd_length) - { - old = _pr_tpd_destructors; - _pr_tpd_destructors = PR_CALLOC( - (_pr_tpd_length + _PR_TPD_MODULO) * sizeof(PRThreadPrivateDTOR*)); - if (NULL == _pr_tpd_destructors) - { - _pr_tpd_destructors = old; old = NULL; - PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); - rv = PR_FAILURE; /* that's just wrong */ - goto failed; /* then extract one's self */ - } - else - { - memcpy( - _pr_tpd_destructors, old, - _pr_tpd_length * sizeof(PRThreadPrivateDTOR*)); - _pr_tpd_length += _PR_TPD_MODULO; - } - } - - *newIndex = _pr_tpd_highwater++; /* this is really all we wanted */ - _pr_tpd_destructors[*newIndex] = dtor; /* record destructor @index */ - -failed: - _PR_UNLOCK_TPINDEX(); - if (NULL != old) PR_DELETE(old); - rv = PR_SUCCESS; + _pr_tpd_destructors[index] = dtor; /* record destructor @index */ + *newIndex = (PRIntn)index; /* copy into client's location */ + rv = PR_SUCCESS; /* that's okay */ } return rv; @@ -162,8 +120,8 @@ failed: /* ** Define some per-thread-private data. -** "index" is an index into the per-thread private data table -** "priv" is the per-thread-private data +** "index" is an index into the per-thread private data table +** "priv" is the per-thread-private data ** ** If the per-thread private data table has a previously registered ** destructor function and a non-NULL per-thread-private data value, @@ -173,9 +131,10 @@ failed: ** high water mark) or memory is insufficient to allocate an exanded vector. */ -PR_IMPLEMENT(PRStatus) PR_SetThreadPrivate(PRUintn index, void *priv) +PR_IMPLEMENT(PRStatus) PR_SetThreadPrivate(PRUintn his, void *priv) { PRStatus rv = PR_SUCCESS; + PRInt32 index = (PRInt32)his; PRThread *self = PR_GetCurrentThread(); /* @@ -183,17 +142,13 @@ PR_IMPLEMENT(PRStatus) PR_SetThreadPrivate(PRUintn index, void *priv) ** thread. But if the index has been allocated, it's okay to go ** ahead and extend this one now. */ - if (index >= _pr_tpd_highwater) + if (index > _pr_tpd_highwater) { - PR_ASSERT(index < _pr_tpd_highwater); PR_SetError(PR_TPD_RANGE_ERROR, 0); - rv = PR_FAILURE; + rv = PR_FAILURE; } else { - PRIntn _is; - - _PR_LOCK_TPINDEX(); if ((NULL == self->privateData) || (self->tpdLength <= index)) { void *extension = PR_CALLOC(_pr_tpd_length * sizeof(void*)); @@ -206,7 +161,7 @@ PR_IMPLEMENT(PRStatus) PR_SetThreadPrivate(PRUintn index, void *priv) extension, self->privateData, self->tpdLength * sizeof(void*)); self->tpdLength = _pr_tpd_length; - self->privateData = extension; + self->privateData = (void**)extension; } } /* @@ -217,9 +172,7 @@ PR_IMPLEMENT(PRStatus) PR_SetThreadPrivate(PRUintn index, void *priv) { void *data = self->privateData[index]; self->privateData[index] = NULL; - _PR_UNLOCK_TPINDEX(); - (*_pr_tpd_destructors[index])(data); - _PR_LOCK_TPINDEX(); + (*_pr_tpd_destructors[index])(data); } /* @@ -232,10 +185,9 @@ PR_IMPLEMENT(PRStatus) PR_SetThreadPrivate(PRUintn index, void *priv) rv = PR_FAILURE; } else self->privateData[index] = priv; - _PR_UNLOCK_TPINDEX(); - } + } - return rv; + return rv; } /* @@ -247,8 +199,9 @@ PR_IMPLEMENT(PRStatus) PR_SetThreadPrivate(PRUintn index, void *priv) ** */ -PR_IMPLEMENT(void*) PR_GetThreadPrivate(uintn index) +PR_IMPLEMENT(void*) PR_GetThreadPrivate(PRUintn his) { + PRInt32 index = (PRInt32)his; PRThread *self = PR_GetCurrentThread(); void *tpd = ((NULL == self->privateData) || (index >= self->tpdLength)) ? NULL : self->privateData[index]; @@ -256,24 +209,57 @@ PR_IMPLEMENT(void*) PR_GetThreadPrivate(uintn index) return tpd; } +/* +** Destroy the thread's private data, if any exists. This is called at +** thread termination time only. There should be no threading issues +** since this is being called by the thread itself. +*/ +void _PR_DestroyThreadPrivate(PRThread* self) +{ + if (NULL != self->privateData) /* we have some */ + { + PRBool clean = PR_TRUE; + PRInt32 index, passes = 4; + PR_ASSERT(0 != self->tpdLength); + do + { + for (index = 0; index < self->tpdLength; ++index) + { + void *priv = self->privateData[index]; /* extract */ + if (NULL != priv) /* we have data at this index */ + { + if (NULL != _pr_tpd_destructors[index]) + { + self->privateData[index] = NULL; /* precondition */ + (*_pr_tpd_destructors[index])(priv); /* destroy */ + clean = PR_FALSE; /* unknown side effects */ + } + } + } + } while ((passes-- > 0) && !clean); /* limit # of passes */ + PR_DELETE(self->privateData); /* that's just this thread's vector */ + } +} /* _PR_DestroyThreadPrivate */ + +#if 0 PR_IMPLEMENT(PRStatus) PR_SetThreadExit(PRUintn index, PRThreadExit func, void *arg) { _PRPerThreadExit *pte; PRThread *thread = _PR_MD_CURRENT_THREAD(); if (index >= thread->numExits) { - if (thread->ptes) { - thread->ptes = (_PRPerThreadExit*) - PR_REALLOC(thread->ptes, (index+1) * sizeof(_PRPerThreadExit)); - } else { - thread->ptes = (_PRPerThreadExit*) - PR_CALLOC(index+1 * sizeof(_PRPerThreadExit)); - } - if (!thread->ptes) { - PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); - return PR_FAILURE; - } - thread->numExits = index + 1; + if (thread->ptes) { + thread->ptes = (_PRPerThreadExit*) + PR_REALLOC(thread->ptes, (index+1) * sizeof(_PRPerThreadExit)); + } else { + thread->ptes = (_PRPerThreadExit*) + PR_CALLOC(index+1 * sizeof(_PRPerThreadExit)); + } + if (!thread->ptes) { + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + return PR_FAILURE; + } + thread->numExits = index + 1; } pte = &thread->ptes[index]; pte->func = func; @@ -287,10 +273,12 @@ PR_IMPLEMENT(PRThreadExit) PR_GetThreadExit(PRUintn index, void **argp) PRThread *thread = _PR_MD_CURRENT_THREAD(); if (index >= thread->numExits) { - if (argp) *argp = 0; - return 0; + if (argp) *argp = 0; + return 0; } pte = &thread->ptes[index]; if (argp) *argp = pte->arg; return pte->func; } + +#endif diff --git a/pr/tests/Makefile b/pr/tests/Makefile index 9db675f9..d1fc8afd 100644 --- a/pr/tests/Makefile +++ b/pr/tests/Makefile @@ -37,6 +37,7 @@ OS_CFLAGS = $(OS_EXE_CFLAGS) endif CSRCS = \ + acceptread.c \ accept.c \ alarm.c \ atomic.c \ @@ -52,11 +53,14 @@ CSRCS = \ dtoa.c \ exit.c \ fileio.c \ + foreign.c \ forktest.c \ fsync.c \ getproto.c \ i2l.c \ + initclk.c \ inrval.c \ + instrumt.c \ intrupt.c \ io_timeout.c \ ipv6.c \ @@ -86,9 +90,11 @@ CSRCS = \ poll_er.c \ poll_nm.c \ poll_to.c \ + pollable.c \ prftest1.c \ prftest2.c \ priotest.c \ + provider.c \ ranfile.c \ sel_spd.c \ selct_er.c \ @@ -106,6 +112,7 @@ CSRCS = \ sprintf.c \ sproc_ch.c \ sproc_p.c \ + stack.c \ stdio.c \ strod.c \ suspend.c \ @@ -120,6 +127,7 @@ CSRCS = \ tmoacc.c \ tmocon.c \ tpd.c \ + version.c \ udpsrv.c \ writev.c \ xnotify.c \ @@ -133,7 +141,7 @@ endif PROGS = $(addprefix $(OBJDIR)/, $(CSRCS:.c=$(PROG_SUFFIX))) -TARGETS = $(PROGS) $(OBJS) +TARGETS = $(PROGS) INCLUDES = -I$(DIST)/include/obsolete -I$(DIST)/include/private -I$(DIST)/include @@ -165,96 +173,112 @@ PWD = $(shell pwd) endif ifeq ($(OS_ARCH), IRIX) -LDOPTS += -rpath $(PWD)/$(DIST)/lib -rdata_shared - + ifeq ($(USE_CPLUS), 1) + CC = CC + endif + LDOPTS += -rpath $(PWD)/$(DIST)/lib -rdata_shared # For 6.x machines, include this flag -ifeq ($(basename $(OS_RELEASE)),6) -ifeq ($(USE_N32),1) -LDOPTS += -n32 -else -LDOPTS += -32 -endif -endif + ifeq ($(basename $(OS_RELEASE)),6) + ifeq ($(USE_N32),1) + LDOPTS += -n32 + else + LDOPTS += -32 + endif + ifeq ($(USE_PTHREADS), 1) + ifeq ($(OS_RELEASE), 6.2) + LDOPTS += -Wl,-woff,85 + endif + endif + endif endif ifeq ($(OS_ARCH), OSF1) + ifeq ($(USE_CPLUS), 1) + CC = cxx + endif # I haven't figured out how to pass -rpath to cc on OSF1 V3.2, so # we do static linking. -ifeq ($(OS_RELEASE), V3.2) - LIBPR = $(DIST)/lib/libnspr$(MOD_VERSION).a - LIBPLC = $(DIST)/lib/libplc$(MOD_VERSION).a - EXTRA_LIBS = -lc_r -else - LDOPTS += -rpath $(PWD)/$(DIST)/lib -endif + ifeq ($(OS_RELEASE), V3.2) + LIBPR = $(DIST)/lib/libnspr$(MOD_VERSION).a + LIBPLC = $(DIST)/lib/libplc$(MOD_VERSION).a + EXTRA_LIBS = -lc_r + else + LDOPTS += -rpath $(PWD)/$(DIST)/lib + endif endif ifeq ($(OS_ARCH), HP-UX) -LDOPTS += -Wl,+s,+b,$(PWD)/$(DIST)/lib + LDOPTS += -z -Wl,+s,+b,$(PWD)/$(DIST)/lib + ifeq ($(USE_64),1) + LDOPTS += -L/usr/lib/pa20_64 -lpthread +DD64 + endif endif # AIX ifeq ($(OS_ARCH),AIX) -ifeq ($(CLASSIC_NSPR),1) -LDOPTS += -blibpath:.:$(PWD)/$(DIST)/lib:/usr/lpp/xlC/lib:/usr/lib:/lib -else -LDOPTS += -blibpath:.:$(PWD)/$(DIST)/lib:/usr/lib/threads:/usr/lpp/xlC/lib:/usr/lib:/lib -endif -ifeq ($(OS_ARCH)$(OS_RELEASE),AIX4.1) -LIBPR = -lnspr$(MOD_VERSION)_shr -LIBPLC = -lplc$(MOD_VERSION)_shr -else -LDOPTS += -brtl -EXTRA_LIBS = -ldl -endif + ifeq ($(CLASSIC_NSPR),1) + LDOPTS += -blibpath:.:$(PWD)/$(DIST)/lib:/usr/lpp/xlC/lib:/usr/lib:/lib + else + LDOPTS += -blibpath:.:$(PWD)/$(DIST)/lib:/usr/lib/threads:/usr/lpp/xlC/lib:/usr/lib:/lib + endif + ifeq ($(OS_ARCH)$(OS_RELEASE),AIX4.1) + LIBPR = -lnspr$(MOD_VERSION)_shr + LIBPLC = -lplc$(MOD_VERSION)_shr + else + LDOPTS += -brtl + EXTRA_LIBS = -ldl + endif endif # Solaris ifeq ($(OS_ARCH), SunOS) -ifneq ($(OS_RELEASE), 4.1.3_U1) -ifdef NS_USE_GCC -LDOPTS += -Xlinker -R -Xlinker $(PWD)/$(DIST)/lib -else -LDOPTS += -R $(PWD)/$(DIST)/lib -endif -endif - -ifneq ($(LOCAL_THREADS_ONLY),1) + ifneq ($(OS_RELEASE), 4.1.3_U1) + ifdef NS_USE_GCC + LDOPTS += -Xlinker -R -Xlinker $(PWD)/$(DIST)/lib + else + ifeq ($(USE_CPLUS), 1) + CC = CC + endif + LDOPTS += -R $(PWD)/$(DIST)/lib + endif + endif + + ifneq ($(LOCAL_THREADS_ONLY),1) # SunOS 5.4 and 5.5 need to link with -lthread or -lpthread, # even though we already linked with these system libraries # when we built libnspr.so. -ifeq ($(OS_RELEASE), 5.4) -EXTRA_LIBS = -lthread -endif - -ifeq ($(OS_RELEASE), 5.5) -ifdef USE_PTHREADS -EXTRA_LIBS = -lpthread -else -EXTRA_LIBS = -lthread -endif -endif -endif # LOCAL_THREADS_ONLY + ifeq ($(OS_RELEASE), 5.4) + EXTRA_LIBS = -lthread + endif + + ifeq ($(OS_RELEASE), 5.5) + ifdef USE_PTHREADS + EXTRA_LIBS = -lpthread + else + EXTRA_LIBS = -lthread + endif + endif + endif # LOCAL_THREADS_ONLY endif # SunOS ifeq ($(OS_ARCH), NEC) -EXTRA_LIBS = $(OS_LIBS) + EXTRA_LIBS = $(OS_LIBS) # This hardcodes in the executable programs the directory to find # libnspr.so etc. at program startup. Equivalent to the -R or -rpath # option for ld on other platforms. -export LD_RUN_PATH = $(PWD)/$(DIST)/lib + export LD_RUN_PATH = $(PWD)/$(DIST)/lib endif ifeq ($(OS_ARCH), NCR) # NCR needs to link against -lsocket -lnsl -ldl (and -lc, which is # linked implicitly by $(CC)). Note that we did not link with these # system libraries when we built libnspr.so. -EXTRA_LIBS = -lsocket -lnsl -ldl + EXTRA_LIBS = -lsocket -lnsl -ldl # This hardcodes in the executable programs the directory to find # libnspr.so etc. at program startup. Equivalent to the -R or -rpath # option for ld on other platforms. -export LD_RUN_PATH = $(PWD)/$(DIST)/lib + export LD_RUN_PATH = $(PWD)/$(DIST)/lib endif ifeq ($(OS_ARCH), NEWS-OS) @@ -262,20 +286,20 @@ ifeq ($(OS_ARCH), NEWS-OS) # libnspr.so etc. at program startup. Equivalent to the -R or -rpath # option for ld on other platforms. #export LD_RUN_PATH = $(PWD)/$(DIST)/lib - LIBPR = $(DIST)/lib/libnspr$(MOD_VERSION).a - LIBPLC = $(DIST)/lib/libplc$(MOD_VERSION).a - EXTRA_LIBS = -lsocket -lnsl -lgen -lresolv + LIBPR = $(DIST)/lib/libnspr$(MOD_VERSION).a + LIBPLC = $(DIST)/lib/libplc$(MOD_VERSION).a + EXTRA_LIBS = -lsocket -lnsl -lgen -lresolv endif ifeq ($(OS_ARCH), Linux) -ifeq ($(OS_RELEASE), 1.2) -EXTRA_LIBS = -ldl -else -LDOPTS += -Xlinker -rpath $(PWD)/$(DIST)/lib -ifeq ($(USE_PTHREADS),1) -EXTRA_LIBS = -lpthread -endif -endif + ifeq ($(OS_RELEASE), 1.2) + EXTRA_LIBS = -ldl + else + LDOPTS += -Xlinker -rpath $(PWD)/$(DIST)/lib + ifeq ($(USE_PTHREADS),1) + EXTRA_LIBS = -lpthread + endif + endif endif ifeq ($(OS_ARCH), SCOOS) @@ -304,12 +328,29 @@ ifeq ($(OS_ARCH),FreeBSD) ifeq ($(USE_PTHREADS),1) EXTRA_LIBS = -lc_r endif +LDOPTS += -Xlinker -R $(PWD)/$(DIST)/lib endif ifeq ($(OS_ARCH),BSD_OS) EXTRA_LIBS = -ldl endif +ifeq ($(USE_PTHREADS),1) +ifeq ($(OS_ARCH),AIX) +LIBPTHREAD = -lpthreads +else + ifeq ($(OS_ARCH),FreeBSD) + LIBPTHREAD = -lc_r + else + ifeq ($(OS_ARCH)$(basename $(OS_RELEASE)),HP-UXB.10) + LIBPTHREAD = -ldce + else + LIBPTHREAD = -lpthread + endif + endif +endif +endif + ##################################################### # # The rules @@ -352,15 +393,7 @@ else ifeq ($(USE_PTHREADS), 1) $(OBJDIR)/attach: $(OBJDIR)/attach.$(OBJ_SUFFIX) @$(MAKE_OBJDIR) -ifeq ($(OS_ARCH), AIX) - $(CC) $< $(LDOPTS) $(LIBPLC) $(LIBPR) -lpthreads -o $@ -else -ifeq ($(OS_ARCH),FreeBSD) - $(CC) $< $(LDOPTS) $(LIBPLC) $(LIBPR) -lc_r -o $@ -else - $(CC) $< $(LDOPTS) $(LIBPLC) $(LIBPR) -lpthread -o $@ -endif -endif + $(CC) $< $(LDOPTS) $(LIBPLC) $(LIBPR) $(LIBPTHREAD) -o $@ endif @@ -400,6 +433,13 @@ install:: export clean:: rm -f $(TARGETS) +ifeq ($(USE_PTHREADS), 1) +$(OBJDIR)/foreign: $(OBJDIR)/foreign.o + $(CC) $(XCFLAGS) $< $(LDOPTS) $(LIBPLC) $(LIBPR) $(EXTRA_LIBS) $(LIBPTHREAD) -o $@ +$(OBJDIR)/provider: $(OBJDIR)/provider.o + $(CC) $(XCFLAGS) $< $(LDOPTS) $(LIBPLC) $(LIBPR) $(EXTRA_LIBS) $(LIBPTHREAD) -o $@ +endif + # # Run the test programs with no arguments # diff --git a/pr/tests/accept.c b/pr/tests/accept.c index 79ab811f..5318de74 100644 --- a/pr/tests/accept.c +++ b/pr/tests/accept.c @@ -48,12 +48,6 @@ #include "plgetopt.h" #include "plerror.h" -#ifdef XP_MAC -#include "prlog.h" -#define printf PR_LogPrint -extern void SetupMacPrintfLog(char *logFile); -#endif - #define BASE_PORT 8001 #define CLIENT_DATA 128 @@ -76,6 +70,7 @@ extern void SetupMacPrintfLog(char *logFile); PRIntervalTime timeoutTime; static PRInt32 count = 1; +static PRFileDesc *output; static PRNetAddr serverAddr; static PRThreadScope thread_scope = PR_LOCAL_THREAD; @@ -86,13 +81,8 @@ void Test_Assert(const char *msg, const char *file, PRIntn line) { failed_already=1; if (debug_mode) { -#if defined(WIN16) - printf( "@%s:%d ", file, line); - printf(msg); -#else - PR_fprintf(PR_STDERR, "@%s:%d ", file, line); - PL_FPrintError(PR_STDERR, msg); -#endif + PR_fprintf(output, "@%s:%d ", file, line); + PR_fprintf(output, msg); } } /* Test_Assert */ @@ -106,7 +96,7 @@ void timeout_callback(void *magic) { TEST_ASSERT(magic == (void *)CALLBACK_MAGIC); if (debug_mode) - printf("timeout callback called okay\n"); + PR_fprintf(output, "timeout callback called okay\n"); } #endif @@ -131,7 +121,7 @@ ClientThread(void *_action) if (!debug_mode) failed_already=1; else - printf("client: unable to create socket\n"); + PR_fprintf(output, "client: unable to create socket\n"); return; } @@ -142,10 +132,9 @@ ClientThread(void *_action) if (!debug_mode) failed_already=1; else - printf( + PR_fprintf(output, "client: unable to connect to server (%ld, %ld, %ld, %ld)\n", - iterations, rv, PR_GetError(), - PR_GetOSError()); + iterations, rv, PR_GetError(), PR_GetOSError()); goto ErrorExit; } @@ -155,25 +144,24 @@ ClientThread(void *_action) if (!debug_mode) failed_already=1; else - printf("client: unable to send to server (%d, %ld, %ld)\n", - CLIENT_DATA, rv, - PR_GetError()); + PR_fprintf(output, + "client: unable to send to server (%d, %ld, %ld)\n", + CLIENT_DATA, rv, PR_GetError()); goto ErrorExit; } } else { - PR_Sleep(PR_SecondsToInterval(TIMEOUTSECS+ - 1)); + PR_Sleep(PR_SecondsToInterval(TIMEOUTSECS + 1)); } } else { - PR_Sleep(PR_SecondsToInterval(TIMEOUTSECS+ - 1)); + PR_Sleep(PR_SecondsToInterval(TIMEOUTSECS + 1)); } if (debug_mode) - printf("."); + PR_fprintf(output, "."); PR_Close(sock); + sock = NULL; } if (debug_mode) - printf("\n"); + PR_fprintf(output, "\n"); ErrorExit: if (sock != NULL) @@ -203,7 +191,7 @@ RunTest(PRInt32 acceptType, PRInt32 clientAction) if (!listenSock) { failed_already=1; if (debug_mode) - printf("unable to create listen socket\n"); + PR_fprintf(output, "unable to create listen socket\n"); return; } listenAddr.inet.family = PR_AF_INET; @@ -213,7 +201,7 @@ RunTest(PRInt32 acceptType, PRInt32 clientAction) if (rv == PR_FAILURE) { failed_already=1; if (debug_mode) - printf("unable to bind\n"); + PR_fprintf(output, "unable to bind\n"); return; } @@ -221,7 +209,7 @@ RunTest(PRInt32 acceptType, PRInt32 clientAction) if (rv == PR_FAILURE) { failed_already=1; if (debug_mode) - printf("unable to listen\n"); + PR_fprintf(output, "unable to listen\n"); return; } @@ -232,7 +220,7 @@ RunTest(PRInt32 acceptType, PRInt32 clientAction) if (!clientThread) { failed_already=1; if (debug_mode) - printf("error creating client thread\n"); + PR_fprintf(output, "error creating client thread\n"); return; } @@ -288,8 +276,7 @@ RunTest(PRInt32 acceptType, PRInt32 clientAction) case CLIENT_TIMEOUT_ACCEPT: TEST_ASSERT(clientSock == 0); if (debug_mode) - printf("PR_GetError is %ld\n", - PR_GetError()); + PR_fprintf(output, "PR_GetError is %ld\n", PR_GetError()); TEST_ASSERT(PR_GetError() == PR_IO_TIMEOUT_ERROR); break; case CLIENT_NORMAL: @@ -342,8 +329,7 @@ RunTest(PRInt32 acceptType, PRInt32 clientAction) break; case CLIENT_TIMEOUT_SEND: if (debug_mode) - printf("clientSock = 0x%8.8lx\n", - clientSock); + PR_fprintf(output, "clientSock = 0x%8.8lx\n", clientSock); TEST_ASSERT(clientSock); TEST_ASSERT(status == -1); TEST_ASSERT(PR_GetError() == PR_IO_TIMEOUT_ERROR); @@ -431,7 +417,7 @@ static void Measure(void (*func)(void), const char *msg) d = (double)PR_IntervalToMicroseconds(stop - start); if (debug_mode) - printf("%40s: %6.2f usec\n", msg, d / count); + PR_fprintf(output, "%40s: %6.2f usec\n", msg, d / count); } @@ -467,6 +453,7 @@ int main(int argc, char **argv) PL_DestroyOptState(opt); PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0); + output = PR_STDERR; PR_STDIO_INIT(); #ifdef XP_MAC @@ -476,7 +463,7 @@ int main(int argc, char **argv) timeoutTime = PR_SecondsToInterval(TIMEOUTSECS); if (debug_mode) - printf("\nRun accept() sucessful connection tests\n"); + PR_fprintf(output, "\nRun accept() sucessful connection tests\n"); Measure(AcceptUpdatedTest, "PR_Accept()"); Measure(AcceptReadTest, "PR_AcceptRead()"); @@ -486,28 +473,19 @@ int main(int argc, char **argv) Measure(AcceptReadCallbackTest, "PR_NTFast_AcceptRead_WithTimeoutCallback()"); #endif if (debug_mode) - printf("\nRun accept() timeout in the accept tests\n"); + PR_fprintf(output, "\nRun accept() timeout in the accept tests\n"); #ifdef WINNT Measure(TimeoutReadReadCallbackTest, "PR_NTFast_AcceptRead_WithTimeoutCallback()"); #endif Measure(TimeoutReadUpdatedTest, "PR_Accept()"); if (debug_mode) - printf("\nRun accept() timeout in the read tests\n"); + PR_fprintf(output, "\nRun accept() timeout in the read tests\n"); Measure(TimeoutReadReadTest, "PR_AcceptRead()"); #ifdef WINNT Measure(TimeoutReadNotUpdatedTest, "PR_NTFast_Accept()"); Measure(TimeoutReadReadNotUpdatedTest, "PR_NTFast_AcceptRead()"); Measure(TimeoutReadReadCallbackTest, "PR_NTFast_AcceptRead_WithTimeoutCallback()"); #endif - if(failed_already) - { - printf("FAIL\n"); - return 1; - } - else - { - printf("PASS\n"); - return 0; - - } + PR_fprintf(output, "%s\n", (failed_already) ? "FAIL" : "PASS"); + return failed_already; } diff --git a/pr/tests/atomic.c b/pr/tests/atomic.c index d5e334d5..a2ba2044 100644 --- a/pr/tests/atomic.c +++ b/pr/tests/atomic.c @@ -22,7 +22,7 @@ PRIntn main(PRIntn argc, char **argv) { - PRInt32 rv, test, result = 0; + PRInt32 rv, oldval, test, result = 0; PRFileDesc *output = PR_GetSpecialFD(PR_StandardOutput); test = -2; @@ -42,6 +42,25 @@ PRIntn main(PRIntn argc, char **argv) output, "PR_AtomicIncrement(%d) == %d: %s\n", test, rv, (rv > 0) ? "PASSED" : "FAILED"); + oldval = test = -2; + rv = PR_AtomicAdd(&test,1); + result = result | ((rv == -1) ? 0 : 1); + PR_fprintf( + output, "PR_AtomicAdd(%d,%d) == %d: %s\n", + oldval, 1, rv, (rv == -1) ? "PASSED" : "FAILED"); + oldval = test; + rv = PR_AtomicAdd(&test, 4); + result = result | ((rv == 3) ? 0 : 1); + PR_fprintf( + output, "PR_AtomicAdd(%d,%d) == %d: %s\n", + oldval, 4, rv, (rv == 3) ? "PASSED" : "FAILED"); + oldval = test; + rv = PR_AtomicAdd(&test, -6); + result = result | ((rv == -3) ? 0 : 1); + PR_fprintf( + output, "PR_AtomicAdd(%d,%d) == %d: %s\n", + oldval, -6, rv, (rv == -3) ? "PASSED" : "FAILED"); + test = 2; rv = PR_AtomicDecrement(&test); result = result | ((rv > 0) ? 0 : 1); diff --git a/pr/tests/attach.c b/pr/tests/attach.c index 3fa38d49..79a5d3d8 100644 --- a/pr/tests/attach.c +++ b/pr/tests/attach.c @@ -66,7 +66,7 @@ #include <os2.h> #endif -#define DEFAULT_COUNT 10000 +#define DEFAULT_COUNT 1000 PRIntn failed_already=0; PRIntn debug_mode; @@ -81,21 +81,17 @@ AttachDetach(void) PRInt32 index; for (index=0;index<count; index++) { - me = PR_AttachThread(PR_USER_THREAD, PR_PRIORITY_NORMAL, NULL); if (!me) { - fprintf(stderr, "Error attaching thread %d: " - "nspr20 error code %d, os error code %d\n", - count, PR_GetError(), PR_GetOSError()); - failed_already = 1; - return; + fprintf(stderr, "Error attaching thread %d: PR_AttachThread failed\n", + count); + failed_already = 1; + return; } - PR_DetachThread(); - } } @@ -277,7 +273,7 @@ int main(int argc, char **argv) } rv = WaitForSingleObject(hThread, INFINITE); if (debug_mode)PR_ASSERT(rv != WAIT_FAILED); - else if (rv != WAIT_FAILED) { + else if (rv == WAIT_FAILED) { failed_already=1; goto exit_now; } @@ -296,6 +292,7 @@ int main(int argc, char **argv) else { if (debug_mode) printf ("thread creation succeeded \n"); + sleep(3); goto exit_now; } rv = waitpid(threadID, NULL, 0); diff --git a/pr/tests/bigfile.c b/pr/tests/bigfile.c index 9cb4e7fd..399da8cd 100644 --- a/pr/tests/bigfile.c +++ b/pr/tests/bigfile.c @@ -35,10 +35,10 @@ static void Verbose(Verbosity, const char*, const char*, PRIntn); #define VERBOSE(_l, _m) Verbose(_l, _m, __FILE__, __LINE__) -static PRIntn filesize = 1; static PRIntn test_result = 2; static PRFileDesc *output = NULL; static PRIntn verbose = v_silent; +static PRIntn filesize = DEFAULT_FILESIZE; static PRIntn Usage(void) { @@ -46,6 +46,7 @@ static PRIntn Usage(void) PR_fprintf(output, ">bigfile [-G] [-d] [-v[*v]] [-s <n>] <filename>\n"); PR_fprintf(output, "\td\tdebug mode (equivalent to -vvv)\t(false)\n"); PR_fprintf(output, "\tv\tAdditional levels of output\t(none)\n"); + PR_fprintf(output, "\tk\tKeep data file after exit\t(false)\n"); PR_fprintf(output, "\ts <n>\tFile size in megabytes\t\t(1 megabyte)\n"); PR_fprintf(output, "\t<filename>\tName of test file\t(none)\n"); return 2; /* nothing happened */ @@ -64,6 +65,7 @@ static PRStatus DeleteIfFound(const char *filename) } else if (PR_FILE_NOT_FOUND_ERROR != PR_GetError()) VERBOSE(v_shout, "Cannot access big file"); + else rv = PR_SUCCESS; return rv; } /* DeleteIfFound */ @@ -87,20 +89,43 @@ static void Verbose( PR_fprintf(output, "[%s : %d]: %s\n", file, line, msg); } /* Verbose */ +static void PrintInfo(PRFileInfo64 *info, const char *filename) +{ + PRExplodedTime tm; + char ctime[40], mtime[40]; + static const char *types[] = {"FILE", "DIRECTORY", "OTHER"}; + PR_fprintf( + output, "[%s : %d]: File info for %s\n", + __FILE__, __LINE__, filename); + PR_fprintf( + output, " type: %s, size: %llu bytes,\n", + types[info->type - 1], info->size); + + PR_ExplodeTime(info->creationTime, PR_GMTParameters, &tm); + (void)PR_FormatTime(ctime, sizeof(ctime), "%c GMT", &tm); + PR_ExplodeTime(info->modifyTime, PR_GMTParameters, &tm); + (void)PR_FormatTime(mtime, sizeof(mtime), "%c GMT", &tm); + + PR_fprintf( + output, " creation: %s,\n modify: %s\n", ctime, mtime); +} /* PrintInfo */ + PRIntn main(PRIntn argc, char **argv) { PRStatus rv; char *buffer; PLOptStatus os; PRInt32 loop, bytes; + PRFileInfo small_info; + PRFileInfo64 big_info; + PRBool keep = PR_FALSE; PRFileDesc *file = NULL; const char *filename = NULL; PRIntn count = DEFAULT_COUNT; - PRFileInfo64 *big_info = NULL; - PRInt64 big_answer, big_size, one_meg, zero_meg, big_fragment; - PRInt64 filesize64; + PRInt64 filesize64, big_answer, big_size, one_meg, zero_meg, big_fragment; + PRInt64 sevenFox = LL_INIT(0,0x7fffffff); - PLOptState *opt = PL_CreateOptState(argc, argv, "dvhs:"); + PLOptState *opt = PL_CreateOptState(argc, argv, "dtvhs:"); output = PR_GetSpecialFD(PR_StandardError); PR_STDIO_INIT(); @@ -116,6 +141,9 @@ PRIntn main(PRIntn argc, char **argv) case 'd': /* debug mode */ verbose = v_shout; break; + case 'k': /* keep file */ + keep = PR_TRUE; + break; case 'v': /* verbosity */ if (v_shout > verbose) verbose += 1; break; @@ -132,9 +160,13 @@ PRIntn main(PRIntn argc, char **argv) } PL_DestroyOptState(opt); - if (NULL == filename) return Usage(); if (0 == count) count = DEFAULT_COUNT; if (0 == filesize) filesize = DEFAULT_FILESIZE; + if (NULL == filename) + { + if (DEFAULT_FILESIZE != filesize) return Usage(); + else filename = "/usr/tmp/bigfile.dat"; + } if (PR_FAILURE == DeleteIfFound(filename)) return 1; @@ -145,7 +177,7 @@ PRIntn main(PRIntn argc, char **argv) LL_I2L(filesize64, filesize); buffer = (char*)PR_MALLOC(BUFFER_SIZE); LL_I2L(big_fragment, BUFFER_SIZE); - LL_MUL(big_size, filesize64, one_meg); + LL_MUL(filesize64, filesize64, one_meg); for (loop = 0; loop < BUFFER_SIZE; ++loop) buffer[loop] = (char)loop; @@ -157,32 +189,45 @@ PRIntn main(PRIntn argc, char **argv) big_answer = file->methods->available64(file); if (!LL_IS_ZERO(big_answer)) return Error("empty available64()", filename); -#if 0 - VERBOSE(v_whisper, "Filling big file with data"); - while (LL_CMP(big_answer, <, big_size)) - { - bytes = file->methods->write(file, buffer, BUFFER_SIZE); - if (bytes != BUFFER_SIZE) return Error("write", filename); - LL_ADD(big_answer, big_answer, big_fragment); - } -#else - LL_SUB(big_size, big_size, one_meg); + LL_SUB(big_size, filesize64, one_meg); + VERBOSE(v_whisper, "Creating sparce big file by seeking to end"); big_answer = file->methods->seek64(file, big_size, PR_SEEK_SET); + if (!LL_EQ(big_answer, big_size)) return Error("seek", filename); + + VERBOSE(v_whisper, "Writing block at end of sparce file"); bytes = file->methods->write(file, buffer, BUFFER_SIZE); if (bytes != BUFFER_SIZE) return Error("write", filename); -#endif - VERBOSE(v_whisper, "Testing available space in filled file"); + VERBOSE(v_whisper, "Testing available space at end of sparce file"); big_answer = file->methods->available64(file); - if (LL_NE(big_answer, zero_meg)) return Error("eof available64()", filename); + if (!LL_IS_ZERO(big_answer)) return Error("eof available64()", filename); + + VERBOSE(v_whisper, "Getting big info on sparce big file"); + rv = file->methods->fileInfo64(file, &big_info); + if (PR_FAILURE == rv) return Error("fileInfo64()", filename); + if (v_shout <= verbose) PrintInfo(&big_info, filename); + + VERBOSE(v_whisper, "Getting small info on sparce big file"); + rv = file->methods->fileInfo(file, &small_info); + if (LL_CMP(sevenFox, <, filesize64) && (PR_SUCCESS == rv)) + { + VERBOSE(v_whisper, "Should have failed and didn't"); + return Error("fileInfo()", filename); + } + else if (LL_CMP(sevenFox, >, filesize64) && (PR_FAILURE == rv)) + { + VERBOSE(v_whisper, "Should have succeeded and didn't"); + return Error("fileInfo()", filename); + } VERBOSE(v_whisper, "Rewinding big file"); big_answer = file->methods->seek64(file, zero_meg, PR_SEEK_SET); - if (LL_NE(big_answer, zero_meg)) return Error("rewind seek64()", filename); + if (!LL_IS_ZERO(big_answer)) return Error("rewind seek64()", filename); VERBOSE(v_whisper, "Establishing available space in rewound file"); - big_size = file->methods->available64(file); - if (!LL_GE_ZERO(big_size)) return Error("bof available64()", filename); + big_answer = file->methods->available64(file); + if (LL_NE(filesize64, big_answer)) + return Error("bof available64()", filename); VERBOSE(v_whisper, "Closing big file"); rv = file->methods->close(file); @@ -190,47 +235,59 @@ PRIntn main(PRIntn argc, char **argv) VERBOSE(v_whisper, "Reopening big file"); file = PR_Open(filename, PR_RDWR, 0666); - if (NULL == file) return Error("bof seek64()", filename); + if (NULL == file) return Error("open failed", filename); VERBOSE(v_whisper, "Checking available data in reopened file"); big_answer = file->methods->available64(file); - if (LL_NE(big_size, big_answer)) return Error("reopened available64()", filename); + if (LL_NE(filesize64, big_answer)) + return Error("reopened available64()", filename); big_answer = zero_meg; - VERBOSE(v_whisper, "Rewriting big file data"); - while (LL_CMP(big_answer, <, big_size)) + VERBOSE(v_whisper, "Rewriting every byte of big file data"); + do { bytes = file->methods->write(file, buffer, BUFFER_SIZE); - if (bytes != BUFFER_SIZE) return Error("write", filename); + if (bytes != BUFFER_SIZE) + return Error("write", filename); LL_ADD(big_answer, big_answer, big_fragment); - } + } while (LL_CMP(big_answer, <, filesize64)); + + VERBOSE(v_whisper, "Checking position at eof"); + big_answer = file->methods->seek64(file, zero_meg, PR_SEEK_CUR); + if (LL_NE(big_answer, filesize64)) + return Error("file size error", filename); VERBOSE(v_whisper, "Testing available space at eof"); big_answer = file->methods->available64(file); - if (LL_NE(big_answer, zero_meg)) return Error("eof available64()", filename); + if (!LL_IS_ZERO(big_answer)) + return Error("eof available64()", filename); - VERBOSE(v_whisper, "Rewinding full file file"); + VERBOSE(v_whisper, "Rewinding full file"); big_answer = file->methods->seek64(file, zero_meg, PR_SEEK_SET); - if (LL_NE(big_answer, zero_meg)) return Error("bof seek64()", filename); + if (!LL_IS_ZERO(big_answer)) return Error("bof seek64()", filename); VERBOSE(v_whisper, "Testing available space in rewound file"); big_answer = file->methods->available64(file); - if (LL_NE(big_answer, big_size)) return Error("bof available64()", filename); + if (LL_NE(big_answer, filesize64)) return Error("bof available64()", filename); VERBOSE(v_whisper, "Seeking to end of big file"); - big_answer = file->methods->seek64(file, big_size, PR_SEEK_SET); - if (LL_NE(big_answer, big_size)) return Error("eof seek64()", filename); + big_answer = file->methods->seek64(file, filesize64, PR_SEEK_SET); + if (LL_NE(big_answer, filesize64)) return Error("eof seek64()", filename); - VERBOSE(v_whisper, "Getting info on big file"); - big_info = PR_NEWZAP(PRFileInfo64); - rv = file->methods->fileInfo64(file, big_info); + VERBOSE(v_whisper, "Getting info on big file while it's open"); + rv = file->methods->fileInfo64(file, &big_info); if (PR_FAILURE == rv) return Error("fileInfo64()", filename); - PR_DELETE(big_info); + if (v_shout <= verbose) PrintInfo(&big_info, filename); VERBOSE(v_whisper, "Closing big file"); rv = file->methods->close(file); if (PR_FAILURE == rv) return Error("close()", filename); + VERBOSE(v_whisper, "Getting info on big file after it's closed"); + rv = PR_GetFileInfo64(filename, &big_info); + if (PR_FAILURE == rv) return Error("fileInfo64()", filename); + if (v_shout <= verbose) PrintInfo(&big_info, filename); + VERBOSE(v_whisper, "Deleting big file"); rv = PR_Delete(filename); if (PR_FAILURE == rv) return Error("PR_Delete()", filename); diff --git a/pr/tests/cltsrv.c b/pr/tests/cltsrv.c index 346ff2f9..f3333be4 100644 --- a/pr/tests/cltsrv.c +++ b/pr/tests/cltsrv.c @@ -79,6 +79,8 @@ #define RECV_FLAGS 0 #define SEND_FLAGS 0 +#define DEFAULT_LOW 0 +#define DEFAULT_HIGH 0 #define BUFFER_SIZE 1024 #define DEFAULT_BACKLOG 5 #define DEFAULT_PORT 12848 @@ -204,22 +206,6 @@ static PRBool Aborted(PRStatus rv) PR_TRUE : PR_FALSE; } -static void Assert(const char *s, const char *file, PRIntn ln) -{ - PRIntn error = PR_GetError(), syserrno = PR_GetOSError(); - TEST_LOG( - cltsrv_log_file, TEST_LOG_ALWAYS, - ("Assertion failed(0x%lx): '%s' in %s[%d]\n", - PR_CurrentThread(), s, file, ln)); - TEST_LOG( - cltsrv_log_file, TEST_LOG_ALWAYS, - ("**Error information: Error = %d, OSError = %d\n", - error, syserrno)); - PR_LogFlush(); - - PR_Abort(); -} /* Assert */ - static void TimeOfDayMessage(const char *msg, PRThread* me) { char buffer[100]; @@ -229,7 +215,7 @@ static void TimeOfDayMessage(const char *msg, PRThread* me) TEST_LOG( cltsrv_log_file, TEST_LOG_ALWAYS, - ("%s(0x%lx): %s\n", msg, me, buffer)); + ("%s(0x%p): %s\n", msg, me, buffer)); } /* TimeOfDayMessage */ @@ -264,7 +250,7 @@ static void PR_CALLBACK Client(void *arg) (void)PR_NetAddrToString(&client->serverAddress, buffer, sizeof(buffer)); TEST_LOG(cltsrv_log_file, TEST_LOG_INFO, - ("\tClient(0x%lx): connecting to server at %s\n", me, buffer)); + ("\tClient(0x%p): connecting to server at %s\n", me, buffer)); fd = PR_Socket(domain, SOCK_STREAM, protocol); TEST_ASSERT(NULL != fd); @@ -273,7 +259,7 @@ static void PR_CALLBACK Client(void *arg) { TEST_LOG( cltsrv_log_file, TEST_LOG_ERROR, - ("\tClient(0x%lx): conection failed\n", me)); + ("\tClient(0x%p): conection failed\n", me)); goto aborted; } @@ -281,10 +267,10 @@ static void PR_CALLBACK Client(void *arg) descriptor->size = PR_htonl(descbytes = rand() % clipping); PR_snprintf( descriptor->filename, sizeof(descriptor->filename), - "CS%lx%lx-%lx.dat", client->started, me, client->operations); + "CS%p%p-%p.dat", client->started, me, client->operations); TEST_LOG( cltsrv_log_file, TEST_LOG_VERBOSE, - ("\tClient(0x%lx): sending descriptor for %ld bytes\n", me, descbytes)); + ("\tClient(0x%p): sending descriptor for %u bytes\n", me, descbytes)); bytes = PR_Send( fd, descriptor, sizeof(*descriptor), SEND_FLAGS, timeout); if (sizeof(CSDescriptor_t) != bytes) @@ -294,7 +280,7 @@ static void PR_CALLBACK Client(void *arg) { TEST_LOG( cltsrv_log_file, TEST_LOG_ERROR, - ("\tClient(0x%lx): send descriptor timeout\n", me)); + ("\tClient(0x%p): send descriptor timeout\n", me)); goto retry; } } @@ -308,7 +294,7 @@ static void PR_CALLBACK Client(void *arg) filebytes = descbytes - netbytes; TEST_LOG( cltsrv_log_file, TEST_LOG_VERBOSE, - ("\tClient(0x%lx): sending %d bytes\n", me, filebytes)); + ("\tClient(0x%p): sending %d bytes\n", me, filebytes)); bytes = PR_Send(fd, buffer, filebytes, SEND_FLAGS, timeout); if (filebytes != bytes) { @@ -317,7 +303,7 @@ static void PR_CALLBACK Client(void *arg) { TEST_LOG( cltsrv_log_file, TEST_LOG_ERROR, - ("\tClient(0x%lx): send data timeout\n", me)); + ("\tClient(0x%p): send data timeout\n", me)); goto retry; } } @@ -332,7 +318,7 @@ static void PR_CALLBACK Client(void *arg) netbytes = descbytes - filebytes; TEST_LOG( cltsrv_log_file, TEST_LOG_VERBOSE, - ("\tClient(0x%lx): receiving %d bytes\n", me, netbytes)); + ("\tClient(0x%p): receiving %d bytes\n", me, netbytes)); bytes = PR_Recv(fd, buffer, netbytes, RECV_FLAGS, timeout); if (-1 == bytes) { @@ -340,17 +326,17 @@ static void PR_CALLBACK Client(void *arg) { TEST_LOG( cltsrv_log_file, TEST_LOG_ERROR, - ("\tClient(0x%lx): receive data aborted\n", me)); + ("\tClient(0x%p): receive data aborted\n", me)); goto aborted; } else if (PR_IO_TIMEOUT_ERROR == PR_GetError()) TEST_LOG( cltsrv_log_file, TEST_LOG_ERROR, - ("\tClient(0x%lx): receive data timeout\n", me)); + ("\tClient(0x%p): receive data timeout\n", me)); else TEST_LOG( cltsrv_log_file, TEST_LOG_ERROR, - ("\tClient(0x%lx): receive error (%ld, %ld)\n", + ("\tClient(0x%p): receive error (%d, %d)\n", me, PR_GetError(), PR_GetOSError())); goto retry; } @@ -358,7 +344,7 @@ static void PR_CALLBACK Client(void *arg) { TEST_LOG( cltsrv_log_file, TEST_LOG_ERROR, - ("\t\tClient(0x%lx): unexpected end of stream\n", + ("\t\tClient(0x%p): unexpected end of stream\n", PR_CurrentThread())); break; } @@ -372,7 +358,7 @@ retry: (void)PR_Close(fd); fd = NULL; TEST_LOG( cltsrv_log_file, TEST_LOG_INFO, - ("\tClient(0x%lx): disconnected from server\n", me)); + ("\tClient(0x%p): disconnected from server\n", me)); PR_Lock(client->ml); client->operations += 1; @@ -395,7 +381,7 @@ aborted: PR_DELETE(descriptor); TEST_LOG( cltsrv_log_file, TEST_LOG_ALWAYS, - ("\tClient(0x%lx): stopped after %lu operations and %lu bytes\n", + ("\tClient(0x%p): stopped after %u operations and %u bytes\n", PR_CurrentThread(), client->operations, client->bytesTransferred)); } /* Client */ @@ -412,7 +398,7 @@ static PRStatus ProcessRequest(PRFileDesc *fd, CSServer_t *server) TEST_LOG( cltsrv_log_file, TEST_LOG_VERBOSE, - ("\tProcessRequest(0x%lx): receiving desciptor\n", me)); + ("\tProcessRequest(0x%p): receiving desciptor\n", me)); bytes = PR_Recv( fd, descriptor, sizeof(*descriptor), RECV_FLAGS, timeout); if (-1 == bytes) @@ -423,7 +409,7 @@ static PRStatus ProcessRequest(PRFileDesc *fd, CSServer_t *server) { TEST_LOG( cltsrv_log_file, TEST_LOG_ERROR, - ("\tProcessRequest(0x%lx): receive timeout\n", me)); + ("\tProcessRequest(0x%p): receive timeout\n", me)); } goto exit; } @@ -432,7 +418,7 @@ static PRStatus ProcessRequest(PRFileDesc *fd, CSServer_t *server) rv = PR_FAILURE; TEST_LOG( cltsrv_log_file, TEST_LOG_ERROR, - ("\tProcessRequest(0x%lx): unexpected end of file\n", me)); + ("\tProcessRequest(0x%p): unexpected end of file\n", me)); goto exit; } descbytes = PR_ntohl(descriptor->size); @@ -440,7 +426,7 @@ static PRStatus ProcessRequest(PRFileDesc *fd, CSServer_t *server) TEST_LOG( cltsrv_log_file, TEST_LOG_VERBOSE, - ("\t\tProcessRequest(0x%lx): read descriptor {%ld, %s}\n", + ("\t\tProcessRequest(0x%p): read descriptor {%d, %s}\n", me, descbytes, descriptor->filename)); file = PR_Open( @@ -453,7 +439,7 @@ static PRStatus ProcessRequest(PRFileDesc *fd, CSServer_t *server) { TEST_LOG( cltsrv_log_file, TEST_LOG_ERROR, - ("\tProcessRequest(0x%lx): open file timeout\n", me)); + ("\tProcessRequest(0x%p): open file timeout\n", me)); goto aborted; } } @@ -467,7 +453,7 @@ static PRStatus ProcessRequest(PRFileDesc *fd, CSServer_t *server) netbytes = descbytes - filebytes; TEST_LOG( cltsrv_log_file, TEST_LOG_VERBOSE, - ("\tProcessRequest(0x%lx): receive %d bytes\n", me, netbytes)); + ("\tProcessRequest(0x%p): receive %d bytes\n", me, netbytes)); bytes = PR_Recv(fd, buffer, netbytes, RECV_FLAGS, timeout); if (-1 == bytes) { @@ -477,7 +463,7 @@ static PRStatus ProcessRequest(PRFileDesc *fd, CSServer_t *server) { TEST_LOG( cltsrv_log_file, TEST_LOG_ERROR, - ("\t\tProcessRequest(0x%lx): receive data timeout\n", me)); + ("\t\tProcessRequest(0x%p): receive data timeout\n", me)); goto aborted; } /* @@ -487,7 +473,7 @@ static PRStatus ProcessRequest(PRFileDesc *fd, CSServer_t *server) */ TEST_LOG( cltsrv_log_file, TEST_LOG_WARNING, - ("\t\tProcessRequest(0x%lx): unexpected error (%d, %d)\n", + ("\t\tProcessRequest(0x%p): unexpected error (%d, %d)\n", me, PR_GetError(), PR_GetOSError())); goto aborted; } @@ -495,7 +481,7 @@ static PRStatus ProcessRequest(PRFileDesc *fd, CSServer_t *server) { TEST_LOG( cltsrv_log_file, TEST_LOG_WARNING, - ("\t\tProcessRequest(0x%lx): unexpected end of stream\n", me)); + ("\t\tProcessRequest(0x%p): unexpected end of stream\n", me)); rv = PR_FAILURE; goto aborted; } @@ -505,7 +491,7 @@ static PRStatus ProcessRequest(PRFileDesc *fd, CSServer_t *server) MY_ASSERT(netbytes > 0); TEST_LOG( cltsrv_log_file, TEST_LOG_VERBOSE, - ("\tProcessRequest(0x%lx): write %d bytes to file\n", me, netbytes)); + ("\tProcessRequest(0x%p): write %d bytes to file\n", me, netbytes)); bytes = PR_Write(file, buffer, netbytes); if (netbytes != bytes) { @@ -515,7 +501,7 @@ static PRStatus ProcessRequest(PRFileDesc *fd, CSServer_t *server) { TEST_LOG( cltsrv_log_file, TEST_LOG_ERROR, - ("\t\tProcessRequest(0x%lx): write file timeout\n", me)); + ("\t\tProcessRequest(0x%p): write file timeout\n", me)); goto aborted; } } @@ -533,7 +519,7 @@ static PRStatus ProcessRequest(PRFileDesc *fd, CSServer_t *server) TEST_LOG( cltsrv_log_file, TEST_LOG_VERBOSE, - ("\t\tProcessRequest(0x%lx): opening %s\n", me, descriptor->filename)); + ("\t\tProcessRequest(0x%p): opening %s\n", me, descriptor->filename)); file = PR_Open(descriptor->filename, PR_RDONLY, 0); if (NULL == file) { @@ -543,13 +529,13 @@ static PRStatus ProcessRequest(PRFileDesc *fd, CSServer_t *server) { TEST_LOG( cltsrv_log_file, TEST_LOG_ERROR, - ("\t\tProcessRequest(0x%lx): open file timeout\n", + ("\t\tProcessRequest(0x%p): open file timeout\n", PR_CurrentThread())); goto aborted; } TEST_LOG( cltsrv_log_file, TEST_LOG_ERROR, - ("\t\tProcessRequest(0x%lx): other file open error (%u, %u)\n", + ("\t\tProcessRequest(0x%p): other file open error (%u, %u)\n", me, PR_GetError(), PR_GetOSError())); goto aborted; } @@ -563,7 +549,7 @@ static PRStatus ProcessRequest(PRFileDesc *fd, CSServer_t *server) filebytes = descbytes - netbytes; TEST_LOG( cltsrv_log_file, TEST_LOG_VERBOSE, - ("\tProcessRequest(0x%lx): read %d bytes from file\n", me, filebytes)); + ("\tProcessRequest(0x%p): read %d bytes from file\n", me, filebytes)); bytes = PR_Read(file, buffer, filebytes); if (filebytes != bytes) { @@ -572,11 +558,11 @@ static PRStatus ProcessRequest(PRFileDesc *fd, CSServer_t *server) if (PR_IO_TIMEOUT_ERROR == PR_GetError()) TEST_LOG( cltsrv_log_file, TEST_LOG_ERROR, - ("\t\tProcessRequest(0x%lx): read file timeout\n", me)); + ("\t\tProcessRequest(0x%p): read file timeout\n", me)); else TEST_LOG( cltsrv_log_file, TEST_LOG_ERROR, - ("\t\tProcessRequest(0x%lx): other file error (%d, %d)\n", + ("\t\tProcessRequest(0x%p): other file error (%d, %d)\n", me, PR_GetError(), PR_GetOSError())); goto aborted; } @@ -585,7 +571,7 @@ static PRStatus ProcessRequest(PRFileDesc *fd, CSServer_t *server) filebytes = bytes; TEST_LOG( cltsrv_log_file, TEST_LOG_VERBOSE, - ("\t\tProcessRequest(0x%lx): sending %d bytes\n", me, filebytes)); + ("\t\tProcessRequest(0x%p): sending %d bytes\n", me, filebytes)); bytes = PR_Send(fd, buffer, filebytes, SEND_FLAGS, timeout); if (filebytes != bytes) { @@ -595,7 +581,7 @@ static PRStatus ProcessRequest(PRFileDesc *fd, CSServer_t *server) { TEST_LOG( cltsrv_log_file, TEST_LOG_ERROR, - ("\t\tProcessRequest(0x%lx): send data timeout\n", me)); + ("\t\tProcessRequest(0x%p): send data timeout\n", me)); goto aborted; } break; @@ -622,7 +608,7 @@ aborted: exit: TEST_LOG( cltsrv_log_file, TEST_LOG_VERBOSE, - ("\t\tProcessRequest(0x%lx): Finished\n", me)); + ("\t\tProcessRequest(0x%p): Finished\n", me)); PR_DELETE(descriptor); @@ -648,7 +634,7 @@ static PRStatus CreateWorker(CSServer_t *server, CSPool_t *pool) } TEST_LOG(cltsrv_log_file, TEST_LOG_STATUS, - ("\tCreateWorker(0x%lx): create new worker (0x%lx)\n", + ("\tCreateWorker(0x%p): create new worker (0x%p)\n", PR_CurrentThread(), worker->thread)); return PR_SUCCESS; @@ -666,7 +652,7 @@ static void PR_CALLBACK Worker(void *arg) TEST_LOG( cltsrv_log_file, TEST_LOG_NOTICE, - ("\t\tWorker(0x%lx): started [%lu]\n", me, pool->workers + 1)); + ("\t\tWorker(0x%p): started [%u]\n", me, pool->workers + 1)); PR_Lock(server->ml); PR_APPEND_LINK(&worker->element, &server->list); @@ -678,14 +664,14 @@ static void PR_CALLBACK Worker(void *arg) { TEST_LOG( cltsrv_log_file, TEST_LOG_VERBOSE, - ("\t\tWorker(0x%lx): waiting for accept slot[%d]\n", + ("\t\tWorker(0x%p): waiting for accept slot[%d]\n", me, pool->accepting)); rv = PR_WaitCondVar(pool->acceptComplete, PR_INTERVAL_NO_TIMEOUT); if (Aborted(rv) || (cs_run != server->state)) { TEST_LOG( cltsrv_log_file, TEST_LOG_NOTICE, - ("\tWorker(0x%lx): has been %s\n", + ("\tWorker(0x%p): has been %s\n", me, (Aborted(rv) ? "interrupted" : "stopped"))); goto exit; } @@ -695,7 +681,7 @@ static void PR_CALLBACK Worker(void *arg) TEST_LOG( cltsrv_log_file, TEST_LOG_VERBOSE, - ("\t\tWorker(0x%lx): calling accept\n", me)); + ("\t\tWorker(0x%p): calling accept\n", me)); fd = PR_Accept(server->listener, &from, PR_INTERVAL_NO_TIMEOUT); PR_Lock(server->ml); @@ -736,7 +722,7 @@ static void PR_CALLBACK Worker(void *arg) if (PR_SUCCESS != rv) TEST_LOG( cltsrv_log_file, TEST_LOG_ERROR, - ("\t\tWorker(0x%lx): server process ended abnormally\n", me)); + ("\t\tWorker(0x%p): server process ended abnormally\n", me)); (void)PR_Close(fd); fd = NULL; PR_Lock(server->ml); @@ -756,7 +742,7 @@ exit: TEST_LOG( cltsrv_log_file, TEST_LOG_NOTICE, - ("\t\tWorker(0x%lx): exiting [%lu]\n", PR_CurrentThread(), pool->workers)); + ("\t\tWorker(0x%p): exiting [%u]\n", PR_CurrentThread(), pool->workers)); PR_Lock(server->ml); pool->workers -= 1; /* undefine our existance */ @@ -809,7 +795,7 @@ static void PR_CALLBACK Server(void *arg) */ TEST_LOG( cltsrv_log_file, TEST_LOG_VERBOSE, - ("\tServer(0x%lx): waiting for state change\n", me)); + ("\tServer(0x%p): waiting for state change\n", me)); PR_Lock(server->ml); while ((cs_run == server->state) && !Aborted(rv)) @@ -821,7 +807,7 @@ static void PR_CALLBACK Server(void *arg) TEST_LOG( cltsrv_log_file, TEST_LOG_INFO, - ("\tServer(0x%lx): shutting down workers\n", me)); + ("\tServer(0x%p): shutting down workers\n", me)); /* ** Get all the worker threads to exit. They know how to @@ -838,7 +824,7 @@ static void PR_CALLBACK Server(void *arg) CSWorker_t *worker = (CSWorker_t*)head; TEST_LOG( cltsrv_log_file, TEST_LOG_VERBOSE, - ("\tServer(0x%lx): interrupting worker(0x%lx)\n", me, worker)); + ("\tServer(0x%p): interrupting worker(0x%p)\n", me, worker)); rv = PR_Interrupt(worker->thread); TEST_ASSERT(PR_SUCCESS == rv); PR_REMOVE_AND_INIT_LINK(head); @@ -848,7 +834,7 @@ static void PR_CALLBACK Server(void *arg) { TEST_LOG( cltsrv_log_file, TEST_LOG_NOTICE, - ("\tServer(0x%lx): waiting for %lu workers to exit\n", + ("\tServer(0x%p): waiting for %u workers to exit\n", me, server->pool.workers)); (void)PR_WaitCondVar(server->pool.exiting, PR_INTERVAL_NO_TIMEOUT); } @@ -859,7 +845,7 @@ static void PR_CALLBACK Server(void *arg) TEST_LOG( cltsrv_log_file, TEST_LOG_ALWAYS, - ("\tServer(0x%lx): stopped after %lu operations and %lu bytes\n", + ("\tServer(0x%p): stopped after %u operations and %u bytes\n", me, server->operations, server->bytesTransferred)); if (NULL != server->listener) PR_Close(server->listener); @@ -867,26 +853,15 @@ static void PR_CALLBACK Server(void *arg) } /* Server */ -#if defined(DEBUG) && defined(_PR_PTHREADS) -static void PrintPthreadStats(void) -{ - PT_FPrintStats(debug_out, "\nPThread Statistics\n"); -} /* PrintPthreadStats */ -#endif /* defined(DEBUG) && defined(_PR_PTHREADS) */ - static void WaitForCompletion(PRIntn execution) { -#if defined(DEBUG) && defined(_PR_PTHREADS) while (execution > 0) { PRIntn dally = (execution > 30) ? 30 : execution; PR_Sleep(PR_SecondsToInterval(dally)); - if (pthread_stats) PrintPthreadStats(); + if (pthread_stats) PT_FPrintStats(debug_out, "\nPThread Statistics\n"); execution -= dally; } -#else - PR_Sleep(PR_SecondsToInterval(execution)); -#endif /* defined(DEBUG) && defined(_PR_PTHREADS) */ } /* WaitForCompletion */ static void Help(void) @@ -895,6 +870,8 @@ static void Help(void) PR_fprintf(debug_out, "\t-a <n> threads allowed in accept (5)\n"); PR_fprintf(debug_out, "\t-b <n> backlock for listen (5)\n"); PR_fprintf(debug_out, "\t-c <threads> number of clients to create (1)\n"); + PR_fprintf(debug_out, "\t-f <low> low water mark for fd caching (0)\n"); + PR_fprintf(debug_out, "\t-F <high> high water mark for fd caching (0)\n"); PR_fprintf(debug_out, "\t-w <threads> minimal number of server threads (1)\n"); PR_fprintf(debug_out, "\t-W <threads> maximum number of server threads (1)\n"); PR_fprintf(debug_out, "\t-e <seconds> duration of the test in seconds (10)\n"); @@ -932,12 +909,15 @@ PRIntn main(PRIntn argc, char** argv) PRUintn workersMin = DEFAULT_WORKERS_MIN; PRUintn workersMax = DEFAULT_WORKERS_MAX; PRIntn execution = DEFAULT_EXECUTION_TIME; + PRIntn low = DEFAULT_LOW, high = DEFAULT_HIGH; /* * -G use global threads * -a <n> threads allowed in accept * -b <n> backlock for listen * -c <threads> number of clients to create + * -f <low> low water mark for caching FDs + * -F <high> high water mark for caching FDs * -w <threads> minimal number of server threads * -W <threads> maximum number of server threads * -e <seconds> duration of the test in seconds @@ -946,7 +926,7 @@ PRIntn main(PRIntn argc, char** argv) */ PLOptStatus os; - PLOptState *opt = PL_CreateOptState(argc, argv, "GX6b:a:c:w:W:e:s:vdhp"); + PLOptState *opt = PL_CreateOptState(argc, argv, "GX6b:a:c:f:F:w:W:e:s:vdhp"); debug_out = PR_GetSpecialFD(PR_StandardError); @@ -976,6 +956,12 @@ PRIntn main(PRIntn argc, char** argv) case 'c': /* number of client threads */ clients = atoi(opt->value); break; + case 'f': /* low water fd cache */ + low = atoi(opt->value); + break; + case 'F': /* low water fd cache */ + high = atoi(opt->value); + break; case 'w': /* minimum server worker threads */ workersMin = atoi(opt->value); break; @@ -1026,12 +1012,15 @@ PRIntn main(PRIntn argc, char** argv) debug_mode = PR_TRUE; #endif + rv = PR_SetFDCacheSize(low, high); + PR_ASSERT(PR_SUCCESS == rv); + if (serverIsLocal) { /* Establish the server */ TEST_LOG( cltsrv_log_file, TEST_LOG_INFO, - ("main(0x%lx): starting server\n", PR_CurrentThread())); + ("main(0x%p): starting server\n", PR_CurrentThread())); server = PR_NEWZAP(CSServer_t); PR_INIT_CLIST(&server->list); @@ -1048,7 +1037,7 @@ PRIntn main(PRIntn argc, char** argv) TEST_LOG( cltsrv_log_file, TEST_LOG_NOTICE, - ("main(0x%lx): creating server thread\n", PR_CurrentThread())); + ("main(0x%p): creating server thread\n", PR_CurrentThread())); server->thread = PR_CreateThread( PR_USER_THREAD, Server, server, PR_PRIORITY_HIGH, @@ -1057,7 +1046,7 @@ PRIntn main(PRIntn argc, char** argv) TEST_LOG( cltsrv_log_file, TEST_LOG_VERBOSE, - ("main(0x%lx): waiting for server init\n", PR_CurrentThread())); + ("main(0x%p): waiting for server init\n", PR_CurrentThread())); PR_Lock(server->ml); while (server->state == cs_init) @@ -1066,7 +1055,7 @@ PRIntn main(PRIntn argc, char** argv) TEST_LOG( cltsrv_log_file, TEST_LOG_VERBOSE, - ("main(0x%lx): server init complete (port #%d)\n", + ("main(0x%p): server init complete (port #%d)\n", PR_CurrentThread(), server->port)); } @@ -1079,7 +1068,7 @@ PRIntn main(PRIntn argc, char** argv) TEST_LOG( cltsrv_log_file, TEST_LOG_VERBOSE, - ("main(0x%lx): creating %d client threads\n", + ("main(0x%p): creating %d client threads\n", PR_CurrentThread(), clients)); if (!serverIsLocal) @@ -1110,7 +1099,7 @@ PRIntn main(PRIntn argc, char** argv) client[index].stateChange = PR_NewCondVar(client[index].ml); TEST_LOG( cltsrv_log_file, TEST_LOG_INFO, - ("main(0x%lx): creating client threads\n", PR_CurrentThread())); + ("main(0x%p): creating client threads\n", PR_CurrentThread())); client[index].thread = PR_CreateThread( PR_USER_THREAD, Client, &client[index], PR_PRIORITY_NORMAL, thread_scope, PR_JOINABLE_THREAD, 0); @@ -1125,7 +1114,7 @@ PRIntn main(PRIntn argc, char** argv) /* Then just let them go at it for a bit */ TEST_LOG( cltsrv_log_file, TEST_LOG_ALWAYS, - ("main(0x%lx): waiting for execution interval (%d seconds)\n", + ("main(0x%p): waiting for execution interval (%d seconds)\n", PR_CurrentThread(), execution)); WaitForCompletion(execution); @@ -1137,7 +1126,7 @@ PRIntn main(PRIntn argc, char** argv) for (index = 0; index < clients; ++index) { TEST_LOG(cltsrv_log_file, TEST_LOG_STATUS, - ("main(0x%lx): notifying client(0x%lx) to stop\n", + ("main(0x%p): notifying client(0x%p) to stop\n", PR_CurrentThread(), client[index].thread)); PR_Lock(client[index].ml); @@ -1152,7 +1141,7 @@ PRIntn main(PRIntn argc, char** argv) PR_Unlock(client[index].ml); TEST_LOG(cltsrv_log_file, TEST_LOG_VERBOSE, - ("main(0x%lx): joining client(0x%lx)\n", + ("main(0x%p): joining client(0x%p)\n", PR_CurrentThread(), client[index].thread)); joinStatus = PR_JoinThread(client[index].thread); @@ -1168,7 +1157,7 @@ PRIntn main(PRIntn argc, char** argv) /* All clients joined - retrieve the server */ TEST_LOG( cltsrv_log_file, TEST_LOG_NOTICE, - ("main(0x%lx): notifying server(0x%lx) to stop\n", + ("main(0x%p): notifying server(0x%p) to stop\n", PR_CurrentThread(), server->thread)); PR_Lock(server->ml); @@ -1180,7 +1169,7 @@ PRIntn main(PRIntn argc, char** argv) TEST_LOG( cltsrv_log_file, TEST_LOG_NOTICE, - ("main(0x%lx): joining server(0x%lx)\n", + ("main(0x%p): joining server(0x%p)\n", PR_CurrentThread(), server->thread)); joinStatus = PR_JoinThread(server->thread); TEST_ASSERT(PR_SUCCESS == joinStatus); @@ -1194,13 +1183,12 @@ PRIntn main(PRIntn argc, char** argv) TEST_LOG( cltsrv_log_file, TEST_LOG_ALWAYS, - ("main(0x%lx): test complete\n", PR_CurrentThread())); + ("main(0x%p): test complete\n", PR_CurrentThread())); -#if defined(DEBUG) && defined(_PR_PTHREADS) - PrintPthreadStats(); -#endif /* defined(DEBUG) && defined(_PR_PTHREADS) */ + PT_FPrintStats(debug_out, "\nPThread Statistics\n"); TimeOfDayMessage("Test exiting at", PR_CurrentThread()); + PR_Cleanup(); return 0; } /* main */ diff --git a/pr/tests/concur.c b/pr/tests/concur.c index 88575dd5..fa2bfa1f 100644 --- a/pr/tests/concur.c +++ b/pr/tests/concur.c @@ -26,6 +26,8 @@ #include "prinrval.h" #include "prlock.h" #include "prprf.h" +#include "prmem.h" +#include "prlog.h" #include "plgetopt.h" @@ -37,7 +39,7 @@ #include <stdlib.h> -#define DEFAULT_RANGE 20 +#define DEFAULT_RANGE 10 #define DEFAULT_LOOPS 100 static PRThreadScope thread_scope = PR_LOCAL_THREAD; @@ -71,8 +73,11 @@ PRIntn PR_CALLBACK Concur(PRIntn argc, char **argv) { PRUintn cpus; PLOptStatus os; + PRThread **threads; PRBool debug = PR_FALSE; PRUintn range = DEFAULT_RANGE; + PRStatus rc; + PRUintn cnt; PRUintn loops = DEFAULT_LOOPS; PRIntervalTime hundredMills = PR_MillisecondsToInterval(100); PLOptState *opt = PL_CreateOptState(argc, argv, "Gdl:r:"); @@ -109,16 +114,17 @@ PRIntn PR_CALLBACK Concur(PRIntn argc, char **argv) PR_fprintf( PR_STDERR, "Testing with %d CPUs and %d interations\n", range, loops); + threads = (PRThread**) PR_CALLOC(sizeof(PRThread*) * range); while (--loops > 0) { - for (cpus = 1; cpus < range; ++cpus) + for (cpus = 1; cpus <= range; ++cpus) { PR_SetConcurrency(cpus); context.want = cpus; - (void)PR_CreateThread( + threads[cpus - 1] = PR_CreateThread( PR_USER_THREAD, Dull, &context, PR_PRIORITY_NORMAL, - thread_scope, PR_UNJOINABLE_THREAD, 0); + thread_scope, PR_JOINABLE_THREAD, 0); } PR_Sleep(hundredMills); @@ -132,6 +138,10 @@ PRIntn PR_CALLBACK Concur(PRIntn argc, char **argv) PR_NotifyCondVar(context.cv); PR_Unlock(context.ml); } + for(cnt = 0; cnt < range; cnt++) { + rc = PR_JoinThread(threads[cnt]); + PR_ASSERT(rc == PR_SUCCESS); + } } diff --git a/pr/tests/cvar2.c b/pr/tests/cvar2.c index f6b34268..f2508a7b 100644 --- a/pr/tests/cvar2.c +++ b/pr/tests/cvar2.c @@ -35,6 +35,7 @@ ***********************************************************************/ #include "nspr.h" +#include "plerror.h" #include "plgetopt.h" #include <stdio.h> @@ -167,8 +168,8 @@ CreateTestThread(threadinfo *info, scope, PR_JOINABLE_THREAD, 0); - if (!info->thread) - printf("error creating thread\n"); + if (!info->thread) + PL_PrintError("error creating thread\n"); } diff --git a/pr/tests/dceemu.c b/pr/tests/dceemu.c index 7935eae8..cb04cbd6 100644 --- a/pr/tests/dceemu.c +++ b/pr/tests/dceemu.c @@ -36,7 +36,7 @@ ***********************************************************************/ -#if defined(XP_UNIX) +#if defined(_PR_DCETHREADS) #include "prlog.h" #include "prinit.h" @@ -93,12 +93,12 @@ static PRIntn prmain(PRIntn argc, char **argv) } /* prmain */ -#endif /* #if defined(XP_UNIX) */ +#endif /* #if defined(_PR_DCETHREADS) */ int main(int argc, char **argv) { -#if defined(XP_UNIX) +#if defined(_PR_DCETHREADS) PR_Initialize(prmain, argc, argv, 0); if(failed_already) return 1; diff --git a/pr/tests/dll/Makefile b/pr/tests/dll/Makefile index 7afc7300..c2f72d71 100644 --- a/pr/tests/dll/Makefile +++ b/pr/tests/dll/Makefile @@ -58,7 +58,9 @@ else TARGETS = $(SHARED_LIBRARY) $(IMPORT_LIBRARY) endif else +ifdef MKSHLIB SHARED_LIBRARY = $(OBJDIR)/libmy.$(DLL_SUFFIX) +endif TARGETS = $(SHARED_LIBRARY) endif @@ -81,6 +83,7 @@ OS_DLL_OPTION = NOCASEEXACT OS_LIB_FLAGS = -irn endif +ifdef SHARED_LIBRARY export:: $(TARGETS) $(NSINSTALL) $(TARGETS) ../$(OBJDIR)/dll @@ -88,3 +91,4 @@ install:: export clean:: rm -rf $(TARGETS) +endif diff --git a/pr/tests/dlltest.c b/pr/tests/dlltest.c index bd8f7c49..bc817a05 100644 --- a/pr/tests/dlltest.c +++ b/pr/tests/dlltest.c @@ -84,15 +84,15 @@ int main(int argc, char** argv) fprintf( stderr, "PR_LoadLibrary failed (%d, %d, %s)\n", PR_GetError(), PR_GetOSError(), text); - if (!debug_mode) failed_already=1; + if (!debug_mode) failed_already=1; } getFcn = (GetFcnType) PR_FindSymbol(lib, "My_GetValue"); setFcn = (SetFcnType) PR_FindSymbol(lib, "My_SetValue"); (*setFcn)(888); value = (*getFcn)(); if (value != 888) { - fprintf(stderr, "Test 1 failed: set value to 888, but got %d\n", value); - if (!debug_mode) failed_already=1; + fprintf(stderr, "Test 1 failed: set value to 888, but got %d\n", value); + if (!debug_mode) failed_already=1; } if (debug_mode) printf("Test 1 passed\n"); @@ -103,26 +103,24 @@ int main(int argc, char** argv) */ getFcn = (GetFcnType) PR_FindSymbolAndLibrary("My_GetValue", &lib2); - if (lib != lib2) { - fprintf(stderr, "Test 2 failed: handles for the same library are not " - "equal: handle 1: %p, handle 2: %p\n", lib, lib2); - if (!debug_mode) failed_already=1; - + if (NULL == getFcn || lib != lib2) { + fprintf(stderr, "Test 2 failed: handles for the same library are not " + "equal: handle 1: %p, handle 2: %p\n", lib, lib2); + if (!debug_mode) failed_already=1; } setFcn = (SetFcnType) PR_FindSymbol(lib2, "My_SetValue"); value = (*getFcn)(); if (value != 888) { - fprintf(stderr, "Test 2 failed: value should be 888, but got %d\n", - value); - if (!debug_mode) failed_already=1; - + fprintf(stderr, "Test 2 failed: value should be 888, but got %d\n", + value); + if (!debug_mode) failed_already=1; } (*setFcn)(777); value = (*getFcn)(); if (value != 777) { - fprintf(stderr, "Test 2 failed: set value to 777, but got %d\n", value); - if (!debug_mode) failed_already=1; - goto exit_now; + fprintf(stderr, "Test 2 failed: set value to 777, but got %d\n", value); + if (!debug_mode) failed_already=1; + goto exit_now; } if (debug_mode) printf("Test 2 passed\n"); @@ -133,19 +131,19 @@ int main(int argc, char** argv) status = PR_UnloadLibrary(lib); if (PR_FAILURE == status) { - fprintf(stderr, "Test 3 failed: cannot unload library: (%d, %d)\n", - PR_GetError(), PR_GetOSError()); - if (!debug_mode) failed_already=1; - goto exit_now; + fprintf(stderr, "Test 3 failed: cannot unload library: (%d, %d)\n", + PR_GetError(), PR_GetOSError()); + if (!debug_mode) failed_already=1; + goto exit_now; } getFcn = (GetFcnType) PR_FindSymbol(lib2, "My_GetValue"); setFcn = (SetFcnType) PR_FindSymbol(lib2, "My_SetValue"); (*setFcn)(666); value = (*getFcn)(); if (value != 666) { - fprintf(stderr, "Test 3 failed: set value to 666, but got %d\n", value); - if (!debug_mode) failed_already=1; - goto exit_now; + fprintf(stderr, "Test 3 failed: set value to 666, but got %d\n", value); + if (!debug_mode) failed_already=1; + goto exit_now; } if (debug_mode) printf("Test 3 passed\n"); @@ -155,21 +153,21 @@ int main(int argc, char** argv) status = PR_UnloadLibrary(lib2); if (PR_FAILURE == status) { - fprintf(stderr, "Test 4 failed: cannot unload library: (%d, %d)\n", - PR_GetError(), PR_GetOSError()); - if (!debug_mode) failed_already=1; - goto exit_now; + fprintf(stderr, "Test 4 failed: cannot unload library: (%d, %d)\n", + PR_GetError(), PR_GetOSError()); + if (!debug_mode) failed_already=1; + goto exit_now; } - status = PR_UnloadLibrary(lib2); - if (PR_FAILURE != status || PR_GetError() != PR_INVALID_ARGUMENT_ERROR) { - fprintf(stderr, "Test 4 failed: how can an already unloaded library " - "be unloaded again?\n"); - if (!debug_mode) failed_already=1; - goto exit_now; + getFcn = (GetFcnType) PR_FindSymbolAndLibrary("My_GetValue", &lib2); + if (NULL != getFcn) { + fprintf(stderr, "Test 4 failed: how can we find a symbol " + "in an already unloaded library?\n"); + if (!debug_mode) failed_already=1; + goto exit_now; } if (debug_mode) { - printf("Test 4 passed\n"); - } + printf("Test 4 passed\n"); + } /* ** Test 5: LoadStaticLibrary() @@ -181,21 +179,24 @@ int main(int argc, char** argv) lib = PR_LoadStaticLibrary( "my.dll", slt ); if ( lib == NULL ) { - printf("dlltest: Test 5: LoadStatiLibrary() failed\n" ); + fprintf(stderr, "Test 5: LoadStatiLibrary() failed\n" ); goto exit_now; } - printf("Test 5 passed\n"); + if (debug_mode) + { + printf("Test 5 passed\n"); + } } - goto exit_now; + goto exit_now; exit_now: PR_Cleanup(); if (failed_already) { printf("FAILED\n"); - return 1; + return 1; } else { printf("PASSED\n"); - return 0; + return 0; } } diff --git a/pr/tests/foreign.c b/pr/tests/foreign.c new file mode 100644 index 00000000..dcf88250 --- /dev/null +++ b/pr/tests/foreign.c @@ -0,0 +1,345 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "NPL"); you may not use this file except in + * compliance with the NPL. You may obtain a copy of the NPL at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the NPL is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL + * for the specific language governing rights and limitations under the + * NPL. + * + * The Initial Developer of this code under the NPL is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All Rights + * Reserved. + */ + +/* +** File: foreign.c +** Description: Testing various functions w/ foreign threads +** +** We create a thread and get it to call exactly one runtime function. +** The thread is allowed to be created by some other environment that +** NSPR, but it does not announce itself to the runtime prior to calling +** in. +** +** The goal: try to survive. +** +*/ + +#include "prcvar.h" +#include "prenv.h" +#include "prerror.h" +#include "prinit.h" +#include "prinrval.h" +#include "prio.h" +#include "prlock.h" +#include "prlog.h" +#include "prmem.h" +#include "prthread.h" +#include "prtypes.h" +#include "prprf.h" +#include "plgetopt.h" + +#include <stdio.h> +#include <stdlib.h> + +static enum { + thread_nspr, thread_pthread, thread_sproc, thread_win32 +} thread_provider; + +typedef void (*StartFn)(void*); +typedef struct StartObject +{ + StartFn start; + void *arg; +} StartObject; + +static PRFileDesc *output; + +static int _debug_on = 0; + +#define DEFAULT_THREAD_COUNT 10 + +#define DPRINTF(arg) if (_debug_on) PR_fprintf arg + +#if defined(_PR_PTHREADS) && !defined(_PR_DCETHREADS) +#include "md/_pth.h" +#include <pthread.h> +static void *pthread_start(void *arg) +{ + StartFn start = ((StartObject*)arg)->start; + void *data = ((StartObject*)arg)->arg; + PR_Free(arg); + start(data); + return NULL; +} /* pthread_start */ +#endif /* defined(_PR_PTHREADS) && !defined(_PR_DCETHREADS) */ + +#if defined(IRIX) && !defined(_PR_PTHREADS) +#include <sys/types.h> +#include <sys/prctl.h> +static void sproc_start(void *arg, PRSize size) +{ + StartObject *so = (StartObject*)arg; + StartFn start = so->start; + void *data = so->arg; + PR_Free(so); + start(data); +} /* sproc_start */ +#endif /* defined(IRIX) && !defined(_PR_PTHREADS) */ + +#if defined(WIN32) +#include <process.h> /* for _beginthreadex() */ + +static PRUintn __stdcall windows_start(void *arg) +{ + StartObject *so = (StartObject*)arg; + StartFn start = so->start; + void *data = so->arg; + PR_Free(so); + start(data); + return 0; +} /* windows_start */ +#endif /* defined(WIN32) */ + +static PRStatus CreateThread(StartFn start, void *arg) +{ + PRStatus rv; + + switch (thread_provider) + { + case thread_nspr: + { + PRThread *thread = PR_CreateThread( + PR_USER_THREAD, start, arg, + PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD, + PR_UNJOINABLE_THREAD, 0); + rv = (NULL == thread) ? PR_FAILURE : PR_SUCCESS; + } + break; + case thread_pthread: +#if defined(_PR_PTHREADS) && !defined(_PR_DCETHREADS) + { + int rv; + pthread_t id; + pthread_attr_t tattr; + StartObject *start_object; + start_object = PR_NEW(StartObject); + PR_ASSERT(NULL != start_object); + start_object->start = start; + start_object->arg = arg; + + rv = PTHREAD_ATTR_INIT(&tattr); + PR_ASSERT(0 == rv); + + rv = pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED); + PR_ASSERT(0 == rv); + +#if !defined(LINUX) + rv = pthread_attr_setstacksize(&tattr, 64 * 1024); + PR_ASSERT(0 == rv); +#endif + + rv = PTHREAD_CREATE(&id, tattr, pthread_start, start_object); + (void)PTHREAD_ATTR_DESTROY(&tattr); + return (0 == rv) ? PR_SUCCESS : PR_FAILURE; + } +#else + PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); + rv = PR_FAILURE; + break; +#endif /* defined(_PR_PTHREADS) && !defined(_PR_DCETHREADS) */ + + case thread_sproc: +#if defined(IRIX) && !defined(_PR_PTHREADS) + { + PRInt32 pid; + StartObject *start_object; + start_object = PR_NEW(StartObject); + PR_ASSERT(NULL != start_object); + start_object->start = start; + start_object->arg = arg; + pid = sprocsp( + sproc_start, PR_SALL, start_object, NULL, 64 * 1024); + rv = (0 < pid) ? PR_SUCCESS : PR_FAILURE; + } +#else + PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); + rv = PR_FAILURE; +#endif /* defined(IRIX) && !defined(_PR_PTHREADS) */ + break; + case thread_win32: +#if defined(WIN32) + { + void *th; + PRUintn id; + StartObject *start_object; + start_object = PR_NEW(StartObject); + PR_ASSERT(NULL != start_object); + start_object->start = start; + start_object->arg = arg; + th = (void*)_beginthreadex( + NULL, /* LPSECURITY_ATTRIBUTES - pointer to thread security attributes */ + 0U, /* DWORD - initial thread stack size, in bytes */ + windows_start, /* LPTHREAD_START_ROUTINE - pointer to thread function */ + start_object, /* LPVOID - argument for new thread */ + 0U, /*DWORD dwCreationFlags - creation flags */ + &id /* LPDWORD - pointer to returned thread identifier */ ); + + rv = (NULL == th) ? PR_FAILURE : PR_SUCCESS; + } +#else + PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); + rv = PR_FAILURE; +#endif + break; + default: + PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); + rv = PR_FAILURE; + } + return rv; +} /* CreateThread */ + +static void PR_CALLBACK lazyEntry(void *arg) +{ + PR_ASSERT(NULL == arg); +} /* lazyEntry */ + + +static void OneShot(void *arg) +{ + PRUintn pdkey; + PRFileDesc *pair[2]; + PRIntn test = (PRIntn)arg; + + for (test = 0; test < 11; ++test) { + + switch (test) + { + case 0: + (void)PR_NewLock(); + DPRINTF((output,"Thread[0x%x] called PR_NewLock\n", + PR_GetCurrentThread())); + break; + + case 1: + (void)PR_SecondsToInterval(1); + DPRINTF((output,"Thread[0x%x] called PR_SecondsToInterval\n", + PR_GetCurrentThread())); + break; + + case 2: (void)PR_CreateThread( + PR_USER_THREAD, lazyEntry, NULL, PR_PRIORITY_NORMAL, + PR_LOCAL_THREAD, PR_UNJOINABLE_THREAD, 0); + DPRINTF((output,"Thread[0x%x] called PR_CreateThread\n", + PR_GetCurrentThread())); + break; + + case 3: + (void)PR_Open("/usr/tmp/", PR_RDONLY, 0); + DPRINTF((output,"Thread[0x%x] called PR_Open\n", + PR_GetCurrentThread())); + break; + + case 4: + (void)PR_NewUDPSocket(); + DPRINTF((output,"Thread[0x%x] called PR_NewUDPSocket\n", + PR_GetCurrentThread())); + break; + + case 5: + (void)PR_NewTCPSocket(); + DPRINTF((output,"Thread[0x%x] called PR_NewTCPSocket\n", + PR_GetCurrentThread())); + break; + + case 6: + (void)PR_OpenDir("/usr/tmp/"); + DPRINTF((output,"Thread[0x%x] called PR_OpenDir\n", + PR_GetCurrentThread())); + break; + + case 7: + (void)PR_NewThreadPrivateIndex(&pdkey, NULL); + DPRINTF((output,"Thread[0x%x] called PR_NewThreadPrivateIndex\n", + PR_GetCurrentThread())); + break; + + case 8: + (void)PR_GetEnv("PATH"); + DPRINTF((output,"Thread[0x%x] called PR_GetEnv\n", + PR_GetCurrentThread())); + break; + + case 9: + (void)PR_NewTCPSocketPair(pair); + DPRINTF((output,"Thread[0x%x] called PR_NewTCPSocketPair\n", + PR_GetCurrentThread())); + break; + + case 10: + PR_SetConcurrency(2); + DPRINTF((output,"Thread[0x%x] called PR_SetConcurrency\n", + PR_GetCurrentThread())); + break; + + default: + break; + } /* switch() */ + } +} /* OneShot */ + +PRIntn main(PRIntn argc, char **argv) +{ + PRStatus rv; + PRIntn test_number; + PRInt32 thread_cnt = DEFAULT_THREAD_COUNT; + PLOptStatus os; + PLOptState *opt = PL_CreateOptState(argc, argv, "dt:"); + +#if defined(WIN32) + thread_provider = thread_win32; +#elif defined(_PR_PTHREADS) + thread_provider = thread_pthread; +#elif defined(IRIX) + thread_provider = thread_sproc; +#else + thread_provider = thread_nspr; +#endif + + + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) + { + if (PL_OPT_BAD == os) continue; + switch (opt->option) + { + case 'd': /* debug mode */ + _debug_on = 1; + break; + case 't': /* thread count */ + thread_cnt = atoi(opt->value); + break; + default: + break; + } + } + PL_DestroyOptState(opt); + + PR_SetConcurrency(2); + + output = PR_GetSpecialFD(PR_StandardOutput); + + while (thread_cnt-- > 0) + { + rv = CreateThread(OneShot, (void*)thread_cnt); + PR_ASSERT(PR_SUCCESS == rv); + PR_Sleep(PR_MillisecondsToInterval(5)); + } + PR_Sleep(PR_SecondsToInterval(3)); + return (PR_SUCCESS == PR_Cleanup()) ? 0 : 1; +} /* main */ + +/* foreign.c */ diff --git a/pr/tests/forktest.c b/pr/tests/forktest.c index b52499d5..ecb09c5b 100644 --- a/pr/tests/forktest.c +++ b/pr/tests/forktest.c @@ -40,6 +40,7 @@ #include "plgetopt.h" #include "nspr.h" +#include <string.h> #include <stdio.h> #include <stdlib.h> @@ -259,6 +260,7 @@ char *argv[] ) { pid_t pid; + int rv; /* main test program */ @@ -275,9 +277,18 @@ char *argv[] printf("Fork succeeded. Parent process continues.\n"); DoIO(); - if (waitpid(pid, &childStatus, 0) != pid) { - fprintf(stderr, "waitpid failed: %d\n", errno); - failed_already = 1; + if ((rv = waitpid(pid, &childStatus, 0)) != pid) { +#if defined(IRIX) && !defined(_PR_PTHREADS) + /* + * nspr may handle SIGCLD signal + */ + if ((rv < 0) && (errno == ECHILD)) { + } else +#endif + { + fprintf(stderr, "waitpid failed: %d\n", errno); + failed_already = 1; + } } else if (!WIFEXITED(childStatus) || WEXITSTATUS(childStatus) != 0) { failed_already = 1; @@ -290,6 +301,10 @@ char *argv[] } return failed_already; } else { +#if defined(IRIX) && !defined(_PR_PTHREADS) + extern void _PR_IRIX_CHILD_PROCESS(void); + _PR_IRIX_CHILD_PROCESS(); +#endif printf("Fork succeeded. Child process continues.\n"); DoIO(); printf("Child process exits.\n"); diff --git a/pr/tests/initclk.c b/pr/tests/initclk.c new file mode 100644 index 00000000..a815997f --- /dev/null +++ b/pr/tests/initclk.c @@ -0,0 +1,87 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "NPL"); you may not use this file except in + * compliance with the NPL. You may obtain a copy of the NPL at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the NPL is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL + * for the specific language governing rights and limitations under the + * NPL. + * + * The Initial Developer of this code under the NPL is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All Rights + * Reserved. + */ + +/* + * This is a regression test for the bug that the interval timer + * is not initialized when _PR_CreateCPU calls PR_IntervalNow. + * The bug would make this test program finish prematurely, + * when the SHORT_TIMEOUT period expires. The correct behavior + * is for the test to finish when the LONG_TIMEOUT period expires. + */ + +#include "prlock.h" +#include "prcvar.h" +#include "prthread.h" +#include "prinrval.h" +#include "prlog.h" +#include <stdio.h> + +/* The timeouts, in milliseconds */ +#define SHORT_TIMEOUT 1000 +#define LONG_TIMEOUT 3000 + +PRLock *lock1, *lock2; +PRCondVar *cv1, *cv2; + +void ThreadFunc(void *arg) +{ + PR_Lock(lock1); + PR_WaitCondVar(cv1, PR_MillisecondsToInterval(SHORT_TIMEOUT)); + PR_Unlock(lock1); +} + +int main() +{ + PRThread *thread; + PRIntervalTime start, end; + PRUint32 elapsed_ms; + + lock1 = PR_NewLock(); + PR_ASSERT(NULL != lock1); + cv1 = PR_NewCondVar(lock1); + PR_ASSERT(NULL != cv1); + lock2 = PR_NewLock(); + PR_ASSERT(NULL != lock2); + cv2 = PR_NewCondVar(lock2); + PR_ASSERT(NULL != cv2); + start = PR_IntervalNow(); + thread = PR_CreateThread( + PR_USER_THREAD, + ThreadFunc, + NULL, + PR_PRIORITY_NORMAL, + PR_LOCAL_THREAD, + PR_JOINABLE_THREAD, + 0); + PR_ASSERT(NULL != thread); + PR_Lock(lock2); + PR_WaitCondVar(cv2, PR_MillisecondsToInterval(LONG_TIMEOUT)); + PR_Unlock(lock2); + PR_JoinThread(thread); + end = PR_IntervalNow(); + elapsed_ms = PR_IntervalToMilliseconds((PRIntervalTime)(end - start)); + /* Allow 100ms imprecision */ + if (elapsed_ms < LONG_TIMEOUT - 100 || elapsed_ms > LONG_TIMEOUT + 100) { + printf("Elapsed time should be %u ms but is %u ms\n", + LONG_TIMEOUT, elapsed_ms); + printf("FAIL\n"); + exit(1); + } + printf("PASS\n"); + return 0; +} diff --git a/pr/tests/inrval.c b/pr/tests/inrval.c index b963da48..ce1df9cc 100644 --- a/pr/tests/inrval.c +++ b/pr/tests/inrval.c @@ -40,6 +40,9 @@ #else #include "obsolete/pralarm.h" #endif + +#include "prio.h" +#include "prprf.h" #include "prlock.h" #include "prlong.h" #include "prcvar.h" @@ -51,14 +54,8 @@ #include <stdio.h> #include <stdlib.h> -#ifdef XP_MAC -#include "prlog.h" -#define printf PR_LogPrint -extern void SetupMacPrintfLog(char *logFile); -#endif - -PRIntn failed_already=0; -PRIntn debug_mode; +static PRIntn debug_mode; +static PRFileDesc *output; static void TestConversions(void) @@ -66,26 +63,62 @@ static void TestConversions(void) PRIntervalTime ticks = PR_TicksPerSecond(); if (debug_mode) { - printf("PR_TicksPerSecond: %ld\n\n", ticks); - printf("PR_SecondsToInterval(1): %ld\n", PR_SecondsToInterval(1)); - printf("PR_MillisecondsToInterval(1000): %ld\n", PR_MillisecondsToInterval(1000)); - printf("PR_MicrosecondsToInterval(1000000): %ld\n\n", PR_MicrosecondsToInterval(1000000)); + PR_fprintf(output, "PR_TicksPerSecond: %ld\n\n", ticks); + PR_fprintf(output, "PR_SecondsToInterval(1): %ld\n", PR_SecondsToInterval(1)); + PR_fprintf(output, "PR_MillisecondsToInterval(1000): %ld\n", PR_MillisecondsToInterval(1000)); + PR_fprintf(output, "PR_MicrosecondsToInterval(1000000): %ld\n\n", PR_MicrosecondsToInterval(1000000)); - printf("PR_SecondsToInterval(3): %ld\n", PR_SecondsToInterval(3)); - printf("PR_MillisecondsToInterval(3000): %ld\n", PR_MillisecondsToInterval(3000)); - printf("PR_MicrosecondsToInterval(3000000): %ld\n\n", PR_MicrosecondsToInterval(3000000)); + PR_fprintf(output, "PR_SecondsToInterval(3): %ld\n", PR_SecondsToInterval(3)); + PR_fprintf(output, "PR_MillisecondsToInterval(3000): %ld\n", PR_MillisecondsToInterval(3000)); + PR_fprintf(output, "PR_MicrosecondsToInterval(3000000): %ld\n\n", PR_MicrosecondsToInterval(3000000)); - printf("PR_IntervalToSeconds(%ld): %ld\n", ticks, PR_IntervalToSeconds(ticks)); - printf("PR_IntervalToMilliseconds(%ld): %ld\n", ticks, PR_IntervalToMilliseconds(ticks)); - printf("PR_IntervalToMicroseconds(%ld): %ld\n\n", ticks, PR_IntervalToMicroseconds(ticks)); + PR_fprintf(output, "PR_IntervalToSeconds(%ld): %ld\n", ticks, PR_IntervalToSeconds(ticks)); + PR_fprintf(output, "PR_IntervalToMilliseconds(%ld): %ld\n", ticks, PR_IntervalToMilliseconds(ticks)); + PR_fprintf(output, "PR_IntervalToMicroseconds(%ld): %ld\n\n", ticks, PR_IntervalToMicroseconds(ticks)); ticks *= 3; - printf("PR_IntervalToSeconds(%ld): %ld\n", ticks, PR_IntervalToSeconds(ticks)); - printf("PR_IntervalToMilliseconds(%ld): %ld\n", ticks, PR_IntervalToMilliseconds(ticks)); - printf("PR_IntervalToMicroseconds(%ld): %ld\n\n", ticks, PR_IntervalToMicroseconds(ticks)); + PR_fprintf(output, "PR_IntervalToSeconds(%ld): %ld\n", ticks, PR_IntervalToSeconds(ticks)); + PR_fprintf(output, "PR_IntervalToMilliseconds(%ld): %ld\n", ticks, PR_IntervalToMilliseconds(ticks)); + PR_fprintf(output, "PR_IntervalToMicroseconds(%ld): %ld\n\n", ticks, PR_IntervalToMicroseconds(ticks)); } /*end debug mode */ } /* TestConversions */ +static void TestIntervalOverhead(void) +{ + /* Hopefully the optimizer won't delete this function */ + PRUint32 elapsed, per_call, loops = 1000000; + + PRIntervalTime timeout, timein = PR_IntervalNow(); + while (--loops > 0) + timeout = PR_IntervalNow(); + + elapsed = 1000U * PR_IntervalToMicroseconds(timeout - timein); + per_call = elapsed / 1000000U; + PR_fprintf( + output, "Overhead of 'PR_IntervalNow()' is %u nsecs\n\n", per_call); +} /* TestIntervalOverhead */ + +static void TestNowOverhead(void) +{ + PRTime timeout, timein; + PRInt32 overhead, loops = 1000000; + PRInt64 elapsed, per_call, ten23rd, ten26th; + + LL_I2L(ten23rd, 1000); + LL_I2L(ten26th, 1000000); + + timein = PR_Now(); + while (--loops > 0) + timeout = PR_Now(); + + LL_SUB(elapsed, timeout, timein); + LL_MUL(elapsed, elapsed, ten23rd); + LL_DIV(per_call, elapsed, ten26th); + LL_L2I(overhead, per_call); + PR_fprintf( + output, "Overhead of 'PR_Now()' is %u nsecs\n\n", overhead); +} /* TestNowOverhead */ + static void TestIntervals(void) { PRStatus rv; @@ -107,58 +140,18 @@ static void TestIntervals(void) LL_I2L(thousand, 1000); LL_DIV(elapsed, elapsed, thousand); LL_L2UI(delta, elapsed); - if (debug_mode) printf( + if (debug_mode) PR_fprintf(output, "TestIntervals: %swaiting %ld seconds took %ld msecs\n", ((rv == PR_SUCCESS) ? "" : "FAILED "), seconds, delta); } PR_DestroyCondVar(cv); PR_DestroyLock(ml); - if (debug_mode) printf("\n"); + if (debug_mode) PR_fprintf(output, "\n"); } /* TestIntervals */ -static PRUint32 GetInterval(PRUint32 loops) -{ - PRIntervalTime interval = 0; - while (loops-- > 0) interval += PR_IntervalNow(); - return 0; -} /* GetInterval */ - -static PRUint32 TimeThis( - const char *msg, PRUint32 (*func)(PRUint32 loops), PRUint32 loops) -{ - PRUint32 overhead, usecs32; - PRTime timein, timeout, usecs; - - timein = PR_Now(); - overhead = func(loops); - timeout = PR_Now(); - - LL_SUB(usecs, timeout, timein); - LL_L2I(usecs32, usecs); - - if(usecs32 < overhead) - { - if (debug_mode) { - printf("%s ran in negative time\n", msg); - printf(" predicted overhead was %ld usecs\n", overhead); - printf(" test completed in %ld usecs\n\n", usecs); - } - } - else - { - if (debug_mode) - printf( - "%s [\n\ttotal: %ld usecs\n\toverhead: %ld usecs\n\tcost: %6.3f usecs]\n\n", - msg, usecs, overhead, - ((double)(usecs32 - overhead) / (double)loops)); - } - - return overhead; -} /* TimeThis */ - static PRIntn PR_CALLBACK RealMain(int argc, char** argv) { - PRUint32 cpu, cpus = 2, loops = 1000; + PRUint32 vcpu, cpus = 0, loops = 1000; /* The command line argument: -d is used to determine if the test is being run in debug mode. The regress tool requires only one line output:PASS or FAIL. @@ -191,42 +184,28 @@ static PRIntn PR_CALLBACK RealMain(int argc, char** argv) } PL_DestroyOptState(opt); + output = PR_GetSpecialFD(PR_StandardOutput); + PR_fprintf(output, "inrval: Examine stdout to determine results.\n"); - printf("inrval: Examine stdout to determine results.\n"); - - if (cpus == 0) cpus = 2; + if (cpus == 0) cpus = 8; if (loops == 0) loops = 1000; - if (debug_mode) printf("Inrval: Using %d loops\n", loops); - - - cpus = (argc < 3) ? 2 : atoi(argv[2]); - if (cpus == 0) cpus = 2; - if (debug_mode) printf("Inrval: Using %d cpu(s)\n", cpus); if (debug_mode > 0) { - printf("Inrval: Using %d loops\n", loops); - printf("Inrval: Using %d cpu(s)\n", cpus); + PR_fprintf(output, "Inrval: Using %d loops\n", loops); + PR_fprintf(output, "Inrval: Using 1 and %d cpu(s)\n", cpus); } -#ifdef XP_MAC - SetupMacPrintfLog("inrval.log"); - debug_mode = 1; -#endif - - for (cpu = 1; cpu <= cpus; ++cpu) + for (vcpu = 1; vcpu <= cpus; vcpu += cpus - 1) { + if (debug_mode) + PR_fprintf(output, "\nInrval: Using %d CPU(s)\n\n", vcpu); + PR_SetConcurrency(vcpu); - if (debug_mode) printf("\nInrval: Using %d CPU(s)\n", cpu); - if (debug_mode > 0) - printf("\nInrval: Using %d CPU(s)\n", cpu); - - PR_SetConcurrency(cpu); - + TestNowOverhead(); + TestIntervalOverhead(); TestConversions(); TestIntervals(); - - (void)TimeThis("GetInterval", GetInterval, loops); } return 0; diff --git a/pr/tests/instrumt.c b/pr/tests/instrumt.c new file mode 100644 index 00000000..5a51a9f3 --- /dev/null +++ b/pr/tests/instrumt.c @@ -0,0 +1,470 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "NPL"); you may not use this file except in + * compliance with the NPL. You may obtain a copy of the NPL at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the NPL is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL + * for the specific language governing rights and limitations under the + * NPL. + * + * The Initial Developer of this code under the NPL is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All Rights + * Reserved. + */ + +/* +** File: instrumt.c +** Description: This test is for the NSPR debug aids defined in +** prcountr.h, prtrace.h, prolock.h +** +** The test case tests the three debug aids in NSPR: +** +** Diagnostic messages can be enabled using "instrumt -v 6" +** This sets the msgLevel to something that PR_LOG() likes. +** Also define in the environment "NSPR_LOG_MODULES=Test:6" +** +** CounterTest() tests the counter facility. This test +** creates 4 threads. Each thread either increments, decrements, +** adds to or subtracts from a counter, depending on an argument +** passed to the thread at thread-create time. Each of these threads +** does COUNT_LIMIT iterations doing its thing. When all 4 threads +** are done, the result of the counter is evaluated. If all was atomic, +** the the value of the counter should be zero. +** +** TraceTest(): +** This test mingles with the counter test. Counters trace. +** A thread to extract trace entries on the fly is started. +** A thread to dump trace entries to a file is started. +** +** OrderedLockTest(): +** +** +** +** +** +*/ + +#include <stdio.h> +#include <plstr.h> +#include <prclist.h> +#include <prmem.h> +#include <plgetopt.h> +#include <prlog.h> +#include <prmon.h> +#include <pratom.h> +#include <prtrace.h> +#include <prcountr.h> +#include <prolock.h> + +#define COUNT_LIMIT (10 * ( 1024)) + +#define SMALL_TRACE_BUFSIZE ( 60 * 1024 ) + +typedef enum +{ + CountLoop = 1, + TraceLoop = 2, + TraceFlow = 3 +} TraceTypes; + + +PRLogModuleLevel msgLevel = PR_LOG_ALWAYS; + +PRBool help = PR_FALSE; +PRBool failed = PR_FALSE; + + +PRLogModuleInfo *lm; +PRMonitor *mon; +PRInt32 activeThreads = 0; +PR_DEFINE_COUNTER( hCounter ); +PR_DEFINE_TRACE( hTrace ); + +static void Help(void) +{ + printf("Help? ... Ha!\n"); +} + +static void ListCounters(void) +{ + PR_DEFINE_COUNTER( qh ); + PR_DEFINE_COUNTER( rh ); + char *qn, *rn, *dn; + char **qname = &qn, **rname = &rn, **desc = &dn; + PRUint32 tCtr; + + PR_INIT_COUNTER_HANDLE( qh, NULL ); + PR_FIND_NEXT_COUNTER_QNAME(qh, qh ); + while ( qh != NULL ) + { + PR_INIT_COUNTER_HANDLE( rh, NULL ); + PR_FIND_NEXT_COUNTER_RNAME(rh, rh, qh ); + while ( rh != NULL ) + { + PR_GET_COUNTER_NAME_FROM_HANDLE( rh, qname, rname, desc ); + tCtr = PR_GET_COUNTER(tCtr, rh); + PR_LOG( lm, msgLevel, + ( "QName: %s RName: %s Desc: %s Value: %ld\n", + qn, rn, dn, tCtr )); + PR_FIND_NEXT_COUNTER_RNAME(rh, rh, qh ); + } + PR_FIND_NEXT_COUNTER_QNAME(qh, qh); + } + return; +} /* end ListCounters() */ + +static void ListTraces(void) +{ + PR_DEFINE_TRACE( qh ); + PR_DEFINE_TRACE( rh ); + char *qn, *rn, *dn; + char **qname = &qn, **rname = &rn, **desc = &dn; + + PR_INIT_TRACE_HANDLE( qh, NULL ); + PR_FIND_NEXT_TRACE_QNAME(qh, qh ); + while ( qh != NULL ) + { + PR_INIT_TRACE_HANDLE( rh, NULL ); + PR_FIND_NEXT_TRACE_RNAME(rh, rh, qh ); + while ( rh != NULL ) + { + PR_GET_TRACE_NAME_FROM_HANDLE( rh, qname, rname, desc ); + PR_LOG( lm, msgLevel, + ( "QName: %s RName: %s Desc: %s", + qn, rn, dn )); + PR_FIND_NEXT_TRACE_RNAME(rh, rh, qh ); + } + PR_FIND_NEXT_TRACE_QNAME(qh, qh); + } + return; +} /* end ListCounters() */ + + +static PRInt32 one = 1; +static PRInt32 two = 2; +static PRInt32 three = 3; +static PRInt32 four = 4; + +/* +** Thread to iteratively count something. +*/ +static void PR_CALLBACK CountSomething( void *arg ) +{ + PRInt32 switchVar = *((PRInt32 *)arg); + PRInt32 i; + + PR_LOG( lm, msgLevel, + ("CountSomething: begin thread %ld", switchVar )); + + for ( i = 0; i < COUNT_LIMIT ; i++) + { + switch ( switchVar ) + { + case 1 : + PR_INCREMENT_COUNTER( hCounter ); + break; + case 2 : + PR_DECREMENT_COUNTER( hCounter ); + break; + case 3 : + PR_ADD_TO_COUNTER( hCounter, 1 ); + break; + case 4 : + PR_SUBTRACT_FROM_COUNTER( hCounter, 1 ); + break; + default : + PR_ASSERT( 0 ); + break; + } + PR_TRACE( hTrace, CountLoop, switchVar, i, 0, 0, 0, 0, 0 ); + } /* end for() */ + + PR_LOG( lm, msgLevel, + ("CounterSomething: end thread %ld", switchVar )); + + PR_EnterMonitor(mon); + --activeThreads; + PR_Notify( mon ); + PR_ExitMonitor(mon); + + return; +} /* end CountSomething() */ + +/* +** Create the counter threads. +*/ +static void CounterTest( void ) +{ + PRThread *t1, *t2, *t3, *t4; + PR_DEFINE_COUNTER( tc ); + + PR_LOG( lm, msgLevel, + ("Begin CounterTest")); + + activeThreads += 4; + PR_CREATE_COUNTER( hCounter, "Atomic", "SMP Tests", "test atomic nature of counter" ); + + PR_GET_COUNTER_HANDLE_FROM_NAME( tc, "Atomic", "SMP Tests" ); + PR_ASSERT( tc == hCounter ); + + t1 = PR_CreateThread(PR_USER_THREAD, + CountSomething, &one, + PR_PRIORITY_NORMAL, + PR_GLOBAL_THREAD, + PR_UNJOINABLE_THREAD, + 0); + PR_ASSERT(t1); + + t2 = PR_CreateThread(PR_USER_THREAD, + CountSomething, &two, + PR_PRIORITY_NORMAL, + PR_GLOBAL_THREAD, + PR_UNJOINABLE_THREAD, + 0); + PR_ASSERT(t2); + + t3 = PR_CreateThread(PR_USER_THREAD, + CountSomething, &three, + PR_PRIORITY_NORMAL, + PR_GLOBAL_THREAD, + PR_UNJOINABLE_THREAD, + 0); + PR_ASSERT(t3); + + t4 = PR_CreateThread(PR_USER_THREAD, + CountSomething, &four, + PR_PRIORITY_NORMAL, + PR_GLOBAL_THREAD, + PR_UNJOINABLE_THREAD, + 0); + PR_ASSERT(t4); + + PR_LOG( lm, msgLevel, + ("Counter Threads started")); + + ListCounters(); + return; +} /* end CounterTest() */ + +/* +** Thread to dump trace buffer to a file. +*/ +static void PR_CALLBACK RecordTrace(void *arg ) +{ + PR_RECORD_TRACE_ENTRIES(); + + PR_EnterMonitor(mon); + --activeThreads; + PR_Notify( mon ); + PR_ExitMonitor(mon); + + return; +} /* end RecordTrace() */ + + + +#define NUM_TRACE_RECORDS ( 10000 ) +/* +** Thread to extract and print trace entries from the buffer. +*/ +static void PR_CALLBACK SampleTrace( void *arg ) +{ +#if defined(DEBUG) || defined(FORCE_NSPR_TRACE) + PRInt32 found, rc; + PRTraceEntry *foundEntries; + PRInt32 i; + + foundEntries = (PRTraceEntry *)PR_Malloc( NUM_TRACE_RECORDS * sizeof(PRTraceEntry)); + PR_ASSERT(foundEntries != NULL ); + + do + { + rc = PR_GetTraceEntries( foundEntries, NUM_TRACE_RECORDS, &found); + PR_LOG( lm, msgLevel, + ("SampleTrace: Lost Data: %ld found: %ld", rc, found )); + + if ( found != 0) + { + for ( i = 0 ; i < found; i++ ) + { + PR_LOG( lm, msgLevel, + ("SampleTrace, detail: Thread: %p, Time: %llX, UD0: %ld, UD1: %ld, UD2: %8.8ld", + (foundEntries +i)->thread, + (foundEntries +i)->time, + (foundEntries +i)->userData[0], + (foundEntries +i)->userData[1], + (foundEntries +i)->userData[2] )); + } + } + PR_Sleep(PR_MillisecondsToInterval(50)); + } + while( found != 0 && activeThreads >= 1 ); + + PR_Free( foundEntries ); + + PR_EnterMonitor(mon); + --activeThreads; + PR_Notify( mon ); + PR_ExitMonitor(mon); + + PR_LOG( lm, msgLevel, + ("SampleTrace(): exiting")); + +#endif + return; +} /* end RecordTrace() */ + +/* +** Basic trace test. +*/ +static void TraceTest( void ) +{ + PRInt32 i; + PRInt32 size; + PR_DEFINE_TRACE( th ); + PRThread *t1, *t2; + + PR_LOG( lm, msgLevel, + ("Begin TraceTest")); + + size = SMALL_TRACE_BUFSIZE; + PR_SET_TRACE_OPTION( PRTraceBufSize, &size ); + PR_GET_TRACE_OPTION( PRTraceBufSize, &i ); + PR_ASSERT( i == size ); + + PR_CREATE_TRACE( th, "TraceTest", "tt2", "A description for the trace test" ); + PR_CREATE_TRACE( th, "TraceTest", "tt3", "A description for the trace test" ); + PR_CREATE_TRACE( th, "TraceTest", "tt4", "A description for the trace test" ); + PR_CREATE_TRACE( th, "TraceTest", "tt5", "A description for the trace test" ); + PR_CREATE_TRACE( th, "TraceTest", "tt6", "A description for the trace test" ); + PR_CREATE_TRACE( th, "TraceTest", "tt7", "A description for the trace test" ); + PR_CREATE_TRACE( th, "TraceTest", "tt8", "A description for the trace test" ); + + PR_CREATE_TRACE( th, "Trace Test", "tt0", "QName is Trace Test, not TraceTest" ); + PR_CREATE_TRACE( th, "Trace Test", "tt1", "QName is Trace Test, not TraceTest" ); + PR_CREATE_TRACE( th, "Trace Test", "tt2", "QName is Trace Test, not TraceTest" ); + PR_CREATE_TRACE( th, "Trace Test", "tt3", "QName is Trace Test, not TraceTest" ); + PR_CREATE_TRACE( th, "Trace Test", "tt4", "QName is Trace Test, not TraceTest" ); + PR_CREATE_TRACE( th, "Trace Test", "tt5", "QName is Trace Test, not TraceTest" ); + PR_CREATE_TRACE( th, "Trace Test", "tt6", "QName is Trace Test, not TraceTest" ); + PR_CREATE_TRACE( th, "Trace Test", "tt7", "QName is Trace Test, not TraceTest" ); + PR_CREATE_TRACE( th, "Trace Test", "tt8", "QName is Trace Test, not TraceTest" ); + PR_CREATE_TRACE( th, "Trace Test", "tt9", "QName is Trace Test, not TraceTest" ); + PR_CREATE_TRACE( th, "Trace Test", "tt10", "QName is Trace Test, not TraceTest" ); + + + + activeThreads += 2; + t1 = PR_CreateThread(PR_USER_THREAD, + RecordTrace, NULL, + PR_PRIORITY_NORMAL, + PR_GLOBAL_THREAD, + PR_UNJOINABLE_THREAD, + 0); + PR_ASSERT(t1); + + t2 = PR_CreateThread(PR_USER_THREAD, + SampleTrace, 0, + PR_PRIORITY_NORMAL, + PR_GLOBAL_THREAD, + PR_UNJOINABLE_THREAD, + 0); + PR_ASSERT(t2); + + ListTraces(); + + PR_GET_TRACE_HANDLE_FROM_NAME( th, "TraceTest","tt1" ); + PR_ASSERT( th == hTrace ); + + PR_LOG( lm, msgLevel, + ("End TraceTest")); + return; +} /* end TraceTest() */ + + +/* +** Ordered lock test. +*/ +static void OrderedLockTest( void ) +{ + PR_LOG( lm, msgLevel, + ("Begin OrderedLockTest")); + + +} /* end OrderedLockTest() */ + + +PRIntn main(PRIntn argc, char *argv[]) +{ +#if defined(DEBUG) || defined(FORCE_NSPR_TRACE) + PRUint32 counter; + PLOptStatus os; + PLOptState *opt = PL_CreateOptState(argc, argv, "hdv:"); + lm = PR_NewLogModule("Test"); + + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) + { + if (PL_OPT_BAD == os) continue; + switch (opt->option) + { + case 'v': /* verbose mode */ + msgLevel = (PRLogModuleLevel)atol( opt->value); + break; + case 'h': /* help message */ + Help(); + help = PR_TRUE; + break; + default: + break; + } + } + PL_DestroyOptState(opt); + + PR_CREATE_TRACE( hTrace, "TraceTest", "tt1", "A description for the trace test" ); + mon = PR_NewMonitor(); + PR_EnterMonitor( mon ); + + TraceTest(); + CounterTest(); + OrderedLockTest(); + + /* Wait for all threads to exit */ + while ( activeThreads > 0 ) { + if ( activeThreads == 1 ) + PR_SET_TRACE_OPTION( PRTraceStopRecording, NULL ); + PR_Wait(mon, PR_INTERVAL_NO_TIMEOUT); + PR_GET_COUNTER( counter, hCounter ); + } + PR_ExitMonitor( mon ); + + /* + ** Evaluate results + */ + PR_GET_COUNTER( counter, hCounter ); + if ( counter != 0 ) + { + failed = PR_TRUE; + PR_LOG( lm, msgLevel, + ("Expected counter == 0, found: %ld", counter)); + printf("FAIL\n"); + } + else + { + printf("PASS\n"); + } + + PR_DestroyMonitor( mon ); + + PR_TRACE( hTrace, TraceFlow, 0xfff,0,0,0,0,0,0); + PR_DESTROY_TRACE( hTrace ); +#else + printf("Test not defined\n"); +#endif + return 0; +} /* main() */ +/* end instrumt.c */ + diff --git a/pr/tests/ipv6.c b/pr/tests/ipv6.c index 63ddfbf6..15303430 100644 --- a/pr/tests/ipv6.c +++ b/pr/tests/ipv6.c @@ -17,10 +17,13 @@ */ #include "prio.h" +#include "prenv.h" #include "prmem.h" +#include "prlink.h" #include "prsystem.h" #include "prnetdb.h" #include "prprf.h" +#include "prvrsion.h" #include "plerror.h" #include "plgetopt.h" @@ -37,8 +40,9 @@ static PRFileDesc *err = NULL; static void Help(void) { - PR_fprintf(err, "Usage: [-t s] [-s] [-h]\n"); + PR_fprintf(err, "Usage: [-V] [-6] [-h]\n"); PR_fprintf(err, "\t<nul> Name of host to lookup (default: self)\n"); + PR_fprintf(err, "\t-V Display runtime version info (default: FALSE)\n"); PR_fprintf(err, "\t-6 First turn on IPv6 capability (default: FALSE)\n"); PR_fprintf(err, "\t-h This message and nothing else\n"); } /* Help */ @@ -91,8 +95,8 @@ PRIntn main(PRIntn argc, char **argv) PRProtoEnt proto; PRBool ipv6 = PR_FALSE; const char *name = NULL; - PRBool failed = PR_FALSE; - PLOptState *opt = PL_CreateOptState(argc, argv, "h6"); + PRBool failed = PR_FALSE, version = PR_FALSE; + PLOptState *opt = PL_CreateOptState(argc, argv, "Vh6"); err = PR_GetSpecialFD(PR_StandardError); @@ -107,6 +111,9 @@ PRIntn main(PRIntn argc, char **argv) case '6': /* Turn on IPv6 mode */ ipv6 = PR_TRUE; break; + case 'V': /* Do version discovery */ + version = PR_TRUE; + break; case 'h': /* user wants some guidance */ default: Help(); /* so give him an earful */ @@ -115,6 +122,58 @@ PRIntn main(PRIntn argc, char **argv) } PL_DestroyOptState(opt); + if (version) + { +#if defined(XP_UNIX) +#define NSPR_LIB "nspr21" +#elif defined(WIN32) +#define NSPR_LIB "libnspr21" +#else +#error "Architecture not supported" +#endif + const PRVersionDescription *version_info; + char *nspr_path = PR_GetEnv("LD_LIBRARY_PATH"); + char *nspr_name = PR_GetLibraryName(nspr_path, NSPR_LIB); + PRLibrary *runtime = PR_LoadLibrary(nspr_name); + if (NULL == runtime) + PL_FPrintError(err, "PR_LoadLibrary"); + else + { + versionEntryPointType versionPoint = (versionEntryPointType) + PR_FindSymbol(runtime, "libVersionPoint"); + if (NULL == versionPoint) + PL_FPrintError(err, "PR_FindSymbol"); + else + { + char buffer[100]; + PRExplodedTime exploded; + version_info = versionPoint(); + (void)PR_fprintf(err, "Runtime library version information\n"); + PR_ExplodeTime( + version_info->buildTime, PR_GMTParameters, &exploded); + (void)PR_FormatTime( + buffer, sizeof(buffer), "%d %b %Y %H:%M:%S", &exploded); + (void)PR_fprintf(err, " Build time: %s GMT\n", buffer); + (void)PR_fprintf( + err, " Build time: %s\n", version_info->buildTimeString); + (void)PR_fprintf( + err, " %s V%u.%u.%u (%s%s%s)\n", + version_info->description, + version_info->vMajor, + version_info->vMinor, + version_info->vPatch, + (version_info->beta ? " beta " : ""), + (version_info->debug ? " debug " : ""), + (version_info->special ? " special" : "")); + (void)PR_fprintf(err, " filename: %s\n", version_info->filename); + (void)PR_fprintf(err, " security: %s\n", version_info->security); + (void)PR_fprintf(err, " copyright: %s\n", version_info->copyright); + (void)PR_fprintf(err, " comment: %s\n", version_info->comment); + } + } + if (NULL != nspr_name) PR_FreeLibraryName(nspr_name); + } + if (ipv6) { rv = PR_SetIPv6Enable(ipv6); diff --git a/pr/tests/joinkk.c b/pr/tests/joinkk.c index f3b5396d..5c2e4e9c 100644 --- a/pr/tests/joinkk.c +++ b/pr/tests/joinkk.c @@ -154,12 +154,12 @@ static PRIntn PR_CALLBACK RealMain( PRIntn argc, char **argv ) if(failed_already) { printf("FAIL\n"); - return 0; + return 1; } else { printf("PASS\n"); - return 1; + return 0; } } diff --git a/pr/tests/layer.c b/pr/tests/layer.c index e6be944f..0c93e4b6 100644 --- a/pr/tests/layer.c +++ b/pr/tests/layer.c @@ -64,6 +64,7 @@ static PRFileDesc *PushLayer(PRFileDesc *stack) return stack; } /* PushLayer */ +#if 0 static PRFileDesc *PopLayer(PRFileDesc *stack) { PRFileDesc *popped = PR_PopIOLayer(stack, identity); @@ -73,6 +74,7 @@ static PRFileDesc *PopLayer(PRFileDesc *stack) return stack; } /* PopLayer */ +#endif static void PR_CALLBACK Client(void *arg) { @@ -355,8 +357,8 @@ PRIntn main(PRIntn argc, char **argv) rv = PR_JoinThread(server_thread); PR_ASSERT(PR_SUCCESS == rv); - rv = PR_Close(PopLayer(client)); PR_ASSERT(PR_SUCCESS == rv); - rv = PR_Close(PopLayer(service)); PR_ASSERT(PR_SUCCESS == rv); + rv = PR_Close(client); PR_ASSERT(PR_SUCCESS == rv); + rv = PR_Close(service); PR_ASSERT(PR_SUCCESS == rv); if (verbosity > silent) PR_fprintf(logFile, "Ending layered test\n"); } diff --git a/pr/tests/lock.c b/pr/tests/lock.c index e5683171..6f4616dc 100644 --- a/pr/tests/lock.c +++ b/pr/tests/lock.c @@ -48,9 +48,11 @@ /* Used to get the command line option */ #include "plgetopt.h" +#include "prio.h" #include "prcmon.h" #include "prinit.h" #include "prinrval.h" +#include "prprf.h" #include "prlock.h" #include "prlog.h" #include "prmon.h" @@ -60,7 +62,6 @@ #include "plstr.h" -#include <stdio.h> #include <stdlib.h> #if defined(XP_UNIX) @@ -72,21 +73,28 @@ #define printf PR_LogPrint extern void SetupMacPrintfLog(char *logFile); #endif -PRIntn failed_already=0; -PRIntn debug_mode; + +static PRIntn failed_already=0; +static PRFileDesc *std_err = NULL; +static PRBool verbosity = PR_FALSE; +static PRBool debug_mode = PR_FALSE; const static PRIntervalTime contention_interval = 50; typedef struct LockContentious_s { PRLock *ml; - PRUint32 loops; + PRInt32 loops; + PRUint32 contender; + PRUint32 contentious; PRIntervalTime overhead; PRIntervalTime interval; } LockContentious_t; typedef struct MonitorContentious_s { PRMonitor *ml; - PRUint32 loops; + PRInt32 loops; + PRUint32 contender; + PRUint32 contentious; PRIntervalTime overhead; PRIntervalTime interval; } MonitorContentious_t; @@ -137,6 +145,7 @@ static void PR_CALLBACK LockContender(void *arg) while (contention->loops-- > 0) { PR_Lock(contention->ml); + contention->contender+= 1; contention->overhead += contention->interval; PR_Sleep(contention->interval); PR_Unlock(contention->ml); @@ -150,7 +159,7 @@ static PRIntervalTime ContentiousLock(PRUint32 loops) LockContentious_t * contention; PRIntervalTime rv, overhead, timein = PR_IntervalNow(); - contention = (LockContentious_t *) PR_Calloc( 1, sizeof(LockContentious_t)); + contention = PR_NEWZAP(LockContentious_t); contention->loops = loops; contention->overhead = 0; contention->ml = PR_NewLock(); @@ -162,9 +171,10 @@ static PRIntervalTime ContentiousLock(PRUint32 loops) overhead = PR_IntervalNow() - timein; - while (contention->loops > 0) + while (contention->loops-- > 0) { PR_Lock(contention->ml); + contention->contentious+= 1; contention->overhead += contention->interval; PR_Sleep(contention->interval); PR_Unlock(contention->ml); @@ -175,6 +185,10 @@ static PRIntervalTime ContentiousLock(PRUint32 loops) PR_DestroyLock(contention->ml); overhead += (PR_IntervalNow() - timein); rv = overhead + contention->overhead; + if (verbosity) + PR_fprintf( + std_err, "Access ratio: %u to %u\n", + contention->contentious, contention->contender); PR_Free(contention); return rv; } /* ContentiousLock */ @@ -210,23 +224,23 @@ static PRIntervalTime NonContentiousMonitor(PRUint32 loops) static void PR_CALLBACK TryEntry(void *arg) { PRMonitor *ml = (PRMonitor*)arg; - if (debug_mode) printf("Reentrant thread created\n"); + if (debug_mode) PR_fprintf(std_err, "Reentrant thread created\n"); PR_EnterMonitor(ml); - if (debug_mode) printf("Reentrant thread acquired monitor\n"); + if (debug_mode) PR_fprintf(std_err, "Reentrant thread acquired monitor\n"); PR_ExitMonitor(ml); - if (debug_mode) printf("Reentrant thread released monitor\n"); + if (debug_mode) PR_fprintf(std_err, "Reentrant thread released monitor\n"); } /* TryEntry */ static PRIntervalTime ReentrantMonitor(PRUint32 loops) { - PRStatus status; + PRStatus status; PRThread *thread; PRMonitor *ml = PR_NewMonitor(); - if (debug_mode) printf("\nMonitor created for reentrant test\n"); + if (debug_mode) PR_fprintf(std_err, "\nMonitor created for reentrant test\n"); PR_EnterMonitor(ml); PR_EnterMonitor(ml); - if (debug_mode) printf("Monitor acquired twice\n"); + if (debug_mode) PR_fprintf(std_err, "Monitor acquired twice\n"); thread = PR_CreateThread( PR_USER_THREAD, TryEntry, ml, @@ -235,13 +249,13 @@ static PRIntervalTime ReentrantMonitor(PRUint32 loops) PR_Sleep(PR_SecondsToInterval(1)); PR_ExitMonitor(ml); - if (debug_mode) printf("Monitor released first time\n"); + if (debug_mode) PR_fprintf(std_err, "Monitor released first time\n"); PR_ExitMonitor(ml); - if (debug_mode) printf("Monitor released second time\n"); + if (debug_mode) PR_fprintf(std_err, "Monitor released second time\n"); status = PR_JoinThread(thread); - if (debug_mode) printf( + if (debug_mode) PR_fprintf(std_err, "Reentrant thread joined %s\n", (status == PR_SUCCESS) ? "successfully" : "in error"); @@ -255,6 +269,7 @@ static void PR_CALLBACK MonitorContender(void *arg) while (contention->loops-- > 0) { PR_EnterMonitor(contention->ml); + contention->contender+= 1; contention->overhead += contention->interval; PR_Sleep(contention->interval); PR_ExitMonitor(contention->ml); @@ -268,7 +283,7 @@ static PRUint32 ContentiousMonitor(PRUint32 loops) MonitorContentious_t * contention; PRIntervalTime rv, overhead, timein = PR_IntervalNow(); - contention = (MonitorContentious_t *) PR_Calloc(1, sizeof(MonitorContentious_t)); + contention = PR_NEWZAP(MonitorContentious_t); contention->loops = loops; contention->overhead = 0; contention->ml = PR_NewMonitor(); @@ -280,9 +295,10 @@ static PRUint32 ContentiousMonitor(PRUint32 loops) overhead = PR_IntervalNow() - timein; - while (contention->loops > 0) + while (contention->loops-- > 0) { PR_EnterMonitor(contention->ml); + contention->contentious+= 1; contention->overhead += contention->interval; PR_Sleep(contention->interval); PR_ExitMonitor(contention->ml); @@ -293,6 +309,10 @@ static PRUint32 ContentiousMonitor(PRUint32 loops) PR_DestroyMonitor(contention->ml); overhead += (PR_IntervalNow() - timein); rv = overhead + contention->overhead; + if (verbosity) + PR_fprintf( + std_err, "Access ratio: %u to %u\n", + contention->contentious, contention->contender); PR_Free(contention); return rv; } /* ContentiousMonitor */ @@ -317,6 +337,7 @@ static void PR_CALLBACK Contender(void *arg) while (contention->loops-- > 0) { PR_CEnterMonitor(contention); + contention->contender+= 1; contention->overhead += contention->interval; PR_Sleep(contention->interval); PR_CExitMonitor(contention); @@ -330,9 +351,8 @@ static PRIntervalTime ContentiousCMonitor(PRUint32 loops) MonitorContentious_t * contention; PRIntervalTime overhead, timein = PR_IntervalNow(); - contention = (MonitorContentious_t *) PR_Calloc(1, sizeof(MonitorContentious_t)); + contention = PR_NEWZAP(MonitorContentious_t); contention->ml = NULL; - contention->overhead = 0; contention->loops = loops; contention->interval = contention_interval; thread = PR_CreateThread( @@ -342,9 +362,10 @@ static PRIntervalTime ContentiousCMonitor(PRUint32 loops) overhead = PR_IntervalNow() - timein; - while (contention->loops > 0) + while (contention->loops-- > 0) { PR_CEnterMonitor(contention); + contention->contentious+= 1; contention->overhead += contention->interval; PR_Sleep(contention->interval); PR_CExitMonitor(contention); @@ -353,7 +374,13 @@ static PRIntervalTime ContentiousCMonitor(PRUint32 loops) timein = PR_IntervalNow(); status = PR_JoinThread(thread); overhead += (PR_IntervalNow() - timein); - return overhead + contention->overhead; + overhead += overhead + contention->overhead; + if (verbosity) + PR_fprintf( + std_err, "Access ratio: %u to %u\n", + contention->contentious, contention->contender); + PR_Free(contention); + return overhead; } /* ContentiousCMonitor */ static PRIntervalTime Test( @@ -381,12 +408,12 @@ static PRIntervalTime Test( accountable = duration - predicted; accountable -= overhead; elapsed = (PRFloat64)PR_IntervalToMicroseconds(accountable); - printf("%s:", msg); - while (spaces++ < 50) printf(" "); + PR_fprintf(PR_STDOUT, "%s:", msg); + while (spaces++ < 50) PR_fprintf(PR_STDOUT, " "); if ((PRInt32)accountable < 0) - printf("*****.** usecs/iteration\n"); + PR_fprintf(PR_STDOUT, "*****.** usecs/iteration\n"); else - printf("%8.2f usecs/iteration\n", elapsed/loops); + PR_fprintf(PR_STDOUT, "%8.2f usecs/iteration\n", elapsed/loops); } return duration; } /* Test */ @@ -410,14 +437,17 @@ int main(int argc, char **argv) Usage: lock [-d] [-l <num>] [-c <num>] */ PLOptStatus os; - PLOptState *opt = PL_CreateOptState(argc, argv, "dl:c:"); + PLOptState *opt = PL_CreateOptState(argc, argv, "dvl:c:"); while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) { if (PL_OPT_BAD == os) continue; switch (opt->option) { case 'd': /* debug mode */ - debug_mode = 1; + debug_mode = PR_TRUE; + break; + case 'v': /* debug mode */ + verbosity = PR_TRUE; break; case 'l': /* number of loops */ loops = atoi(opt->value); @@ -441,16 +471,20 @@ int main(int argc, char **argv) #endif if (loops == 0) loops = 100; - if (debug_mode) printf("Lock: Using %d loops\n", loops); + if (debug_mode) + { + std_err = PR_STDERR; + PR_fprintf(std_err, "Lock: Using %d loops\n", loops); + } if (cpus == 0) cpus = 2; - if (debug_mode) printf("Lock: Using %d cpu(s)\n", cpus); + if (debug_mode) PR_fprintf(std_err, "Lock: Using %d cpu(s)\n", cpus); (void)Sleeper(10); /* try filling in the caches */ for (cpu = 1; cpu <= cpus; ++cpu) { - if (debug_mode) printf("\nLock: Using %d CPU(s)\n", cpu); + if (debug_mode) PR_fprintf(std_err, "\nLock: Using %d CPU(s)\n", cpu); PR_SetConcurrency(cpu); duration = Test("Overhead of PR_Sleep", Sleeper, loops, 0); @@ -469,7 +503,10 @@ int main(int argc, char **argv) (void)ReentrantMonitor(loops); } - if (debug_mode) printf("%s: test %s\n", "Lock(mutex) test", ((rv) ? "passed" : "failed")); + if (debug_mode) + PR_fprintf( + std_err, "%s: test %s\n", "Lock(mutex) test", + ((rv) ? "passed" : "failed")); else { if (!rv) failed_already=1; @@ -477,12 +514,12 @@ int main(int argc, char **argv) if(failed_already) { - printf("FAIL\n"); + PR_fprintf(PR_STDOUT, "FAIL\n"); return 1; } else { - printf("PASS\n"); + PR_fprintf(PR_STDOUT, "PASS\n"); return 0; } diff --git a/pr/tests/many_cv.c b/pr/tests/many_cv.c index ae973655..1f964458 100644 --- a/pr/tests/many_cv.c +++ b/pr/tests/many_cv.c @@ -114,9 +114,7 @@ static PRIntn PR_CALLBACK RealMain( PRIntn argc, char **argv ) printf("PASS\n"); -#if defined(DEBUG) && defined(_PR_PTHREADS) PT_FPrintStats(err, "\nPThread Statistics\n"); -#endif /* defined(DEBUG) && defined(_PR_PTHREADS) */ return 0; } diff --git a/pr/tests/multiwait.c b/pr/tests/multiwait.c index be4ed6bb..4358b350 100644 --- a/pr/tests/multiwait.c +++ b/pr/tests/multiwait.c @@ -43,7 +43,6 @@ typedef struct Shared typedef enum Verbosity {silent, quiet, chatty, noisy} Verbosity; -static PRUint32 identity = 0; static PRFileDesc *debug = NULL; static PRInt32 desc_allocated = 0; static PRUint16 default_port = 12273; @@ -113,7 +112,7 @@ static PRRecvWait *CreateRecvWait(PRFileDesc *fd, PRIntervalTime timeout) return desc_out; } /* CreateRecvWait */ -static void DestroyRecvWait(Shared *shared, PRRecvWait *desc_out) +static void DestroyRecvWait(PRRecvWait *desc_out) { if (verbosity > chatty) PrintRecvDesc(desc_out, "Destroying"); @@ -134,7 +133,7 @@ static void CancelGroup(Shared *shared) do { desc_out = PR_CancelWaitGroup(shared->group); - if (NULL != desc_out) DestroyRecvWait(shared, desc_out); + if (NULL != desc_out) DestroyRecvWait(desc_out); } while (NULL != desc_out); MW_ASSERT(0 == desc_allocated); @@ -298,7 +297,7 @@ static void PR_CALLBACK SomeOpsThread(void *arg) if (NULL == desc_out) { MW_ASSERT(PR_PENDING_INTERRUPT_ERROR == PR_GetError()); - if (verbosity > quiet) PrintRecvDesc(desc_out, "Aborted"); + if (verbosity > quiet) PR_fprintf(debug, "Aborted\n"); break; } MW_ASSERT(PR_MW_TIMEOUT == desc_out->outcome); @@ -422,9 +421,6 @@ static void PR_CALLBACK ServiceThread(void *arg) case PR_MW_SUCCESS: { PR_AtomicIncrement(&ops_done); - if (verbosity > quiet) - PR_fprintf( - debug, "%s: Servicing %u\n", shared->title, ops_done); if (verbosity > chatty) PrintRecvDesc(desc_out, "Service ready"); rv = ServiceRequest(shared, desc_out); @@ -445,10 +441,40 @@ static void PR_CALLBACK ServiceThread(void *arg) } } while (PR_SUCCESS == rv); - if (NULL != desc_out) DestroyRecvWait(shared, desc_out); + if (NULL != desc_out) DestroyRecvWait(desc_out); } /* ServiceThread */ +static void PR_CALLBACK EnumerationThread(void *arg) +{ + PRStatus rv; + PRIntn count; + PRRecvWait *desc; + Shared *shared = (Shared*)arg; + PRIntervalTime five_seconds = PR_SecondsToInterval(5); + PRMWaitEnumerator *enumerator = PR_CreateMWaitEnumerator(shared->group); + MW_ASSERT(NULL != enumerator); + + while (PR_SUCCESS == PR_Sleep(five_seconds)) + { + count = 0; + desc = NULL; + while (NULL != (desc = PR_EnumerateWaitGroup(enumerator, desc))) + { + if (verbosity > chatty) PrintRecvDesc(desc, shared->title); + count += 1; + } + if (verbosity > silent) + PR_fprintf(debug, + "%s Enumerated %d objects\n", shared->title, count); + } + + MW_ASSERT(PR_PENDING_INTERRUPT_ERROR == PR_GetError()); + + + rv = PR_DestroyMWaitEnumerator(enumerator); + MW_ASSERT(PR_SUCCESS == rv); +} /* EnumerationThread */ static void PR_CALLBACK ServerThread(void *arg) { @@ -534,7 +560,7 @@ static void RealOneGroupIO(Shared *shared) */ PRStatus rv; PRIntn index; - PRThread *server_thread, **client_thread; + PRThread *server_thread, *enumeration_thread, **client_thread; if (verbosity > quiet) PR_fprintf(debug, "%s: creating server_thread\n", shared->title); @@ -545,6 +571,14 @@ static void RealOneGroupIO(Shared *shared) PR_JOINABLE_THREAD, 16 * 1024); if (verbosity > quiet) + PR_fprintf(debug, "%s: creating enumeration_thread\n", shared->title); + + enumeration_thread = PR_CreateThread( + PR_USER_THREAD, EnumerationThread, shared, + PR_PRIORITY_HIGH, thread_scope, + PR_JOINABLE_THREAD, 16 * 1024); + + if (verbosity > quiet) PR_fprintf(debug, "%s: snoozing before creating clients\n", shared->title); PR_Sleep(5 * shared->timeout); @@ -572,6 +606,13 @@ static void RealOneGroupIO(Shared *shared) } if (verbosity > quiet) + PR_fprintf(debug, "%s: interrupting/joining enumeration_thread\n", shared->title); + rv = PR_Interrupt(enumeration_thread); + MW_ASSERT(PR_SUCCESS == rv); + rv = PR_JoinThread(enumeration_thread); + MW_ASSERT(PR_SUCCESS == rv); + + if (verbosity > quiet) PR_fprintf(debug, "%s: interrupting/joining server_thread\n", shared->title); rv = PR_Interrupt(server_thread); MW_ASSERT(PR_SUCCESS == rv); @@ -598,7 +639,7 @@ static void RunThisOne( static Verbosity ChangeVerbosity(Verbosity verbosity, PRIntn delta) { PRIntn verbage = (PRIntn)verbosity; - return (Verbosity)(verbage += 1); + return (Verbosity)(verbage += delta); } /* ChangeVerbosity */ PRIntn main(PRIntn argc, char **argv) diff --git a/pr/tests/nbconn.c b/pr/tests/nbconn.c index 372a8e78..b206f991 100644 --- a/pr/tests/nbconn.c +++ b/pr/tests/nbconn.c @@ -38,6 +38,7 @@ */ #include "nspr.h" +#include "plgetopt.h" #include <stdio.h> #ifdef XP_MAC @@ -46,21 +47,61 @@ extern void SetupMacPrintfLog(char *logFile); static char *hosts[4] = {"cynic", "warp", "gandalf", "neon"}; #endif +#define SERVER_MAX_BIND_COUNT 100 +#define DATA_BUF_SIZE 256 +#define TCP_SERVER_PORT 10000 + +typedef struct Server_Param { + PRFileDesc *sp_fd; /* server port */ +} Server_Param; +static void PR_CALLBACK TCP_Server(void *arg); + +int _debug_on; +#define DPRINTF(arg) if (_debug_on) printf arg + +static PRIntn connection_success_test(); +static PRIntn connection_failure_test(); int main(int argc, char **argv) { PRHostEnt he; char buf[1024]; PRNetAddr addr; - PRFileDesc *sock; PRPollDesc pd; PRStatus rv; PRSocketOptionData optData; - PRIntn n; - + const char *hostname; + PRIntn default_case, n, bytes_read, bytes_sent; + PRInt32 failed_already = 0; #ifdef XP_MAC int index; PRIntervalTime timeout; +#endif + + /* + * -d debug mode + */ + + PLOptStatus os; + PLOptState *opt = PL_CreateOptState(argc, argv, "d"); + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) + { + if (PL_OPT_BAD == os) continue; + switch (opt->option) + { + case 0: /* debug mode */ + hostname = opt->value; + break; + case 'd': /* debug mode */ + _debug_on = 1; + break; + default: + break; + } + } + PL_DestroyOptState(opt); + +#ifdef XP_MAC SetupMacPrintfLog("nbconn.log"); for (index=0; index<4; index++) { argv[1] = hosts[index]; @@ -69,90 +110,473 @@ int main(int argc, char **argv) timeout = PR_SecondsToInterval(10UL); #endif + PR_STDIO_INIT(); #ifndef XP_MAC - if (argc != 2) { - fprintf(stderr, "Usage: nbconn <hostname>\n"); - exit(1); - } + if (hostname) + default_case = 0; + else + default_case = 1; #endif - if (PR_GetHostByName(argv[1], buf, sizeof(buf), &he) == PR_FAILURE) { - printf( "Unknown host: %s\n", buf); - exit(1); - } else { - printf( "host: %s\n", buf); - } - PR_EnumerateHostEnt(0, &he, 80, &addr); - - sock = PR_NewTCPSocket(); - optData.option = PR_SockOpt_Nonblocking; - optData.value.non_blocking = PR_TRUE; - PR_SetSocketOption(sock, &optData); - rv = PR_Connect(sock, &addr, PR_INTERVAL_NO_TIMEOUT); - if (rv == PR_FAILURE && PR_GetError() == PR_IN_PROGRESS_ERROR) { - printf( "Connect in progress\n"); - } + if (default_case) { + + /* + * In the default case the following tests are executed: + * 1. successful connection: a server thread accepts a connection + * from the main thread + * 2. unsuccessful connection: the main thread tries to connect to a + * non-existent port and expects to get an error + */ + rv = connection_success_test(); + if (rv == 0) + rv = connection_failure_test(); + return rv; + } else { + PRFileDesc *sock; - pd.fd = sock; - pd.in_flags = PR_POLL_WRITE | PR_POLL_EXCEPT; + if (PR_GetHostByName(argv[1], buf, sizeof(buf), &he) == PR_FAILURE) { + printf( "Unknown host: %s\n", argv[1]); + exit(1); + } else { + printf( "host: %s\n", buf); + } + PR_EnumerateHostEnt(0, &he, 80, &addr); + + sock = PR_NewTCPSocket(); + optData.option = PR_SockOpt_Nonblocking; + optData.value.non_blocking = PR_TRUE; + PR_SetSocketOption(sock, &optData); + rv = PR_Connect(sock, &addr, PR_INTERVAL_NO_TIMEOUT); + if (rv == PR_FAILURE && PR_GetError() == PR_IN_PROGRESS_ERROR) { + printf( "Connect in progress\n"); + } + + pd.fd = sock; + pd.in_flags = PR_POLL_WRITE | PR_POLL_EXCEPT; #ifndef XP_MAC - n = PR_Poll(&pd, 1, PR_INTERVAL_NO_TIMEOUT); + n = PR_Poll(&pd, 1, PR_INTERVAL_NO_TIMEOUT); #else - n = PR_Poll(&pd, 1, timeout); + n = PR_Poll(&pd, 1, timeout); #endif - if (n == -1) { - printf( "PR_Poll failed\n"); - exit(1); - } - printf( "PR_Poll returns %d\n", n); - if (pd.out_flags & PR_POLL_READ) { - printf( "PR_POLL_READ\n"); - } - if (pd.out_flags & PR_POLL_WRITE) { - printf( "PR_POLL_WRITE\n"); - } - if (pd.out_flags & PR_POLL_EXCEPT) { - printf( "PR_POLL_EXCEPT\n"); - } - if (pd.out_flags & PR_POLL_ERR) { - printf( "PR_POLL_ERR\n"); - } - if (pd.out_flags & PR_POLL_NVAL) { - printf( "PR_POLL_NVAL\n"); - } + if (n == -1) { + printf( "PR_Poll failed\n"); + exit(1); + } + printf( "PR_Poll returns %d\n", n); + if (pd.out_flags & PR_POLL_READ) { + printf( "PR_POLL_READ\n"); + } + if (pd.out_flags & PR_POLL_WRITE) { + printf( "PR_POLL_WRITE\n"); + } + if (pd.out_flags & PR_POLL_EXCEPT) { + printf( "PR_POLL_EXCEPT\n"); + } + if (pd.out_flags & PR_POLL_ERR) { + printf( "PR_POLL_ERR\n"); + } + if (pd.out_flags & PR_POLL_NVAL) { + printf( "PR_POLL_NVAL\n"); + } - if (PR_GetConnectStatus(&pd) == PR_SUCCESS) { - printf("PR_GetConnectStatus: connect succeeded\n"); - /* Mac and Win16 have trouble printing to the console. */ + if (PR_GetConnectStatus(&pd) == PR_SUCCESS) { + printf("PR_GetConnectStatus: connect succeeded\n"); + /* Mac and Win16 have trouble printing to the console. */ #if !defined(XP_MAC) && !defined(WIN16) - PR_Write(sock, "GET /\r\n\r\n", 9); - PR_Shutdown(sock, PR_SHUTDOWN_SEND); - pd.in_flags = PR_POLL_READ; - while (1) { - n = PR_Poll(&pd, 1, PR_INTERVAL_NO_TIMEOUT); - printf( "poll returns %d\n", n); - n = PR_Read(sock, buf, sizeof(buf)); - printf( "read returns %d\n", n); - if (n <= 0) { - break; - } - PR_Write(PR_STDOUT, buf, n); - } + PR_Write(sock, "GET /\r\n\r\n", 9); + PR_Shutdown(sock, PR_SHUTDOWN_SEND); + pd.in_flags = PR_POLL_READ; + while (1) { + n = PR_Poll(&pd, 1, PR_INTERVAL_NO_TIMEOUT); + printf( "poll returns %d\n", n); + n = PR_Read(sock, buf, sizeof(buf)); + printf( "read returns %d\n", n); + if (n <= 0) { + break; + } + PR_Write(PR_STDOUT, buf, n); + } #endif - } else { - if (PR_GetError() == PR_IN_PROGRESS_ERROR) { - printf( "PR_GetConnectStatus: connect still in progress\n"); - exit(1); - } - printf( "PR_GetConnectStatus: connect failed: (%ld, %ld)\n", - PR_GetError(), PR_GetOSError()); - } - PR_Close(sock); + } else { + if (PR_GetError() == PR_IN_PROGRESS_ERROR) { + printf( "PR_GetConnectStatus: connect still in progress\n"); + exit(1); + } + printf( "PR_GetConnectStatus: connect failed: (%ld, %ld)\n", + PR_GetError(), PR_GetOSError()); + } + PR_Close(sock); #ifdef XP_MAC - } /* end of for loop */ + } /* end of for loop */ +#endif + printf( "PASS\n"); + return 0; + + } +} + + +/* + * TCP Server + * Server Thread + * Accept a connection from the client and write some data + */ +static void PR_CALLBACK +TCP_Server(void *arg) +{ + Server_Param *sp = (Server_Param *) arg; + PRFileDesc *sockfd, *newsockfd; + char data_buf[DATA_BUF_SIZE]; + PRIntn rv, bytes_read; + + sockfd = sp->sp_fd; + if ((newsockfd = PR_Accept(sockfd, NULL, + PR_INTERVAL_NO_TIMEOUT)) == NULL) { + fprintf(stderr,"ERROR - PR_Accept failed: (%d,%d)\n", + PR_GetError(), PR_GetOSError()); + return; + } + bytes_read = 0; + while (bytes_read != DATA_BUF_SIZE) { + rv = PR_Read(newsockfd, data_buf + bytes_read , + DATA_BUF_SIZE - bytes_read); + if (rv < 0) { + fprintf(stderr,"Error - PR_Read failed: (%d, %d)\n", + PR_GetError(), PR_GetOSError()); + PR_Close(newsockfd); + return; + } + PR_ASSERT(rv != 0); + bytes_read += rv; + } + DPRINTF(("Bytes read from client - %d\n",bytes_read)); + rv = PR_Write(newsockfd, data_buf,DATA_BUF_SIZE); + if (rv < 0) { + fprintf(stderr,"Error - PR_Write failed: (%d, %d)\n", + PR_GetError(), PR_GetOSError()); + PR_Close(newsockfd); + return; + } + PR_ASSERT(rv == DATA_BUF_SIZE); + DPRINTF(("Bytes written to client - %d\n",rv)); + PR_Close(newsockfd); +} + + +/* + * test for successful connection using a non-blocking socket + */ +static PRIntn +connection_success_test() +{ + PRFileDesc *sockfd = NULL, *conn_fd = NULL; + PRNetAddr netaddr; + PRInt32 i, rv; + PRPollDesc pd; + PRSocketOptionData optData; + PRThread *thr = NULL; + Server_Param sp; + char send_buf[DATA_BUF_SIZE], recv_buf[DATA_BUF_SIZE]; + PRIntn default_case, n, bytes_read, bytes_sent; + PRIntn failed_already; + + /* + * Create a tcp socket + */ + if ((sockfd = PR_NewTCPSocket()) == NULL) { + fprintf(stderr,"Error - PR_NewTCPSocket failed\n"); + failed_already=1; + goto def_exit; + } + memset(&netaddr, 0 , sizeof(netaddr)); + netaddr.inet.family = PR_AF_INET; + netaddr.inet.port = PR_htons(TCP_SERVER_PORT); + netaddr.inet.ip = PR_htonl(PR_INADDR_ANY); + /* + * try a few times to bind server's address, if addresses are in + * use + */ + i = 0; + while (PR_Bind(sockfd, &netaddr) < 0) { + if (PR_GetError() == PR_ADDRESS_IN_USE_ERROR) { + netaddr.inet.port += 2; + if (i++ < SERVER_MAX_BIND_COUNT) + continue; + } + fprintf(stderr,"ERROR - PR_Bind failed: (%d,%d)\n", + PR_GetError(), PR_GetOSError()); + failed_already=1; + goto def_exit; + } + + if (PR_Listen(sockfd, 32) < 0) { + fprintf(stderr,"ERROR - PR_Listen failed: (%d,%d)\n", + PR_GetError(), PR_GetOSError()); + failed_already=1; + goto def_exit; + } + + if (PR_GetSockName(sockfd, &netaddr) < 0) { + fprintf(stderr,"ERROR - PR_GetSockName failed: (%d,%d)\n", + PR_GetError(), PR_GetOSError()); + failed_already=1; + goto def_exit; + } + if ((conn_fd = PR_NewTCPSocket()) == NULL) { + fprintf(stderr,"Error - PR_NewTCPSocket failed\n"); + failed_already=1; + goto def_exit; + } + optData.option = PR_SockOpt_Nonblocking; + optData.value.non_blocking = PR_TRUE; + PR_SetSocketOption(conn_fd, &optData); + rv = PR_Connect(conn_fd, &netaddr, PR_INTERVAL_NO_TIMEOUT); + if (rv == PR_FAILURE) { + if (PR_GetError() == PR_IN_PROGRESS_ERROR) { + DPRINTF(("Connect in progress\n")); + } else { + fprintf(stderr,"Error - PR_Connect failed: (%d, %d)\n", + PR_GetError(), PR_GetOSError()); + failed_already=1; + goto def_exit; + } + } else { + PR_ASSERT(rv == PR_SUCCESS); + fprintf(stderr,"Error - PR_Connect succeeded, expected to fail\n"); + failed_already=1; + goto def_exit; + } + /* + * Now create a thread to accept a connection + */ + sp.sp_fd = sockfd; + thr = PR_CreateThread(PR_USER_THREAD, TCP_Server, (void *)&sp, + PR_PRIORITY_NORMAL, PR_LOCAL_THREAD, PR_JOINABLE_THREAD, 0); + if (thr == NULL) { + fprintf(stderr,"Error - PR_CreateThread failed: (%d,%d)\n", + PR_GetError(), PR_GetOSError()); + failed_already=1; + goto def_exit; + } + DPRINTF(("Created TCP_Server thread [0x%x]\n",thr)); + pd.fd = conn_fd; + pd.in_flags = PR_POLL_WRITE | PR_POLL_EXCEPT; +#ifndef XP_MAC + n = PR_Poll(&pd, 1, PR_INTERVAL_NO_TIMEOUT); +#else + n = PR_Poll(&pd, 1, timeout); +#endif + if (n == -1) { + fprintf(stderr,"Error - PR_Poll failed: (%d, %d)\n", + PR_GetError(), PR_GetOSError()); + failed_already=1; + goto def_exit; + } + if (pd.out_flags != PR_POLL_WRITE) { + fprintf(stderr,"Error - PR_Poll returned invalid outflags: 0x%x\n", + pd.out_flags); + failed_already=1; + goto def_exit; + } + if (PR_GetConnectStatus(&pd) == PR_SUCCESS) { + PRInt32 rv; + + DPRINTF(("Connection successful\n")); + + /* + * Write some data, read it back and check data integrity to + * make sure the connection is good + */ + pd.in_flags = PR_POLL_WRITE; + bytes_sent = 0; + memset(send_buf, 'a', DATA_BUF_SIZE); + while (bytes_sent != DATA_BUF_SIZE) { + rv = PR_Poll(&pd, 1, PR_INTERVAL_NO_TIMEOUT); + if (rv < 0) { + fprintf(stderr,"Error - PR_Poll failed: (%d, %d)\n", + PR_GetError(), PR_GetOSError()); + failed_already=1; + goto def_exit; + } + PR_ASSERT((rv == 1) && (pd.out_flags == PR_POLL_WRITE)); + rv = PR_Write(conn_fd, send_buf + bytes_sent, + DATA_BUF_SIZE - bytes_sent); + if (rv < 0) { + fprintf(stderr,"Error - PR_Write failed: (%d, %d)\n", + PR_GetError(), PR_GetOSError()); + failed_already=1; + goto def_exit; + } + PR_ASSERT(rv > 0); + bytes_sent += rv; + } + DPRINTF(("Bytes written to server - %d\n",bytes_sent)); + PR_Shutdown(conn_fd, PR_SHUTDOWN_SEND); + pd.in_flags = PR_POLL_READ; + bytes_read = 0; + memset(recv_buf, 0, DATA_BUF_SIZE); + while (bytes_read != DATA_BUF_SIZE) { + rv = PR_Poll(&pd, 1, PR_INTERVAL_NO_TIMEOUT); + if (rv < 0) { + fprintf(stderr,"Error - PR_Poll failed: (%d, %d)\n", + PR_GetError(), PR_GetOSError()); + failed_already=1; + goto def_exit; + } + PR_ASSERT((rv == 1) && (pd.out_flags == PR_POLL_READ)); + rv = PR_Read(conn_fd, recv_buf + bytes_read , + DATA_BUF_SIZE - bytes_read); + if (rv < 0) { + fprintf(stderr,"Error - PR_Read failed: (%d, %d)\n", + PR_GetError(), PR_GetOSError()); + failed_already=1; + goto def_exit; + } + PR_ASSERT(rv != 0); + bytes_read += rv; + } + DPRINTF(("Bytes read from server - %d\n",bytes_read)); + /* + * verify the data read + */ + if (memcmp(send_buf, recv_buf, DATA_BUF_SIZE) != 0) { + fprintf(stderr,"ERROR - data corruption\n"); + failed_already=1; + goto def_exit; + } + DPRINTF(("Data integrity verified\n")); + } else { + fprintf(stderr,"PR_GetConnectStatus: connect failed: (%ld, %ld)\n", + PR_GetError(), PR_GetOSError()); + failed_already = 1; + goto def_exit; + } +def_exit: + if (thr) { + PR_JoinThread(thr); + thr = NULL; + } + if (sockfd) { + PR_Close(sockfd); + sockfd = NULL; + } + if (conn_fd) { + PR_Close(conn_fd); + conn_fd = NULL; + } + if (failed_already) + return 1; + else + return 0; + +} + +/* + * test for connection to a non-existent port using a non-blocking socket + */ +static PRIntn +connection_failure_test() +{ + PRFileDesc *sockfd = NULL, *conn_fd = NULL; + PRNetAddr netaddr; + PRInt32 i, rv; + PRPollDesc pd; + PRSocketOptionData optData; + PRIntn n, failed_already = 0; + + /* + * Create a tcp socket + */ + if ((sockfd = PR_NewTCPSocket()) == NULL) { + fprintf(stderr,"Error - PR_NewTCPSocket failed\n"); + failed_already=1; + goto def_exit; + } + memset(&netaddr, 0 , sizeof(netaddr)); + netaddr.inet.family = PR_AF_INET; + netaddr.inet.port = PR_htons(TCP_SERVER_PORT); + netaddr.inet.ip = PR_htonl(PR_INADDR_ANY); + /* + * try a few times to bind server's address, if addresses are in + * use + */ + i = 0; + while (PR_Bind(sockfd, &netaddr) < 0) { + if (PR_GetError() == PR_ADDRESS_IN_USE_ERROR) { + netaddr.inet.port += 2; + if (i++ < SERVER_MAX_BIND_COUNT) + continue; + } + fprintf(stderr,"ERROR - PR_Bind failed: (%d,%d)\n", + PR_GetError(), PR_GetOSError()); + failed_already=1; + goto def_exit; + } + + if (PR_GetSockName(sockfd, &netaddr) < 0) { + fprintf(stderr,"ERROR - PR_GetSockName failed: (%d,%d)\n", + PR_GetError(), PR_GetOSError()); + failed_already=1; + goto def_exit; + } + if ((conn_fd = PR_NewTCPSocket()) == NULL) { + fprintf(stderr,"Error - PR_NewTCPSocket failed\n"); + failed_already=1; + goto def_exit; + } + optData.option = PR_SockOpt_Nonblocking; + optData.value.non_blocking = PR_TRUE; + PR_SetSocketOption(conn_fd, &optData); + rv = PR_Connect(conn_fd, &netaddr, PR_INTERVAL_NO_TIMEOUT); + if (rv == PR_FAILURE) { + DPRINTF(("PR_Connect to a non-listen port failed: (%d, %d)\n", + PR_GetError(), PR_GetOSError())); + } else { + PR_ASSERT(rv == PR_SUCCESS); + fprintf(stderr,"Error - PR_Connect succeeded, expected to fail\n"); + failed_already=1; + goto def_exit; + } + pd.fd = conn_fd; + pd.in_flags = PR_POLL_WRITE | PR_POLL_EXCEPT; +#ifndef XP_MAC + n = PR_Poll(&pd, 1, PR_INTERVAL_NO_TIMEOUT); +#else + n = PR_Poll(&pd, 1, timeout); #endif + if (n == -1) { + fprintf(stderr,"Error - PR_Poll failed: (%d, %d)\n", + PR_GetError(), PR_GetOSError()); + failed_already=1; + goto def_exit; + } + if (pd.out_flags != PR_POLL_WRITE) { + fprintf(stderr,"Error - PR_Poll returned invalid outflags: 0x%x\n", + pd.out_flags); + failed_already=1; + goto def_exit; + } + if (PR_GetConnectStatus(&pd) == PR_SUCCESS) { + PRInt32 rv; + fprintf(stderr,"PR_GetConnectStatus succeeded, expected to fail\n"); + failed_already = 1; + goto def_exit; + } + rv = PR_GetError(); + DPRINTF(("Connection failed, successfully with PR_Error %d\n",rv)); +def_exit: + if (sockfd) { + PR_Close(sockfd); + sockfd = NULL; + } + if (conn_fd) { + PR_Close(conn_fd); + conn_fd = NULL; + } + if (failed_already) + return 1; + else + return 0; - printf( "PASS\n"); - return 0; } diff --git a/pr/tests/nblayer.c b/pr/tests/nblayer.c index 2c0ffd67..b14073a1 100644 --- a/pr/tests/nblayer.c +++ b/pr/tests/nblayer.c @@ -103,20 +103,24 @@ static void PR_CALLBACK Client(void *arg) rv = PR_Connect(stack, &server_address, PR_INTERVAL_NO_TIMEOUT); if ((PR_FAILURE == rv) && (PR_IN_PROGRESS_ERROR == PR_GetError())) { + if (verbosity > quiet) + PR_fprintf(logFile, "Client connect 'in progress'\n"); do { - { - polldesc.fd = stack; - polldesc.out_flags = 0; - polldesc.in_flags = PR_POLL_WRITE | PR_POLL_EXCEPT; - ready = PR_Poll(&polldesc, 1, PR_INTERVAL_NO_TIMEOUT); - if (1 != ready) break; /* if not 1, then we're dead */ - rv = PR_GetConnectStatus(&polldesc); - if (PR_FAILURE == rv) - { - if (PR_IN_PROGRESS_ERROR != PR_GetError()) break; - } - } + polldesc.fd = stack; + polldesc.out_flags = 0; + polldesc.in_flags = PR_POLL_WRITE | PR_POLL_EXCEPT; + ready = PR_Poll(&polldesc, 1, PR_INTERVAL_NO_TIMEOUT); + if ((1 != ready) /* if not 1, then we're dead */ + || (0 == (polldesc.in_flags & polldesc.out_flags))) + { PR_ASSERT(!"Whoa!"); break; } + if (verbosity > quiet) + PR_fprintf( + logFile, "Client connect 'in progress' [0x%x]\n", + polldesc.out_flags); + rv = PR_GetConnectStatus(&polldesc); + if ((PR_FAILURE == rv) + && (PR_IN_PROGRESS_ERROR != PR_GetError())) break; } while (PR_FAILURE == rv); } PR_ASSERT(PR_SUCCESS == rv); @@ -126,24 +130,29 @@ static void PR_CALLBACK Client(void *arg) for (mits = 0; mits < minor_iterations; ++mits) { bytes_sent = 0; - if (verbosity > chatty) + if (verbosity > quiet) PR_fprintf(logFile, "Client sending %d bytes\n", sizeof(buffer)); do { + if (verbosity > chatty) + PR_fprintf( + logFile, "Client sending %d bytes\n", + sizeof(buffer) - bytes_sent); ready = PR_Send( stack, buffer + bytes_sent, sizeof(buffer) - bytes_sent, empty_flags, PR_INTERVAL_NO_TIMEOUT); - if (0 < ready) - { - bytes_sent += ready; - } + if (verbosity > chatty) + PR_fprintf(logFile, "Client send status [%d]\n", ready); + if (0 < ready) bytes_sent += ready; else if ((-1 == ready) && (PR_WOULD_BLOCK_ERROR == PR_GetError())) { polldesc.fd = stack; polldesc.out_flags = 0; polldesc.in_flags = PR_POLL_WRITE; ready = PR_Poll(&polldesc, 1, PR_INTERVAL_NO_TIMEOUT); - if (1 != ready) break; /* if not 1, then we're dead */ + if ((1 != ready) /* if not 1, then we're dead */ + || (0 == (polldesc.in_flags & polldesc.out_flags))) + { PR_ASSERT(!"Whoa!"); break; } } else break; } while (bytes_sent < sizeof(buffer)); @@ -152,20 +161,26 @@ static void PR_CALLBACK Client(void *arg) bytes_read = 0; do { + if (verbosity > chatty) + PR_fprintf( + logFile, "Client receiving %d bytes\n", + bytes_sent - bytes_read); ready = PR_Recv( stack, buffer + bytes_read, bytes_sent - bytes_read, empty_flags, PR_INTERVAL_NO_TIMEOUT); - if (0 < ready) - { - bytes_read += ready; - } + if (verbosity > chatty) + PR_fprintf( + logFile, "Client receive status [%d]\n", ready); + if (0 < ready) bytes_read += ready; else if ((-1 == ready) && (PR_WOULD_BLOCK_ERROR == PR_GetError())) { polldesc.fd = stack; polldesc.out_flags = 0; polldesc.in_flags = PR_POLL_READ; ready = PR_Poll(&polldesc, 1, PR_INTERVAL_NO_TIMEOUT); - if (1 != ready) break; /* if not 1, then we're dead */ + if ((1 != ready) /* if not 1, then we're dead */ + || (0 == (polldesc.in_flags & polldesc.out_flags))) + { PR_ASSERT(!"Whoa!"); break; } } else break; } while (bytes_read < bytes_sent); @@ -200,14 +215,20 @@ static void PR_CALLBACK Server(void *arg) do { + if (verbosity > chatty) + PR_fprintf(logFile, "Server accepting connection\n"); service = PR_Accept(stack, &client_address, PR_INTERVAL_NO_TIMEOUT); + if (verbosity > chatty) + PR_fprintf(logFile, "Server accept status [0x%p]\n", service); if ((NULL == service) && (PR_WOULD_BLOCK_ERROR == PR_GetError())) { polldesc.fd = stack; polldesc.out_flags = 0; - polldesc.in_flags = PR_POLL_READ; + polldesc.in_flags = PR_POLL_READ | PR_POLL_EXCEPT; ready = PR_Poll(&polldesc, 1, PR_INTERVAL_NO_TIMEOUT); - if (1 != ready) break; /* if not 1, then we're dead */ + if ((1 != ready) /* if not 1, then we're dead */ + || (0 == (polldesc.in_flags & polldesc.out_flags))) + { PR_ASSERT(!"Whoa!"); break; } } } while (NULL == service); PR_ASSERT(NULL != service); @@ -220,20 +241,25 @@ static void PR_CALLBACK Server(void *arg) bytes_read = 0; do { + if (verbosity > chatty) + PR_fprintf( + logFile, "Server receiving %d bytes\n", + sizeof(buffer) - bytes_read); ready = PR_Recv( service, buffer + bytes_read, sizeof(buffer) - bytes_read, empty_flags, PR_INTERVAL_NO_TIMEOUT); - if (0 < ready) - { - bytes_read += ready; - } + if (verbosity > chatty) + PR_fprintf(logFile, "Server receive status [%d]\n", ready); + if (0 < ready) bytes_read += ready; else if ((-1 == ready) && (PR_WOULD_BLOCK_ERROR == PR_GetError())) { polldesc.fd = service; polldesc.out_flags = 0; polldesc.in_flags = PR_POLL_READ; ready = PR_Poll(&polldesc, 1, PR_INTERVAL_NO_TIMEOUT); - if (1 != ready) break; /* if not 1, then we're dead */ + if ((1 != ready) /* if not 1, then we're dead */ + || (0 == (polldesc.in_flags & polldesc.out_flags))) + { PR_ASSERT(!"Whoa!"); break; } } else break; } while (bytes_read < sizeof(buffer)); @@ -260,7 +286,9 @@ static void PR_CALLBACK Server(void *arg) polldesc.out_flags = 0; polldesc.in_flags = PR_POLL_WRITE; ready = PR_Poll(&polldesc, 1, PR_INTERVAL_NO_TIMEOUT); - if (1 != ready) break; /* if not 1, then we're dead */ + if ((1 != ready) /* if not 1, then we're dead */ + || (0 == (polldesc.in_flags & polldesc.out_flags))) + { PR_ASSERT(!"Whoa!"); break; } } else break; } while (bytes_sent < bytes_read); @@ -331,7 +359,6 @@ static PRInt32 PR_CALLBACK MyRecv( { char *b; PRInt32 rv; - PRPollDesc polldesc; PRFileDesc *lo = fd->lower; PRFilePrivate *mine = (PRFilePrivate*)fd->secret; diff --git a/pr/tests/op_filok.c b/pr/tests/op_filok.c index dc17efea..ae540ac7 100644 --- a/pr/tests/op_filok.c +++ b/pr/tests/op_filok.c @@ -42,31 +42,42 @@ #else #endif -static PRFileDesc *t1; +/* + * The name of a file that is guaranteed to exist + * on every machine of a particular OS. + */ +#ifdef XP_UNIX +#define EXISTING_FILENAME "/bin/sh" +#elif defined(WIN32) +#define EXISTING_FILENAME "c:/boot.ini" +#else +#error "Unknown OS" +#endif -PRIntn error_code; +static PRFileDesc *t1; int main(int argc, char **argv) { - #ifdef XP_MAC SetupMacPrintfLog("pr_open_re.log"); #endif - - PR_STDIO_INIT(); - t1 = PR_Open("/usr/tmp/ttools/nspr20/err03.tmp", PR_TRUNCATE | PR_RDWR, 0666); + t1 = PR_Open(EXISTING_FILENAME, PR_RDONLY, 0666); if (t1 == NULL) { - if (PR_GetError() == PR_FILE_NOT_FOUND_ERROR) { - printf ("error code is %d \n", PR_GetError()); - printf ("File should be found\n"); + printf ("error code is %d \n", PR_GetError()); + printf ("File %s should be found\n", + EXISTING_FILENAME); + return 1; + } else { + if (PR_Close(t1) == PR_SUCCESS) { + printf ("Test passed \n"); + return 0; + } else { + printf ("cannot close file\n"); + printf ("error code is %d\n", PR_GetError()); return 1; } } - else { - printf ("Test passed \n"); - return 0; - } } diff --git a/pr/tests/op_noacc.c b/pr/tests/op_noacc.c index c528dc75..b45fce2e 100644 --- a/pr/tests/op_noacc.c +++ b/pr/tests/op_noacc.c @@ -54,6 +54,10 @@ int main(int argc, char **argv) SetupMacPrintfLog("pr_open_re.log"); #endif +#ifdef XP_PC + printf("op_noacc: Test not valid on MS-Windows.\n\tNo concept of 'mode' on Open() call\n"); + return(0); +#endif PR_STDIO_INIT(); diff --git a/pr/tests/op_nofil.c b/pr/tests/op_nofil.c index c38063ff..3cb3adef 100644 --- a/pr/tests/op_nofil.c +++ b/pr/tests/op_nofil.c @@ -43,31 +43,38 @@ #else #endif +/* + * A file name that cannot exist + */ +#define NO_SUCH_FILE "/no/such/file.tmp" + static PRFileDesc *t1; -PRIntn error_code; int main(int argc, char **argv) { - #ifdef XP_MAC SetupMacPrintfLog("pr_open_re.log"); #endif - - PR_STDIO_INIT(); - t1 = PR_Open("/usr/tmp/err02.tmp", PR_RDWR, 0666); - if (t1 == NULL) + t1 = PR_Open(NO_SUCH_FILE, PR_RDONLY, 0666); + if (t1 == NULL) { if (PR_GetError() == PR_FILE_NOT_FOUND_ERROR) { - - printf ("error code is %d \n", PR_GetError()); - printf ("PASS\n"); - return 0; - } - else { - printf ("error code is %d \n", PR_GetError()); - printf ("FAIL\n"); - return 1; + printf ("error code is PR_FILE_NOT_FOUND_ERROR, as expected\n"); + printf ("PASS\n"); + return 0; + } else { + printf ("error code is %d \n", PR_GetError()); + printf ("FAIL\n"); + return 1; } + } + printf ("File %s exists on this machine!?\n", NO_SUCH_FILE); + if (PR_Close(t1) == PR_FAILURE) { + printf ("cannot close file\n"); + printf ("error code is %d \n", PR_GetError()); + } + printf ("FAIL\n"); + return 1; } diff --git a/pr/tests/parent.c b/pr/tests/parent.c index 4e82b8b0..d5fef9ec 100644 --- a/pr/tests/parent.c +++ b/pr/tests/parent.c @@ -26,6 +26,7 @@ #include "prprf.h" #include "prinit.h" #include "prproces.h" +#include "prinrval.h" typedef struct Child { @@ -44,6 +45,7 @@ PRIntn main (PRIntn argc, char **argv) { PRStatus rv; PRInt32 test_status = 1; + PRIntervalTime t_start, t_elapsed; PRFileDesc *debug = NULL; Child *child = PR_NEWZAP(Child); @@ -83,14 +85,22 @@ PRIntn main (PRIntn argc, char **argv) child->attr, PR_StandardError, PR_GetSpecialFD(PR_StandardError)); + t_start = PR_IntervalNow(); child->process = PR_CreateProcess( child->name, argv, NULL, child->attr); + t_elapsed = (PRIntervalTime) (PR_IntervalNow() - t_start); test_status = (NULL == child->process) ? 1 : 0; if (NULL != debug) + { PR_fprintf( debug, "Child was %sforked\n", (0 == test_status) ? "" : "NOT "); + if (0 == test_status) + PR_fprintf( + debug, "PR_CreateProcess took %lu microseconds\n", + PR_IntervalToMicroseconds(t_elapsed)); + } if (0 == test_status) { diff --git a/pr/tests/perf.c b/pr/tests/perf.c index 5928052f..b6785d75 100644 --- a/pr/tests/perf.c +++ b/pr/tests/perf.c @@ -67,6 +67,26 @@ static void DLLProcedureCall(void) } } +static void Now(void) +{ + PRInt32 i; + PRTime time; + + for (i = 0; i < count; i++) { + time = PR_Now(); + } +} + +static void Interval(void) +{ + PRInt32 i; + PRIntervalTime time; + + for (i = 0; i < count; i++) { + time = PR_IntervalNow(); + } +} + static void IdleLock(void) { PRInt32 i; @@ -399,6 +419,8 @@ int main(int argc, char **argv) Measure(LocalProcedureCall, "local procedure call overhead"); Measure(DLLProcedureCall, "DLL procedure call overhead"); + Measure(Now, "current calendar time"); + Measure(Interval, "interval time"); Measure(IdleLock, "idle lock lock/unlock pair"); Measure(IdleMonitor, "idle monitor entry/exit pair"); Measure(IdleCMonitor, "idle cache monitor entry/exit pair"); @@ -420,6 +442,8 @@ int main(int argc, char **argv) Measure(LocalProcedureCall, "local procedure call overhead"); Measure(DLLProcedureCall, "DLL procedure call overhead"); + Measure(Now, "current calendar time"); + Measure(Interval, "interval time"); Measure(IdleLock, "idle lock lock/unlock pair"); Measure(IdleMonitor, "idle monitor entry/exit pair"); Measure(IdleCMonitor, "idle cache monitor entry/exit pair"); diff --git a/pr/tests/poll_nm.c b/pr/tests/poll_nm.c index a8995b3b..ab5c5286 100644 --- a/pr/tests/poll_nm.c +++ b/pr/tests/poll_nm.c @@ -89,7 +89,7 @@ clientThreadFunc(void *arg) addr.inet.port = PR_htons((PRUint16)port); addr.inet.ip = PR_htonl(PR_INADDR_LOOPBACK); memset(buf, 0, sizeof(buf)); - PR_snprintf(buf, sizeof(buf), "%hu", addr.inet.ip); + PR_snprintf(buf, sizeof(buf), "%hu", port); for (i = 0; i < NUM_ITERATIONS; i++) { sock = PR_NewTCPSocket(); diff --git a/pr/tests/pollable.c b/pr/tests/pollable.c new file mode 100644 index 00000000..f31d8a93 --- /dev/null +++ b/pr/tests/pollable.c @@ -0,0 +1,273 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "NPL"); you may not use this file except in + * compliance with the NPL. You may obtain a copy of the NPL at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the NPL is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL + * for the specific language governing rights and limitations under the + * NPL. + * + * The Initial Developer of this code under the NPL is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All Rights + * Reserved. + */ + +/* + * A test for the pollable events. + * + * A number of threads are in a ring configuration, each waiting on + * a pollable event that is set by its upstream neighbor. + */ + +#include "prinit.h" +#include "prio.h" +#include "prthread.h" +#include "prerror.h" +#include "prmem.h" +#include "prlog.h" +#include "prprf.h" + +#include "plgetopt.h" + +#include <stdlib.h> + +#define DEFAULT_THREADS 10 +#define DEFAULT_LOOPS 100 + +PRIntn numThreads = DEFAULT_THREADS; +PRIntn numIterations = DEFAULT_LOOPS; +PRIntervalTime dally = PR_INTERVAL_NO_WAIT; +PRFileDesc *debug_out = NULL; +PRBool debug_mode = PR_FALSE; +PRBool verbosity = PR_FALSE; + +typedef struct ThreadData { + PRFileDesc *event; + int index; + struct ThreadData *next; +} ThreadData; + +void ThreadRoutine(void *arg) +{ + ThreadData *data = (ThreadData *) arg; + PRIntn i; + PRPollDesc pd; + PRInt32 rv; + + pd.fd = data->event; + pd.in_flags = PR_POLL_READ; + + for (i = 0; i < numIterations; i++) { + rv = PR_Poll(&pd, 1, PR_INTERVAL_NO_TIMEOUT); + if (rv == -1) { + PR_fprintf(PR_STDERR, "PR_Poll failed\n"); + exit(1); + } + if (verbosity) { + PR_fprintf(debug_out, "thread %d awakened\n", data->index); + } + PR_ASSERT(rv != 0); + PR_ASSERT(pd.out_flags & PR_POLL_READ); + if (PR_WaitForPollableEvent(data->event) == PR_FAILURE) { + PR_fprintf(PR_STDERR, "consume event failed\n"); + exit(1); + } + if (dally != PR_INTERVAL_NO_WAIT) { + PR_Sleep(dally); + } + if (verbosity) { + PR_fprintf(debug_out, "thread %d posting event\n", data->index); + } + if (PR_SetPollableEvent(data->next->event) == PR_FAILURE) { + PR_fprintf(PR_STDERR, "post event failed\n"); + exit(1); + } + } +} + +static void Help(void) +{ + debug_out = PR_STDOUT; + + PR_fprintf( + debug_out, "Usage: pollable [-c n] [-t n] [-d] [-v] [-G] [-C n] [-D n]\n"); + PR_fprintf( + debug_out, "-c n\tloops at thread level (default: %d)\n", DEFAULT_LOOPS); + PR_fprintf( + debug_out, "-t n\tnumber of threads (default: %d)\n", DEFAULT_THREADS); + PR_fprintf(debug_out, "-d\tturn on debugging output (default: FALSE)\n"); + PR_fprintf(debug_out, "-v\tturn on verbose output (default: FALSE)\n"); + PR_fprintf(debug_out, "-G\tglobal threads only (default: FALSE)\n"); + PR_fprintf(debug_out, "-C n\tconcurrency setting (default: 1)\n"); + PR_fprintf(debug_out, "-D n\tdally setting (msecs) (default: 0)\n"); +} /* Help */ + +int main(int argc, char **argv) +{ + ThreadData selfData; + ThreadData *data; + PRThread **thread; + void *block; + PRIntn i; + PRIntervalTime timeStart, timeEnd; + PRPollDesc pd; + PRInt32 rv; + PRThreadScope thread_scope = PR_LOCAL_THREAD; + PRBool help = PR_FALSE; + PRUintn concurrency = 1; + PRUintn average; + PLOptStatus os; + PLOptState *opt; + + PR_STDIO_INIT(); + + opt = PL_CreateOptState(argc, argv, "hdvc:t:C:GD:"); + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) { + if (PL_OPT_BAD == os) { + continue; + } + switch (opt->option) { + case 'v': /* verbose mode */ + verbosity = PR_TRUE; + case 'd': /* debug mode */ + debug_mode = PR_TRUE; + break; + case 'c': /* loop counter */ + numIterations = atoi(opt->value); + break; + case 't': /* thread limit */ + numThreads = atoi(opt->value); + break; + case 'C': /* Concurrency limit */ + concurrency = atoi(opt->value); + break; + case 'G': /* global threads only */ + thread_scope = PR_GLOBAL_THREAD; + break; + case 'D': /* dally */ + dally = PR_MillisecondsToInterval(atoi(opt->value)); + break; + case 'h': /* help message */ + Help(); + help = PR_TRUE; + break; + default: + break; + } + } + PL_DestroyOptState(opt); + + if (help) { + return 1; + } + + if (concurrency > 1) { + PR_SetConcurrency(concurrency); + } + + if (PR_TRUE == debug_mode) { + debug_out = PR_STDOUT; + PR_fprintf(debug_out, "Test parameters\n"); + PR_fprintf(debug_out, "\tThreads involved: %d\n", numThreads); + PR_fprintf(debug_out, "\tIteration limit: %d\n", numIterations); + PR_fprintf(debug_out, "\tConcurrency: %d\n", concurrency); + PR_fprintf(debug_out, "\tThread type: %s\n", + (PR_GLOBAL_THREAD == thread_scope) ? "GLOBAL" : "LOCAL"); + } + + /* + * Malloc a block of memory and divide it into data and thread. + */ + block = PR_MALLOC(numThreads * (sizeof(ThreadData) + sizeof(PRThread *))); + if (block == NULL) { + PR_fprintf(PR_STDERR, "cannot malloc, failed\n"); + exit(1); + } + data = (ThreadData *) block; + thread = (PRThread **) &data[numThreads]; + + /* Pollable event */ + selfData.event = PR_NewPollableEvent(); + if (selfData.event == NULL) { + PR_fprintf(PR_STDERR, "cannot create event: (%ld, %ld)\n", + PR_GetError(), PR_GetOSError()); + exit(1); + } + selfData.next = &data[0]; + for (i = 0; i < numThreads; i++) { + data[i].event = PR_NewPollableEvent(); + if (data[i].event == NULL) { + PR_fprintf(PR_STDERR, "cannot create event: (%ld, %ld)\n", + PR_GetError(), PR_GetOSError()); + exit(1); + } + data[i].index = i; + if (i != numThreads - 1) { + data[i].next = &data[i + 1]; + } else { + data[i].next = &selfData; + } + + thread[i] = PR_CreateThread(PR_USER_THREAD, + ThreadRoutine, &data[i], PR_PRIORITY_NORMAL, + thread_scope, PR_JOINABLE_THREAD, 0); + if (thread[i] == NULL) { + PR_fprintf(PR_STDERR, "cannot create thread\n"); + exit(1); + } + } + + timeStart = PR_IntervalNow(); + pd.fd = selfData.event; + pd.in_flags = PR_POLL_READ; + for (i = 0; i < numIterations; i++) { + if (dally != PR_INTERVAL_NO_WAIT) { + PR_Sleep(dally); + } + if (verbosity) { + PR_fprintf(debug_out, "main thread posting event\n"); + } + if (PR_SetPollableEvent(selfData.next->event) == PR_FAILURE) { + PR_fprintf(PR_STDERR, "set event failed\n"); + exit(1); + } + rv = PR_Poll(&pd, 1, PR_INTERVAL_NO_TIMEOUT); + if (rv == -1) { + PR_fprintf(PR_STDERR, "wait failed\n"); + exit(1); + } + PR_ASSERT(rv != 0); + PR_ASSERT(pd.out_flags & PR_POLL_READ); + if (verbosity) { + PR_fprintf(debug_out, "main thread awakened\n"); + } + if (PR_WaitForPollableEvent(selfData.event) == PR_FAILURE) { + PR_fprintf(PR_STDERR, "consume event failed\n"); + exit(1); + } + } + timeEnd = PR_IntervalNow(); + + if (debug_mode) { + average = PR_IntervalToMicroseconds(timeEnd - timeStart) + / (numIterations * numThreads); + PR_fprintf(debug_out, "Average switch times %d usecs for %d threads\n", + average, numThreads); + } + + for (i = 0; i < numThreads; i++) { + if (PR_JoinThread(thread[i]) == PR_FAILURE) { + PR_fprintf(PR_STDERR, "join thread failed\n"); + exit(1); + } + PR_DestroyPollableEvent(data[i].event); + } + PR_DELETE(block); + + PR_fprintf(PR_STDOUT, "PASSED\n"); + return 0; +} diff --git a/pr/tests/prftest2.c b/pr/tests/prftest2.c index b5322888..c3239905 100644 --- a/pr/tests/prftest2.c +++ b/pr/tests/prftest2.c @@ -105,6 +105,6 @@ int main( int argc, char *argv[]) else { printf("PASSED\n"); - return 1; + return 0; } } diff --git a/pr/tests/priotest.c b/pr/tests/priotest.c index cdc76953..f9df1528 100644 --- a/pr/tests/priotest.c +++ b/pr/tests/priotest.c @@ -42,7 +42,7 @@ #include <stdio.h> #include <stdlib.h> -#define DEFAULT_DURATION 20 +#define DEFAULT_DURATION 5 static PRBool failed = PR_FALSE; static PRIntervalTime oneSecond; @@ -131,7 +131,7 @@ static void RudimentaryTests(void) } /* RudimentataryTests */ -static void CreateThreads(PRInt32 *lowCount, PRInt32 *highCount) +static void CreateThreads(PRUint32 *lowCount, PRUint32 *highCount) { (void)PR_CreateThread( PR_USER_THREAD, Low, lowCount, PR_PRIORITY_LOW, diff --git a/pr/tests/provider.c b/pr/tests/provider.c new file mode 100644 index 00000000..49428b3a --- /dev/null +++ b/pr/tests/provider.c @@ -0,0 +1,1356 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "NPL"); you may not use this file except in + * compliance with the NPL. You may obtain a copy of the NPL at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the NPL is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL + * for the specific language governing rights and limitations under the + * NPL. + * + * The Initial Developer of this code under the NPL is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All Rights + * Reserved. + */ + +/* + * + * Notes: + * [1] lth. The call to Sleep() is a hack to get the test case to run + * on Windows 95. Without it, the test case fails with an error + * WSAECONNRESET following a recv() call. The error is caused by the + * server side thread termination without a shutdown() or closesocket() + * call. Windows docmunentation suggests that this is predicted + * behavior; that other platforms get away with it is ... serindipity. + * The test case should shutdown() or closesocket() before + * thread termination. I didn't have time to figure out where or how + * to do it. The Sleep() call inserts enough delay to allow the + * client side to recv() all his data before the server side thread + * terminates. Whew! ... + * + ** Modification History: + * 14-May-97 AGarcia- Converted the test to accomodate the debug_mode flag. + * The debug mode will print all of the printfs associated with this test. + * The regress mode will be the default mode. Since the regress tool limits + * the output to a one line status:PASS or FAIL,all of the printf statements + * have been handled with an if (debug_mode) statement. + */ + +#include "prclist.h" +#include "prcvar.h" +#include "prerror.h" +#include "prinit.h" +#include "prinrval.h" +#include "prio.h" +#include "prlock.h" +#include "prlog.h" +#include "prtime.h" +#include "prmem.h" +#include "prnetdb.h" +#include "prprf.h" +#include "prthread.h" + +#include "pprio.h" +#include "primpl.h" + +#include "plstr.h" +#include "plerror.h" +#include "plgetopt.h" + +#include <stdlib.h> +#include <string.h> + + +#if defined(XP_UNIX) +#include <math.h> +#endif + +#ifdef XP_MAC +#include "prlog.h" +#define printf PR_LogPrint +#endif + +/* +** This is the beginning of the test +*/ + +#define RECV_FLAGS 0 +#define SEND_FLAGS 0 +#define BUFFER_SIZE 1024 +#define DEFAULT_BACKLOG 5 +#define DEFAULT_PORT 12848 +#define DEFAULT_CLIENTS 1 +#define ALLOWED_IN_ACCEPT 1 +#define DEFAULT_CLIPPING 1000 +#define DEFAULT_WORKERS_MIN 1 +#define DEFAULT_WORKERS_MAX 1 +#define DEFAULT_SERVER "localhost" +#define DEFAULT_EXECUTION_TIME 10 +#define DEFAULT_CLIENT_TIMEOUT 4000 +#define DEFAULT_SERVER_TIMEOUT 4000 +#define DEFAULT_SERVER_PRIORITY PR_PRIORITY_HIGH + +typedef enum CSState_e {cs_init, cs_run, cs_stop, cs_exit} CSState_t; + +static void PR_CALLBACK Worker(void *arg); +typedef struct CSPool_s CSPool_t; +typedef struct CSWorker_s CSWorker_t; +typedef struct CSServer_s CSServer_t; +typedef enum Verbosity +{ + TEST_LOG_ALWAYS, + TEST_LOG_ERROR, + TEST_LOG_WARNING, + TEST_LOG_NOTICE, + TEST_LOG_INFO, + TEST_LOG_STATUS, + TEST_LOG_VERBOSE +} Verbosity; + +static enum { + thread_nspr, thread_pthread, thread_sproc, thread_win32 +} thread_provider; + +static PRInt32 domain = AF_INET; +static PRInt32 protocol = 6; /* TCP */ +static PRFileDesc *debug_out = NULL; +static PRBool debug_mode = PR_FALSE; +static PRBool pthread_stats = PR_FALSE; +static Verbosity verbosity = TEST_LOG_ALWAYS; +static PRThreadScope thread_scope = PR_LOCAL_THREAD; + +struct CSWorker_s +{ + PRCList element; /* list of the server's workers */ + + PRThread *thread; /* this worker objects thread */ + CSServer_t *server; /* back pointer to server structure */ +}; + +struct CSPool_s +{ + PRCondVar *exiting; + PRCondVar *acceptComplete; + PRUint32 accepting, active, workers; +}; + +struct CSServer_s +{ + PRCList list; /* head of worker list */ + + PRLock *ml; + PRThread *thread; /* the main server thread */ + PRCondVar *stateChange; + + PRUint16 port; /* port we're listening on */ + PRUint32 backlog; /* size of our listener backlog */ + PRFileDesc *listener; /* the fd accepting connections */ + + CSPool_t pool; /* statistics on worker threads */ + CSState_t state; /* the server's state */ + struct /* controlling worker counts */ + { + PRUint32 minimum, maximum, accepting; + } workers; + + /* statistics */ + PRIntervalTime started, stopped; + PRUint32 operations, bytesTransferred; +}; + +typedef struct CSDescriptor_s +{ + PRInt32 size; /* size of transfer */ + char filename[60]; /* filename, null padded */ +} CSDescriptor_t; + +typedef struct CSClient_s +{ + PRLock *ml; + PRThread *thread; + PRCondVar *stateChange; + PRNetAddr serverAddress; + + CSState_t state; + + /* statistics */ + PRIntervalTime started, stopped; + PRUint32 operations, bytesTransferred; +} CSClient_t; + +#define TEST_LOG(l, p, a) \ + do { \ + if (debug_mode || (p <= verbosity)) printf a; \ + } while (0) + +PRLogModuleInfo *cltsrv_log_file = NULL; + +#define MY_ASSERT(_expr) \ + ((_expr)?((void)0):_MY_Assert(# _expr,__FILE__,__LINE__)) + +#define TEST_ASSERT(_expr) \ + ((_expr)?((void)0):_MY_Assert(# _expr,__FILE__,__LINE__)) + +static void _MY_Assert(const char *s, const char *file, PRIntn ln) +{ + PL_PrintError(NULL); +#if DEBUG + PR_Assert(s, file, ln); +#endif +} /* _MW_Assert */ + +static PRBool Aborted(PRStatus rv) +{ + return ((PR_FAILURE == rv) && (PR_PENDING_INTERRUPT_ERROR == PR_GetError())) ? + PR_TRUE : PR_FALSE; +} + +static void TimeOfDayMessage(const char *msg, PRThread* me) +{ + char buffer[100]; + PRExplodedTime tod; + PR_ExplodeTime(PR_Now(), PR_LocalTimeParameters, &tod); + (void)PR_FormatTime(buffer, sizeof(buffer), "%T", &tod); + + TEST_LOG( + cltsrv_log_file, TEST_LOG_ALWAYS, + ("%s(0x%p): %s\n", msg, me, buffer)); +} /* TimeOfDayMessage */ + + +static void PR_CALLBACK Client(void *arg) +{ + PRStatus rv; + PRIntn index; + char buffer[1024]; + PRFileDesc *fd = NULL; + PRUintn clipping = DEFAULT_CLIPPING; + CSClient_t *client = (CSClient_t*)arg; + PRThread *me = client->thread = PR_CurrentThread(); + CSDescriptor_t *descriptor = PR_NEW(CSDescriptor_t); + PRIntervalTime timeout = PR_MillisecondsToInterval(DEFAULT_CLIENT_TIMEOUT); + + + for (index = 0; index < sizeof(buffer); ++index) + buffer[index] = (char)index; + + client->started = PR_IntervalNow(); + + PR_Lock(client->ml); + client->state = cs_run; + PR_NotifyCondVar(client->stateChange); + PR_Unlock(client->ml); + + TimeOfDayMessage("Client started at", me); + + while (cs_run == client->state) + { + PRInt32 bytes, descbytes, filebytes, netbytes; + + (void)PR_NetAddrToString(&client->serverAddress, buffer, sizeof(buffer)); + TEST_LOG(cltsrv_log_file, TEST_LOG_INFO, + ("\tClient(0x%p): connecting to server at %s\n", me, buffer)); + + fd = PR_Socket(domain, SOCK_STREAM, protocol); + TEST_ASSERT(NULL != fd); + rv = PR_Connect(fd, &client->serverAddress, timeout); + if (PR_FAILURE == rv) + { + TEST_LOG( + cltsrv_log_file, TEST_LOG_ERROR, + ("\tClient(0x%p): conection failed\n", me)); + goto aborted; + } + + memset(descriptor, 0, sizeof(*descriptor)); + descriptor->size = PR_htonl(descbytes = rand() % clipping); + PR_snprintf( + descriptor->filename, sizeof(descriptor->filename), + "CS%p%p-%p.dat", client->started, me, client->operations); + TEST_LOG( + cltsrv_log_file, TEST_LOG_VERBOSE, + ("\tClient(0x%p): sending descriptor for %u bytes\n", me, descbytes)); + bytes = PR_Send( + fd, descriptor, sizeof(*descriptor), SEND_FLAGS, timeout); + if (sizeof(CSDescriptor_t) != bytes) + { + if (Aborted(PR_FAILURE)) goto aborted; + if (PR_IO_TIMEOUT_ERROR == PR_GetError()) + { + TEST_LOG( + cltsrv_log_file, TEST_LOG_ERROR, + ("\tClient(0x%p): send descriptor timeout\n", me)); + goto retry; + } + } + TEST_ASSERT(sizeof(*descriptor) == bytes); + + netbytes = 0; + while (netbytes < descbytes) + { + filebytes = sizeof(buffer); + if ((descbytes - netbytes) < filebytes) + filebytes = descbytes - netbytes; + TEST_LOG( + cltsrv_log_file, TEST_LOG_VERBOSE, + ("\tClient(0x%p): sending %d bytes\n", me, filebytes)); + bytes = PR_Send(fd, buffer, filebytes, SEND_FLAGS, timeout); + if (filebytes != bytes) + { + if (Aborted(PR_FAILURE)) goto aborted; + if (PR_IO_TIMEOUT_ERROR == PR_GetError()) + { + TEST_LOG( + cltsrv_log_file, TEST_LOG_ERROR, + ("\tClient(0x%p): send data timeout\n", me)); + goto retry; + } + } + TEST_ASSERT(bytes == filebytes); + netbytes += bytes; + } + filebytes = 0; + while (filebytes < descbytes) + { + netbytes = sizeof(buffer); + if ((descbytes - filebytes) < netbytes) + netbytes = descbytes - filebytes; + TEST_LOG( + cltsrv_log_file, TEST_LOG_VERBOSE, + ("\tClient(0x%p): receiving %d bytes\n", me, netbytes)); + bytes = PR_Recv(fd, buffer, netbytes, RECV_FLAGS, timeout); + if (-1 == bytes) + { + if (Aborted(PR_FAILURE)) + { + TEST_LOG( + cltsrv_log_file, TEST_LOG_ERROR, + ("\tClient(0x%p): receive data aborted\n", me)); + goto aborted; + } + else if (PR_IO_TIMEOUT_ERROR == PR_GetError()) + TEST_LOG( + cltsrv_log_file, TEST_LOG_ERROR, + ("\tClient(0x%p): receive data timeout\n", me)); + else + TEST_LOG( + cltsrv_log_file, TEST_LOG_ERROR, + ("\tClient(0x%p): receive error (%d, %d)\n", + me, PR_GetError(), PR_GetOSError())); + goto retry; + } + if (0 == bytes) + { + TEST_LOG( + cltsrv_log_file, TEST_LOG_ERROR, + ("\t\tClient(0x%p): unexpected end of stream\n", + PR_CurrentThread())); + break; + } + filebytes += bytes; + } + + rv = PR_Shutdown(fd, PR_SHUTDOWN_BOTH); + if (Aborted(rv)) goto aborted; + TEST_ASSERT(PR_SUCCESS == rv); +retry: + (void)PR_Close(fd); fd = NULL; + TEST_LOG( + cltsrv_log_file, TEST_LOG_INFO, + ("\tClient(0x%p): disconnected from server\n", me)); + + PR_Lock(client->ml); + client->operations += 1; + client->bytesTransferred += 2 * descbytes; + rv = PR_WaitCondVar(client->stateChange, rand() % clipping); + PR_Unlock(client->ml); + if (Aborted(rv)) break; + } + +aborted: + client->stopped = PR_IntervalNow(); + + PR_ClearInterrupt(); + if (NULL != fd) rv = PR_Close(fd); + + PR_Lock(client->ml); + client->state = cs_exit; + PR_NotifyCondVar(client->stateChange); + PR_Unlock(client->ml); + PR_DELETE(descriptor); + TEST_LOG( + cltsrv_log_file, TEST_LOG_ALWAYS, + ("\tClient(0x%p): stopped after %u operations and %u bytes\n", + PR_CurrentThread(), client->operations, client->bytesTransferred)); + +} /* Client */ + +static PRStatus ProcessRequest(PRFileDesc *fd, CSServer_t *server) +{ + PRStatus drv, rv; + char buffer[1024]; + PRFileDesc *file = NULL; + PRThread * me = PR_CurrentThread(); + PRInt32 bytes, descbytes, netbytes, filebytes = 0; + CSDescriptor_t *descriptor = PR_NEW(CSDescriptor_t); + PRIntervalTime timeout = PR_MillisecondsToInterval(DEFAULT_SERVER_TIMEOUT); + + TEST_LOG( + cltsrv_log_file, TEST_LOG_VERBOSE, + ("\tProcessRequest(0x%p): receiving desciptor\n", me)); + bytes = PR_Recv( + fd, descriptor, sizeof(*descriptor), RECV_FLAGS, timeout); + if (-1 == bytes) + { + rv = PR_FAILURE; + if (Aborted(rv)) goto exit; + if (PR_IO_TIMEOUT_ERROR == PR_GetError()) + { + TEST_LOG( + cltsrv_log_file, TEST_LOG_ERROR, + ("\tProcessRequest(0x%p): receive timeout\n", me)); + } + goto exit; + } + if (0 == bytes) + { + rv = PR_FAILURE; + TEST_LOG( + cltsrv_log_file, TEST_LOG_ERROR, + ("\tProcessRequest(0x%p): unexpected end of file\n", me)); + goto exit; + } + descbytes = PR_ntohl(descriptor->size); + TEST_ASSERT(sizeof(*descriptor) == bytes); + + TEST_LOG( + cltsrv_log_file, TEST_LOG_VERBOSE, + ("\t\tProcessRequest(0x%p): read descriptor {%d, %s}\n", + me, descbytes, descriptor->filename)); + + file = PR_Open( + descriptor->filename, (PR_CREATE_FILE | PR_WRONLY), 0666); + if (NULL == file) + { + rv = PR_FAILURE; + if (Aborted(rv)) goto aborted; + if (PR_IO_TIMEOUT_ERROR == PR_GetError()) + { + TEST_LOG( + cltsrv_log_file, TEST_LOG_ERROR, + ("\tProcessRequest(0x%p): open file timeout\n", me)); + goto aborted; + } + } + TEST_ASSERT(NULL != file); + + filebytes = 0; + while (filebytes < descbytes) + { + netbytes = sizeof(buffer); + if ((descbytes - filebytes) < netbytes) + netbytes = descbytes - filebytes; + TEST_LOG( + cltsrv_log_file, TEST_LOG_VERBOSE, + ("\tProcessRequest(0x%p): receive %d bytes\n", me, netbytes)); + bytes = PR_Recv(fd, buffer, netbytes, RECV_FLAGS, timeout); + if (-1 == bytes) + { + rv = PR_FAILURE; + if (Aborted(rv)) goto aborted; + if (PR_IO_TIMEOUT_ERROR == PR_GetError()) + { + TEST_LOG( + cltsrv_log_file, TEST_LOG_ERROR, + ("\t\tProcessRequest(0x%p): receive data timeout\n", me)); + goto aborted; + } + /* + * XXX: I got (PR_CONNECT_RESET_ERROR, ERROR_NETNAME_DELETED) + * on NT here. This is equivalent to ECONNRESET on Unix. + * -wtc + */ + TEST_LOG( + cltsrv_log_file, TEST_LOG_WARNING, + ("\t\tProcessRequest(0x%p): unexpected error (%d, %d)\n", + me, PR_GetError(), PR_GetOSError())); + goto aborted; + } + if(0 == bytes) + { + TEST_LOG( + cltsrv_log_file, TEST_LOG_WARNING, + ("\t\tProcessRequest(0x%p): unexpected end of stream\n", me)); + rv = PR_FAILURE; + goto aborted; + } + filebytes += bytes; + netbytes = bytes; + /* The byte count for PR_Write should be positive */ + MY_ASSERT(netbytes > 0); + TEST_LOG( + cltsrv_log_file, TEST_LOG_VERBOSE, + ("\tProcessRequest(0x%p): write %d bytes to file\n", me, netbytes)); + bytes = PR_Write(file, buffer, netbytes); + if (netbytes != bytes) + { + rv = PR_FAILURE; + if (Aborted(rv)) goto aborted; + if (PR_IO_TIMEOUT_ERROR == PR_GetError()) + { + TEST_LOG( + cltsrv_log_file, TEST_LOG_ERROR, + ("\t\tProcessRequest(0x%p): write file timeout\n", me)); + goto aborted; + } + } + TEST_ASSERT(bytes > 0); + } + + PR_Lock(server->ml); + server->operations += 1; + server->bytesTransferred += filebytes; + PR_Unlock(server->ml); + + rv = PR_Close(file); file = NULL; + if (Aborted(rv)) goto aborted; + TEST_ASSERT(PR_SUCCESS == rv); + + TEST_LOG( + cltsrv_log_file, TEST_LOG_VERBOSE, + ("\t\tProcessRequest(0x%p): opening %s\n", me, descriptor->filename)); + file = PR_Open(descriptor->filename, PR_RDONLY, 0); + if (NULL == file) + { + rv = PR_FAILURE; + if (Aborted(rv)) goto aborted; + if (PR_IO_TIMEOUT_ERROR == PR_GetError()) + { + TEST_LOG( + cltsrv_log_file, TEST_LOG_ERROR, + ("\t\tProcessRequest(0x%p): open file timeout\n", + PR_CurrentThread())); + goto aborted; + } + TEST_LOG( + cltsrv_log_file, TEST_LOG_ERROR, + ("\t\tProcessRequest(0x%p): other file open error (%u, %u)\n", + me, PR_GetError(), PR_GetOSError())); + goto aborted; + } + TEST_ASSERT(NULL != file); + + netbytes = 0; + while (netbytes < descbytes) + { + filebytes = sizeof(buffer); + if ((descbytes - netbytes) < filebytes) + filebytes = descbytes - netbytes; + TEST_LOG( + cltsrv_log_file, TEST_LOG_VERBOSE, + ("\tProcessRequest(0x%p): read %d bytes from file\n", me, filebytes)); + bytes = PR_Read(file, buffer, filebytes); + if (filebytes != bytes) + { + rv = PR_FAILURE; + if (Aborted(rv)) goto aborted; + if (PR_IO_TIMEOUT_ERROR == PR_GetError()) + TEST_LOG( + cltsrv_log_file, TEST_LOG_ERROR, + ("\t\tProcessRequest(0x%p): read file timeout\n", me)); + else + TEST_LOG( + cltsrv_log_file, TEST_LOG_ERROR, + ("\t\tProcessRequest(0x%p): other file error (%d, %d)\n", + me, PR_GetError(), PR_GetOSError())); + goto aborted; + } + TEST_ASSERT(bytes > 0); + netbytes += bytes; + filebytes = bytes; + TEST_LOG( + cltsrv_log_file, TEST_LOG_VERBOSE, + ("\t\tProcessRequest(0x%p): sending %d bytes\n", me, filebytes)); + bytes = PR_Send(fd, buffer, filebytes, SEND_FLAGS, timeout); + if (filebytes != bytes) + { + rv = PR_FAILURE; + if (Aborted(rv)) goto aborted; + if (PR_IO_TIMEOUT_ERROR == PR_GetError()) + { + TEST_LOG( + cltsrv_log_file, TEST_LOG_ERROR, + ("\t\tProcessRequest(0x%p): send data timeout\n", me)); + goto aborted; + } + break; + } + TEST_ASSERT(bytes > 0); + } + + PR_Lock(server->ml); + server->bytesTransferred += filebytes; + PR_Unlock(server->ml); + + rv = PR_Shutdown(fd, PR_SHUTDOWN_BOTH); + if (Aborted(rv)) goto aborted; + + rv = PR_Close(file); file = NULL; + if (Aborted(rv)) goto aborted; + TEST_ASSERT(PR_SUCCESS == rv); + +aborted: + PR_ClearInterrupt(); + if (NULL != file) PR_Close(file); + drv = PR_Delete(descriptor->filename); + TEST_ASSERT(PR_SUCCESS == drv); +exit: + TEST_LOG( + cltsrv_log_file, TEST_LOG_VERBOSE, + ("\t\tProcessRequest(0x%p): Finished\n", me)); + + PR_DELETE(descriptor); + +#if defined(WIN95) + PR_Sleep(PR_MillisecondsToInterval(200)); /* lth. see note [1] */ +#endif + return rv; +} /* ProcessRequest */ + +typedef void (*StartFn)(void*); +typedef struct StartObject +{ + StartFn start; + void *arg; +} StartObject; + +#if defined(_PR_PTHREADS) && !defined(_PR_DCETHREADS) +#include "md/_pth.h" +#include <pthread.h> + +static void *pthread_start(void *arg) +{ + StartObject *so = (StartObject*)arg; + StartFn start = so->start; + void *data = so->arg; + PR_Free(so); + start(data); + return NULL; +} /* pthread_start */ +#endif /* defined(_PR_PTHREADS) && !defined(_PR_DCETHREADS) */ + +#if defined(IRIX) && !defined(_PR_PTHREADS) +#include <sys/types.h> +#include <sys/prctl.h> +static void sproc_start(void *arg, PRSize size) +{ + StartObject *so = (StartObject*)arg; + StartFn start = so->start; + void *data = so->arg; + PR_Free(so); + start(data); +} /* sproc_start */ +#endif /* defined(IRIX) && !defined(_PR_PTHREADS) */ + +#if defined(WIN32) +#include <process.h> /* for _beginthreadex() */ + +static PRUintn __stdcall windows_start(void *arg) +{ + StartObject *so = (StartObject*)arg; + StartFn start = so->start; + void *data = so->arg; + PR_Free(so); + start(data); + return 0; +} /* windows_start */ +#endif /* defined(WIN32) */ + +static PRStatus JoinThread(PRThread *thread) +{ + PRStatus rv; + switch (thread_provider) + { + case thread_nspr: + rv = PR_JoinThread(thread); + break; + case thread_pthread: +#if defined(_PR_PTHREADS) && !defined(_PR_DCETHREADS) + rv = PR_SUCCESS; + break; +#endif /* defined(_PR_PTHREADS) && !defined(_PR_DCETHREADS) */ + case thread_win32: +#if defined(WIN32) + rv = PR_SUCCESS; + break; +#endif + default: + rv = PR_FAILURE; + break; + } + return rv; +} /* JoinThread */ + +static PRStatus NewThread( + StartFn start, void *arg, PRThreadPriority prio, PRThreadState state) +{ + PRStatus rv; + + switch (thread_provider) + { + case thread_nspr: + { + PRThread *thread = PR_CreateThread( + PR_USER_THREAD, start, arg, + PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD, + PR_UNJOINABLE_THREAD, 0); + rv = (NULL == thread) ? PR_FAILURE : PR_SUCCESS; + } + break; + case thread_pthread: +#if defined(_PR_PTHREADS) && !defined(_PR_DCETHREADS) + { + int rv; + pthread_t id; + pthread_attr_t tattr; + StartObject *start_object; + start_object = PR_NEW(StartObject); + PR_ASSERT(NULL != start_object); + start_object->start = start; + start_object->arg = arg; + + rv = PTHREAD_ATTR_INIT(&tattr); + PR_ASSERT(0 == rv); + + rv = pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED); + PR_ASSERT(0 == rv); + +#if !defined(LINUX) + rv = pthread_attr_setstacksize(&tattr, 64 * 1024); + PR_ASSERT(0 == rv); +#endif + + rv = PTHREAD_CREATE(&id, tattr, pthread_start, start_object); + (void)PTHREAD_ATTR_DESTROY(&tattr); + return (0 == rv) ? PR_SUCCESS : PR_FAILURE; + } +#else + PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); + rv = PR_FAILURE; +#endif /* defined(_PR_PTHREADS) && !defined(_PR_DCETHREADS) */ + break; + + case thread_sproc: +#if defined(IRIX) && !defined(_PR_PTHREADS) + { + PRInt32 pid; + StartObject *start_object; + start_object = PR_NEW(StartObject); + PR_ASSERT(NULL != start_object); + start_object->start = start; + start_object->arg = arg; + pid = sprocsp( + sproc_start, PR_SALL, start_object, NULL, 64 * 1024); + rv = (0 < pid) ? PR_SUCCESS : PR_FAILURE; + } +#else + PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); + rv = PR_FAILURE; +#endif /* defined(IRIX) && !defined(_PR_PTHREADS) */ + break; + case thread_win32: +#if defined(WIN32) + { + void *th; + PRUintn id; + StartObject *start_object; + start_object = PR_NEW(StartObject); + PR_ASSERT(NULL != start_object); + start_object->start = start; + start_object->arg = arg; + th = (void*)_beginthreadex( + NULL, /* LPSECURITY_ATTRIBUTES - pointer to thread security attributes */ + 0U, /* DWORD - initial thread stack size, in bytes */ + windows_start, /* LPTHREAD_START_ROUTINE - pointer to thread function */ + start_object, /* LPVOID - argument for new thread */ + 0U, /*DWORD dwCreationFlags - creation flags */ + &id /* LPDWORD - pointer to returned thread identifier */ ); + + rv = (NULL == th) ? PR_FAILURE : PR_SUCCESS; + } +#else + PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); + rv = PR_FAILURE; +#endif + break; + default: + PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); + rv = PR_FAILURE; + } + return rv; +} /* NewThread */ + +static PRStatus CreateWorker(CSServer_t *server, CSPool_t *pool) +{ + PRStatus rv; + CSWorker_t *worker = PR_NEWZAP(CSWorker_t); + worker->server = server; + PR_INIT_CLIST(&worker->element); + rv = NewThread( + Worker, worker, DEFAULT_SERVER_PRIORITY, PR_UNJOINABLE_THREAD); + if (PR_FAILURE == rv) PR_DELETE(worker); + + TEST_LOG(cltsrv_log_file, TEST_LOG_STATUS, + ("\tCreateWorker(0x%p): create new worker (0x%p)\n", + PR_CurrentThread(), worker->thread)); + + return rv; +} /* CreateWorker */ + +static void PR_CALLBACK Worker(void *arg) +{ + PRStatus rv; + PRNetAddr from; + PRFileDesc *fd = NULL; + CSWorker_t *worker = (CSWorker_t*)arg; + CSServer_t *server = worker->server; + CSPool_t *pool = &server->pool; + + PRThread *me = worker->thread = PR_CurrentThread(); + + TEST_LOG( + cltsrv_log_file, TEST_LOG_NOTICE, + ("\t\tWorker(0x%p): started [%u]\n", me, pool->workers + 1)); + + PR_Lock(server->ml); + PR_APPEND_LINK(&worker->element, &server->list); + pool->workers += 1; /* define our existance */ + + while (cs_run == server->state) + { + while (pool->accepting >= server->workers.accepting) + { + TEST_LOG( + cltsrv_log_file, TEST_LOG_VERBOSE, + ("\t\tWorker(0x%p): waiting for accept slot[%d]\n", + me, pool->accepting)); + rv = PR_WaitCondVar(pool->acceptComplete, PR_INTERVAL_NO_TIMEOUT); + if (Aborted(rv) || (cs_run != server->state)) + { + TEST_LOG( + cltsrv_log_file, TEST_LOG_NOTICE, + ("\tWorker(0x%p): has been %s\n", + me, (Aborted(rv) ? "interrupted" : "stopped"))); + goto exit; + } + } + pool->accepting += 1; /* how many are really in accept */ + PR_Unlock(server->ml); + + TEST_LOG( + cltsrv_log_file, TEST_LOG_VERBOSE, + ("\t\tWorker(0x%p): calling accept\n", me)); + fd = PR_Accept(server->listener, &from, PR_INTERVAL_NO_TIMEOUT); + + PR_Lock(server->ml); + pool->accepting -= 1; + PR_NotifyCondVar(pool->acceptComplete); + + if ((NULL == fd) && Aborted(PR_FAILURE)) + { + if (NULL != server->listener) + { + PR_Close(server->listener); + server->listener = NULL; + } + goto exit; + } + + if (NULL != fd) + { + /* + ** Create another worker of the total number of workers is + ** less than the minimum specified or we have none left in + ** accept() AND we're not over the maximum. + ** This sort of presumes that the number allowed in accept + ** is at least as many as the minimum. Otherwise we'll keep + ** creating new threads and deleting them soon after. + */ + PRBool another = + ((pool->workers < server->workers.minimum) || + ((0 == pool->accepting) + && (pool->workers < server->workers.maximum))) ? + PR_TRUE : PR_FALSE; + pool->active += 1; + PR_Unlock(server->ml); + + if (another) (void)CreateWorker(server, pool); + + rv = ProcessRequest(fd, server); + if (PR_SUCCESS != rv) + TEST_LOG( + cltsrv_log_file, TEST_LOG_ERROR, + ("\t\tWorker(0x%p): server process ended abnormally\n", me)); + (void)PR_Close(fd); fd = NULL; + + PR_Lock(server->ml); + pool->active -= 1; + } + } + +exit: + PR_ClearInterrupt(); + PR_Unlock(server->ml); + + if (NULL != fd) + { + (void)PR_Shutdown(fd, PR_SHUTDOWN_BOTH); + (void)PR_Close(fd); + } + + TEST_LOG( + cltsrv_log_file, TEST_LOG_NOTICE, + ("\t\tWorker(0x%p): exiting [%u]\n", PR_CurrentThread(), pool->workers)); + + PR_Lock(server->ml); + pool->workers -= 1; /* undefine our existance */ + PR_REMOVE_AND_INIT_LINK(&worker->element); + PR_NotifyCondVar(pool->exiting); + PR_Unlock(server->ml); + + PR_DELETE(worker); /* destruction of the "worker" object */ + +} /* Worker */ + +static void PR_CALLBACK Server(void *arg) +{ + PRStatus rv; + PRNetAddr serverAddress; + CSServer_t *server = (CSServer_t*)arg; + PRThread *me = server->thread = PR_CurrentThread(); + + server->listener = PR_Socket(domain, SOCK_STREAM, protocol); + + rv = PR_InitializeNetAddr(PR_IpAddrAny, DEFAULT_PORT, &serverAddress); + + rv = PR_Bind(server->listener, &serverAddress); + TEST_ASSERT(PR_SUCCESS == rv); + + rv = PR_Listen(server->listener, server->backlog); + TEST_ASSERT(PR_SUCCESS == rv); + + server->started = PR_IntervalNow(); + TimeOfDayMessage("Server started at", me); + + PR_Lock(server->ml); + server->state = cs_run; + PR_NotifyCondVar(server->stateChange); + PR_Unlock(server->ml); + + /* + ** Create the first worker (actually, a thread that accepts + ** connections and then processes the work load as needed). + ** From this point on, additional worker threads are created + ** as they are needed by existing worker threads. + */ + rv = CreateWorker(server, &server->pool); + TEST_ASSERT(PR_SUCCESS == rv); + + /* + ** From here on this thread is merely hanging around as the contact + ** point for the main test driver. It's just waiting for the driver + ** to declare the test complete. + */ + TEST_LOG( + cltsrv_log_file, TEST_LOG_VERBOSE, + ("\tServer(0x%p): waiting for state change\n", me)); + + PR_Lock(server->ml); + while ((cs_run == server->state) && !Aborted(rv)) + { + rv = PR_WaitCondVar(server->stateChange, PR_INTERVAL_NO_TIMEOUT); + } + PR_Unlock(server->ml); + PR_ClearInterrupt(); + + TEST_LOG( + cltsrv_log_file, TEST_LOG_INFO, + ("\tServer(0x%p): shutting down workers\n", me)); + + /* + ** Get all the worker threads to exit. They know how to + ** clean up after themselves, so this is just a matter of + ** waiting for clorine in the pool to take effect. During + ** this stage we're ignoring interrupts. + */ + server->workers.minimum = server->workers.maximum = 0; + + PR_Lock(server->ml); + while (!PR_CLIST_IS_EMPTY(&server->list)) + { + PRCList *head = PR_LIST_HEAD(&server->list); + CSWorker_t *worker = (CSWorker_t*)head; + TEST_LOG( + cltsrv_log_file, TEST_LOG_VERBOSE, + ("\tServer(0x%p): interrupting worker(0x%p)\n", me, worker)); + rv = PR_Interrupt(worker->thread); + TEST_ASSERT(PR_SUCCESS == rv); + PR_REMOVE_AND_INIT_LINK(head); + } + + while (server->pool.workers > 0) + { + TEST_LOG( + cltsrv_log_file, TEST_LOG_NOTICE, + ("\tServer(0x%p): waiting for %u workers to exit\n", + me, server->pool.workers)); + (void)PR_WaitCondVar(server->pool.exiting, PR_INTERVAL_NO_TIMEOUT); + } + + server->state = cs_exit; + PR_NotifyCondVar(server->stateChange); + PR_Unlock(server->ml); + + TEST_LOG( + cltsrv_log_file, TEST_LOG_ALWAYS, + ("\tServer(0x%p): stopped after %u operations and %u bytes\n", + me, server->operations, server->bytesTransferred)); + + if (NULL != server->listener) PR_Close(server->listener); + server->stopped = PR_IntervalNow(); + +} /* Server */ + +static void WaitForCompletion(PRIntn execution) +{ + while (execution > 0) + { + PRIntn dally = (execution > 30) ? 30 : execution; + PR_Sleep(PR_SecondsToInterval(dally)); + if (pthread_stats) PT_FPrintStats(debug_out, "\nPThread Statistics\n"); + execution -= dally; + } +} /* WaitForCompletion */ + +static void Help(void) +{ + PR_fprintf(debug_out, "cltsrv test program usage:\n"); + PR_fprintf(debug_out, "\t-a <n> threads allowed in accept (5)\n"); + PR_fprintf(debug_out, "\t-b <n> backlock for listen (5)\n"); + PR_fprintf(debug_out, "\t-c <threads> number of clients to create (1)\n"); + PR_fprintf(debug_out, "\t-w <threads> minimal number of server threads (1)\n"); + PR_fprintf(debug_out, "\t-W <threads> maximum number of server threads (1)\n"); + PR_fprintf(debug_out, "\t-e <seconds> duration of the test in seconds (10)\n"); + PR_fprintf(debug_out, "\t-s <string> dsn name of server (localhost)\n"); + PR_fprintf(debug_out, "\t-G use GLOBAL threads (LOCAL)\n"); + PR_fprintf(debug_out, "\t-T <string> thread provider ('n' | 'p' | 'w')(n)\n"); + PR_fprintf(debug_out, "\t-X use XTP as transport (TCP)\n"); +#ifdef _PR_INET6 + PR_fprintf(debug_out, "\t-6 Use IPv6 (IPv4)\n"); +#endif /* _PR_INET6 */ + PR_fprintf(debug_out, "\t-v verbosity (accumulative) (0)\n"); + PR_fprintf(debug_out, "\t-p pthread statistics (FALSE)\n"); + PR_fprintf(debug_out, "\t-d debug mode (FALSE)\n"); + PR_fprintf(debug_out, "\t-h this message\n"); +} /* Help */ + +static Verbosity IncrementVerbosity(void) +{ + PRIntn verboge = (PRIntn)verbosity + 1; + return (Verbosity)verboge; +} /* IncrementVerbosity */ + +PRIntn main(PRIntn argc, char** argv) +{ + PRUintn index; + PRBool boolean; + CSClient_t *client; + PRStatus rv, joinStatus; + CSServer_t *server = NULL; + + PRUintn backlog = DEFAULT_BACKLOG; + PRUintn clients = DEFAULT_CLIENTS; + const char *serverName = DEFAULT_SERVER; + PRBool serverIsLocal = PR_TRUE; + PRUintn accepting = ALLOWED_IN_ACCEPT; + PRUintn workersMin = DEFAULT_WORKERS_MIN; + PRUintn workersMax = DEFAULT_WORKERS_MAX; + PRIntn execution = DEFAULT_EXECUTION_TIME; + + /* + * -G use global threads + * -a <n> threads allowed in accept + * -b <n> backlock for listen + * -c <threads> number of clients to create + * -w <threads> minimal number of server threads + * -W <threads> maximum number of server threads + * -e <seconds> duration of the test in seconds + * -s <string> dsn name of server (implies no server here) + * -v verbosity + */ + + PLOptStatus os; + PLOptState *opt = PL_CreateOptState(argc, argv, "GX6b:a:c:w:W:e:s:T:vdhp"); + + debug_out = PR_GetSpecialFD(PR_StandardError); + + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) + { + if (PL_OPT_BAD == os) continue; + switch (opt->option) + { + case 'G': /* use global threads */ + thread_scope = PR_GLOBAL_THREAD; + break; + case 'X': /* use XTP as transport */ + protocol = 36; + break; +#ifdef _PR_INET6 + case '6': /* Use IPv6 */ + domain = AF_INET6; + PR_SetIPv6Enable(PR_TRUE); + break; +#endif /* _PR_INET6 */ + case 'a': /* the value for accepting */ + accepting = atoi(opt->value); + break; + case 'b': /* the value for backlock */ + backlog = atoi(opt->value); + break; + case 'T': /* the thread provider */ + if ('n' == *opt->value) thread_provider = thread_nspr; + else if ('p' == *opt->value) thread_provider = thread_pthread; + else if ('w' == *opt->value) thread_provider = thread_win32; + else {Help(); return 2; } + break; + case 'c': /* number of client threads */ + clients = atoi(opt->value); + break; + case 'w': /* minimum server worker threads */ + workersMin = atoi(opt->value); + break; + case 'W': /* maximum server worker threads */ + workersMax = atoi(opt->value); + break; + case 'e': /* program execution time in seconds */ + execution = atoi(opt->value); + break; + case 's': /* server's address */ + serverName = opt->value; + break; + case 'v': /* verbosity */ + verbosity = IncrementVerbosity(); + break; + case 'd': /* debug mode */ + debug_mode = PR_TRUE; + break; + case 'p': /* pthread mode */ + pthread_stats = PR_TRUE; + break; + case 'h': + default: + Help(); + return 2; + } + } + PL_DestroyOptState(opt); + + if (0 != PL_strcmp(serverName, DEFAULT_SERVER)) serverIsLocal = PR_FALSE; + if (0 == execution) execution = DEFAULT_EXECUTION_TIME; + if (0 == workersMax) workersMax = DEFAULT_WORKERS_MAX; + if (0 == workersMin) workersMin = DEFAULT_WORKERS_MIN; + if (0 == accepting) accepting = ALLOWED_IN_ACCEPT; + if (0 == backlog) backlog = DEFAULT_BACKLOG; + + if (workersMin > accepting) accepting = workersMin; + + PR_STDIO_INIT(); + TimeOfDayMessage("Client/Server started at", PR_CurrentThread()); + + cltsrv_log_file = PR_NewLogModule("cltsrv_log"); + MY_ASSERT(NULL != cltsrv_log_file); + boolean = PR_SetLogFile("cltsrv.log"); + MY_ASSERT(boolean); + +#ifdef XP_MAC + debug_mode = PR_TRUE; +#endif + + if (serverIsLocal) + { + /* Establish the server */ + TEST_LOG( + cltsrv_log_file, TEST_LOG_INFO, + ("main(0x%p): starting server\n", PR_CurrentThread())); + + server = PR_NEWZAP(CSServer_t); + PR_INIT_CLIST(&server->list); + server->state = cs_init; + server->ml = PR_NewLock(); + server->backlog = backlog; + server->port = DEFAULT_PORT; + server->workers.minimum = workersMin; + server->workers.maximum = workersMax; + server->workers.accepting = accepting; + server->stateChange = PR_NewCondVar(server->ml); + server->pool.exiting = PR_NewCondVar(server->ml); + server->pool.acceptComplete = PR_NewCondVar(server->ml); + + TEST_LOG( + cltsrv_log_file, TEST_LOG_NOTICE, + ("main(0x%p): creating server thread\n", PR_CurrentThread())); + + rv = NewThread( + Server, server, PR_PRIORITY_HIGH, PR_JOINABLE_THREAD); + TEST_ASSERT(PR_SUCCESS == rv); + + TEST_LOG( + cltsrv_log_file, TEST_LOG_VERBOSE, + ("main(0x%p): waiting for server init\n", PR_CurrentThread())); + + PR_Lock(server->ml); + while (server->state == cs_init) + PR_WaitCondVar(server->stateChange, PR_INTERVAL_NO_TIMEOUT); + PR_Unlock(server->ml); + + TEST_LOG( + cltsrv_log_file, TEST_LOG_VERBOSE, + ("main(0x%p): server init complete (port #%d)\n", + PR_CurrentThread(), server->port)); + } + + if (clients != 0) + { + /* Create all of the clients */ + PRHostEnt host; + char buffer[BUFFER_SIZE]; + client = (CSClient_t*)PR_CALLOC(clients * sizeof(CSClient_t)); + + TEST_LOG( + cltsrv_log_file, TEST_LOG_VERBOSE, + ("main(0x%p): creating %d client threads\n", + PR_CurrentThread(), clients)); + + if (!serverIsLocal) + { + rv = PR_GetHostByName(serverName, buffer, BUFFER_SIZE, &host); + if (PR_SUCCESS != rv) + { + PL_FPrintError(PR_STDERR, "PR_GetHostByName"); + return 2; + } + } + + for (index = 0; index < clients; ++index) + { + client[index].state = cs_init; + client[index].ml = PR_NewLock(); + if (serverIsLocal) + { + (void)PR_InitializeNetAddr( + PR_IpAddrLoopback, DEFAULT_PORT, + &client[index].serverAddress); + } + else + { + (void)PR_EnumerateHostEnt( + 0, &host, DEFAULT_PORT, &client[index].serverAddress); + } + client[index].stateChange = PR_NewCondVar(client[index].ml); + TEST_LOG( + cltsrv_log_file, TEST_LOG_INFO, + ("main(0x%p): creating client threads\n", PR_CurrentThread())); + rv = NewThread( + Client, &client[index], PR_PRIORITY_NORMAL, PR_JOINABLE_THREAD); + TEST_ASSERT(PR_SUCCESS == rv); + PR_Lock(client[index].ml); + while (cs_init == client[index].state) + PR_WaitCondVar(client[index].stateChange, PR_INTERVAL_NO_TIMEOUT); + PR_Unlock(client[index].ml); + } + } + + /* Then just let them go at it for a bit */ + TEST_LOG( + cltsrv_log_file, TEST_LOG_ALWAYS, + ("main(0x%p): waiting for execution interval (%d seconds)\n", + PR_CurrentThread(), execution)); + + WaitForCompletion(execution); + + TimeOfDayMessage("Shutting down", PR_CurrentThread()); + + if (clients != 0) + { + for (index = 0; index < clients; ++index) + { + TEST_LOG(cltsrv_log_file, TEST_LOG_STATUS, + ("main(0x%p): notifying client(0x%p) to stop\n", + PR_CurrentThread(), client[index].thread)); + + PR_Lock(client[index].ml); + if (cs_run == client[index].state) + { + client[index].state = cs_stop; + PR_Interrupt(client[index].thread); + while (cs_stop == client[index].state) + PR_WaitCondVar( + client[index].stateChange, PR_INTERVAL_NO_TIMEOUT); + } + PR_Unlock(client[index].ml); + + TEST_LOG(cltsrv_log_file, TEST_LOG_VERBOSE, + ("main(0x%p): joining client(0x%p)\n", + PR_CurrentThread(), client[index].thread)); + + joinStatus = JoinThread(client[index].thread); + TEST_ASSERT(PR_SUCCESS == joinStatus); + PR_DestroyCondVar(client[index].stateChange); + PR_DestroyLock(client[index].ml); + } + PR_DELETE(client); + } + + if (NULL != server) + { + /* All clients joined - retrieve the server */ + TEST_LOG( + cltsrv_log_file, TEST_LOG_NOTICE, + ("main(0x%p): notifying server(0x%p) to stop\n", + PR_CurrentThread(), server->thread)); + + PR_Lock(server->ml); + server->state = cs_stop; + PR_Interrupt(server->thread); + while (cs_exit != server->state) + PR_WaitCondVar(server->stateChange, PR_INTERVAL_NO_TIMEOUT); + PR_Unlock(server->ml); + + TEST_LOG( + cltsrv_log_file, TEST_LOG_NOTICE, + ("main(0x%p): joining server(0x%p)\n", + PR_CurrentThread(), server->thread)); + joinStatus = JoinThread(server->thread); + TEST_ASSERT(PR_SUCCESS == joinStatus); + + PR_DestroyCondVar(server->stateChange); + PR_DestroyCondVar(server->pool.exiting); + PR_DestroyCondVar(server->pool.acceptComplete); + PR_DestroyLock(server->ml); + PR_DELETE(server); + } + + TEST_LOG( + cltsrv_log_file, TEST_LOG_ALWAYS, + ("main(0x%p): test complete\n", PR_CurrentThread())); + + PT_FPrintStats(debug_out, "\nPThread Statistics\n"); + + TimeOfDayMessage("Test exiting at", PR_CurrentThread()); + return 0; +} /* main */ + +/* cltsrv.c */ diff --git a/pr/tests/sel_spd.c b/pr/tests/sel_spd.c index f4ce1483..b0033567 100644 --- a/pr/tests/sel_spd.c +++ b/pr/tests/sel_spd.c @@ -51,6 +51,9 @@ typedef struct timer_slot_t { unsigned long requests; } timer_slot_t; +static long _iterations = 5; +static long _client_data = 8192; + #if defined(XP_MAC) /* * Mac does not scale well specially the requirement for thread stack @@ -58,22 +61,18 @@ typedef struct timer_slot_t { * memory and not be able to allocate thread stack or client/server data * buffer. */ +static long _server_data = (8*1024); static long _threads_max = 10, _threads = 10; -static long _iterations = 50; -static long _client_data = 8192; -static long _server_data = 8192; #else -static long _threads_max = 100, _threads = 100; -static long _iterations = 1000; -static long _client_data = 8192; static long _server_data = (128*1024); +static long _threads_max = 100, _threads = 100; #endif -static long _thread_exit_count; +static int verbose=0; static PRMonitor *exit_cv; +static long _thread_exit_count; static timer_slot_t *timer_data; static PRThreadScope scope1, scope2; -static int verbose=0; void tally_results(int); diff --git a/pr/tests/socket.c b/pr/tests/socket.c index 33ce32bb..770d5f71 100644 --- a/pr/tests/socket.c +++ b/pr/tests/socket.c @@ -373,7 +373,7 @@ UDP_Server(void *arg) PRFileDesc *sockfd; buffer *in_buf; PRNetAddr netaddr; - PRInt32 bytes, i, rv; + PRInt32 bytes, i, rv = 0; bytes = sp->datalen; @@ -1046,7 +1046,6 @@ TransmitFile_Client(void *arg) fprintf(stderr, "prsocket_test: TransmitFile_Client ERROR - large file data corruption\n"); failed_already=1; - return; } #endif PR_DELETE(small_buf); @@ -1518,8 +1517,8 @@ done: PR_DELETE(buf); } #ifdef XP_UNIX - munmap(small_file_addr, SMALL_FILE_SIZE); - munmap(large_file_addr, LARGE_FILE_SIZE); + munmap((char*)small_file_addr, SMALL_FILE_SIZE); + munmap((char*)large_file_addr, LARGE_FILE_SIZE); #endif PR_Close(small_file_fd); PR_Close(large_file_fd); diff --git a/pr/tests/stack.c b/pr/tests/stack.c new file mode 100644 index 00000000..d48e3ddb --- /dev/null +++ b/pr/tests/stack.c @@ -0,0 +1,266 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "NPL"); you may not use this file except in + * compliance with the NPL. You may obtain a copy of the NPL at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the NPL is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL + * for the specific language governing rights and limitations under the + * NPL. + * + * The Initial Developer of this code under the NPL is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All Rights + * Reserved. + */ + + +/* + * + * Test atomic stack operations + * + * Two stacks are created and threads add data items (each containing + * one of the first n integers) to the first stack, remove data items + * from the first stack and add them to the second stack. The primordial + * thread compares the sum of the first n integers to the sum of the + * integers in the data items in the second stack. The test succeeds if + * they are equal. + */ + +#include "nspr.h" +#include "plgetopt.h" + +typedef struct _DataRecord { + PRInt32 data; + PRStackElem link; +} DataRecord; + +#define RECORD_LINK_PTR(lp) ((DataRecord*) ((char*) (lp) - offsetof(DataRecord,link))) + +#define MAX_THREAD_CNT 100 +#define DEFAULT_THREAD_CNT 4 +#define DEFAULT_DATA_CNT 4 +/* + * sum of the first n numbers using the formula n*(n+1)/2 + */ +#define SUM_OF_NUMBERS(n) ((n & 1) ? (((n + 1)/2) * n) : ((n/2) * (n+1))) + +typedef struct stack_data { + PRStack *list1; + PRStack *list2; + PRInt32 initial_data_value; + PRInt32 data_cnt; +} stack_data; + +static void stackop(void *arg); + +static int _debug_on; + +PRFileDesc *output; +PRFileDesc *errhandle; + +PRIntn main(PRIntn argc, char **argv) +{ + PRInt32 rv, cnt, sum; + DataRecord *Item; + PRStack *list1, *list2; + PRStackElem *node; + PRStatus rc; + + PRInt32 thread_cnt = DEFAULT_THREAD_CNT; + PRInt32 data_cnt = DEFAULT_DATA_CNT; + PRThread **threads; + stack_data *thread_args; + + PLOptStatus os; + PLOptState *opt = PL_CreateOptState(argc, argv, "dt:c:"); + + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) + { + if (PL_OPT_BAD == os) continue; + switch (opt->option) + { + case 'd': /* debug mode */ + _debug_on = 1; + break; + case 't': /* thread count */ + thread_cnt = atoi(opt->value); + break; + case 'c': /* data count */ + data_cnt = atoi(opt->value); + break; + default: + break; + } + } + PL_DestroyOptState(opt); + + PR_SetConcurrency(4); + + output = PR_GetSpecialFD(PR_StandardOutput); + errhandle = PR_GetSpecialFD(PR_StandardError); + list1 = PR_CreateStack("Stack_1"); + if (list1 == NULL) { + PR_fprintf(errhandle, "PR_CreateStack failed - error %d\n", + PR_GetError()); + return 1; + } + + list2 = PR_CreateStack("Stack_2"); + if (list2 == NULL) { + PR_fprintf(errhandle, "PR_CreateStack failed - error %d\n", + PR_GetError()); + return 1; + } + + + threads = (PRThread**) PR_CALLOC(sizeof(PRThread*) * thread_cnt); + thread_args = (stack_data *) PR_CALLOC(sizeof(stack_data) * thread_cnt); + + if (_debug_on) + PR_fprintf(output,"%s: thread_cnt = %d data_cnt = %d\n", argv[0], + thread_cnt, data_cnt); + for(cnt = 0; cnt < thread_cnt; cnt++) { + PRThreadScope scope; + + thread_args[cnt].list1 = list1; + thread_args[cnt].list2 = list2; + thread_args[cnt].data_cnt = data_cnt; + thread_args[cnt].initial_data_value = 1 + cnt * data_cnt; + + if (cnt & 1) + scope = PR_GLOBAL_THREAD; + else + scope = PR_LOCAL_THREAD; + + + threads[cnt] = PR_CreateThread(PR_USER_THREAD, + stackop, &thread_args[cnt], + PR_PRIORITY_NORMAL, + scope, + PR_JOINABLE_THREAD, + 0); + if (threads[cnt] == NULL) { + PR_fprintf(errhandle, "PR_CreateThread failed - error %d\n", + PR_GetError()); + PR_ProcessExit(2); + } + if (_debug_on) + PR_fprintf(output,"%s: created thread = 0x%x\n", argv[0], + threads[cnt]); + } + + for(cnt = 0; cnt < thread_cnt; cnt++) { + rc = PR_JoinThread(threads[cnt]); + PR_ASSERT(rc == PR_SUCCESS); + } + + node = PR_StackPop(list1); + /* + * list1 should be empty + */ + if (node != NULL) { + PR_fprintf(errhandle, "Error - Stack 1 not empty\n"); + PR_ASSERT(node == NULL); + PR_ProcessExit(4); + } + + cnt = data_cnt * thread_cnt; + sum = 0; + while (cnt-- > 0) { + node = PR_StackPop(list2); + /* + * There should be at least 'cnt' number of records + */ + if (node == NULL) { + PR_fprintf(errhandle, "Error - PR_StackPop returned NULL\n"); + PR_ProcessExit(3); + } + Item = RECORD_LINK_PTR(node); + sum += Item->data; + } + node = PR_StackPop(list2); + /* + * there should be exactly 'cnt' number of records + */ + if (node != NULL) { + PR_fprintf(errhandle, "Error - Stack 2 not empty\n"); + PR_ASSERT(node == NULL); + PR_ProcessExit(4); + } + PR_DELETE(threads); + PR_DELETE(thread_args); + + PR_DestroyStack(list1); + PR_DestroyStack(list2); + + if (sum == SUM_OF_NUMBERS(data_cnt * thread_cnt)) { + PR_fprintf(output, "%s successful\n", argv[0]); + PR_fprintf(output, "\t\tsum = 0x%x, expected = 0x%x\n", sum, + SUM_OF_NUMBERS(thread_cnt * data_cnt)); + return 0; + } else { + PR_fprintf(output, "%s failed: sum = 0x%x, expected = 0x%x\n", + argv[0], sum, + SUM_OF_NUMBERS(data_cnt * thread_cnt)); + return 2; + } +} + +static void stackop(void *thread_arg) +{ + PRInt32 val, cnt, index; + DataRecord *Items, *Item; + PRStack *list1, *list2; + PRStackElem *node; + stack_data *arg = (stack_data *) thread_arg; + + val = arg->initial_data_value; + cnt = arg->data_cnt; + list1 = arg->list1; + list2 = arg->list2; + + /* + * allocate memory for the data records + */ + Items = (DataRecord *) PR_CALLOC(sizeof(DataRecord) * cnt); + PR_ASSERT(Items != NULL); + index = 0; + + if (_debug_on) + PR_fprintf(output, + "Thread[0x%x] init_val = %d cnt = %d data1 = 0x%x datan = 0x%x\n", + PR_GetCurrentThread(), val, cnt, &Items[0], &Items[cnt-1]); + + + /* + * add the data records to list1 + */ + while (cnt-- > 0) { + Items[index].data = val++; + PR_StackPush(list1, &Items[index].link); + index++; + } + + /* + * remove the data records from list1 and add them to list2 + */ + cnt = arg->data_cnt; + while (cnt-- > 0) { + node = PR_StackPop(list1); + if (node == NULL) { + PR_fprintf(errhandle, "Error - PR_StackPop returned NULL\n"); + PR_ASSERT(node != NULL); + PR_ProcessExit(3); + } + PR_StackPush(list2, node); + } + if (_debug_on) + PR_fprintf(output, + "Thread[0x%x] init_val = %d cnt = %d exiting\n", + PR_GetCurrentThread(), val, cnt); + +} + diff --git a/pr/tests/switch.c b/pr/tests/switch.c index 131260fc..878d7d15 100644 --- a/pr/tests/switch.c +++ b/pr/tests/switch.c @@ -63,14 +63,14 @@ static void Help(void) debug_out = PR_STDOUT; PR_fprintf( - debug_out, "Usage: >./switch [-d] [-c n] [-t n] [-T n] [-G]\n"); + debug_out, "Usage: >./switch [-c n] [-t n] [-d] [-v] [-G] [-C n]\n"); PR_fprintf( debug_out, "-c n\tloops at thread level (default: %d)\n", DEFAULT_LOOPS); PR_fprintf( debug_out, "-t n\tnumber of threads (default: %d)\n", DEFAULT_THREADS); PR_fprintf(debug_out, "-d\tturn on debugging output (default: FALSE)\n"); PR_fprintf(debug_out, "-v\tturn on verbose output (default: FALSE)\n"); - PR_fprintf(debug_out, "-G n\tglobal threads only (default: FALSE)\n"); + PR_fprintf(debug_out, "-G\tglobal threads only (default: FALSE)\n"); PR_fprintf(debug_out, "-C n\tconcurrency setting (default: 1)\n"); } /* Help */ diff --git a/pr/tests/testfile.c b/pr/tests/testfile.c index d492a0ff..2f5129d4 100644 --- a/pr/tests/testfile.c +++ b/pr/tests/testfile.c @@ -44,7 +44,6 @@ extern void SetupMacPrintfLog(char *logFile); PRLock *lock; PRMonitor *mon; -PRMonitor *mon2; PRInt32 count; int thread_count; @@ -108,11 +107,12 @@ int offset, len; } DPRINTF(("Write out_buf[0] = 0x%x\n",(*((int *) buf)))); PR_Close(fd_file); + PR_DELETE(fp); - PR_EnterMonitor(mon2); + PR_EnterMonitor(mon); --thread_count; - PR_Notify(mon2); - PR_ExitMonitor(mon2); + PR_Notify(mon); + PR_ExitMonitor(mon); } static void PR_CALLBACK File_Read(void *arg) @@ -143,11 +143,12 @@ int offset, len; } DPRINTF(("Read in_buf[0] = 0x%x\n",(*((int *) buf)))); PR_Close(fd_file); + PR_DELETE(fp); - PR_EnterMonitor(mon2); + PR_EnterMonitor(mon); --thread_count; - PR_Notify(mon2); - PR_ExitMonitor(mon2); + PR_Notify(mon); + PR_ExitMonitor(mon); } @@ -295,6 +296,7 @@ static PRInt32 PR_CALLBACK FileTest(void) PRDir *fd_dir; int i, offset, len; PRThread *t; +PRThreadScope scope; File_Rdwr_Param *fparamp; /* @@ -334,12 +336,7 @@ File_Rdwr_Param *fparamp; */ offset = 0; len = CHUNK_SIZE; - mon2 = PR_NewMonitor(); - if (mon2 == NULL) { - printf("testfile: PR_NewMonitor failed\n"); - return -1; - } - PR_EnterMonitor(mon2); + PR_EnterMonitor(mon); for (i = 0; i < NUM_RDWR_THREADS; i++) { fparamp = PR_NEW(File_Rdwr_Param); if (fparamp == NULL) { @@ -356,27 +353,24 @@ File_Rdwr_Param *fparamp; * Create LOCAL and GLOBAL Threads, alternately */ if (i % 1) - t = PR_CreateThread(PR_USER_THREAD, - File_Write, (void *)fparamp, - PR_PRIORITY_NORMAL, - PR_GLOBAL_THREAD, - PR_UNJOINABLE_THREAD, - 0); + scope = PR_GLOBAL_THREAD; else - t = PR_CreateThread(PR_USER_THREAD, - File_Write, (void *)fparamp, - PR_PRIORITY_NORMAL, - PR_LOCAL_THREAD, - PR_UNJOINABLE_THREAD, - 0); + scope = PR_LOCAL_THREAD; + + t = PR_CreateThread(PR_USER_THREAD, + File_Write, (void *)fparamp, + PR_PRIORITY_NORMAL, + scope, + PR_UNJOINABLE_THREAD, + 0); offset += len; } thread_count = i; /* Wait for writer threads to exit */ while (thread_count) { - PR_Wait(mon2, PR_INTERVAL_NO_TIMEOUT); + PR_Wait(mon, PR_INTERVAL_NO_TIMEOUT); } - PR_ExitMonitor(mon2); + PR_ExitMonitor(mon); /* @@ -384,7 +378,7 @@ File_Rdwr_Param *fparamp; */ offset = 0; len = CHUNK_SIZE; - PR_EnterMonitor(mon2); + PR_EnterMonitor(mon); for (i = 0; i < NUM_RDWR_THREADS; i++) { fparamp = PR_NEW(File_Rdwr_Param); if (fparamp == NULL) { @@ -400,19 +394,16 @@ File_Rdwr_Param *fparamp; * Create LOCAL and GLOBAL Threads, alternately */ if (i % 1) - t = PR_CreateThread(PR_USER_THREAD, - File_Read, (void *)fparamp, - PR_PRIORITY_NORMAL, - PR_LOCAL_THREAD, - PR_UNJOINABLE_THREAD, - 0); + scope = PR_LOCAL_THREAD; else - t = PR_CreateThread(PR_USER_THREAD, - File_Read, (void *)fparamp, - PR_PRIORITY_NORMAL, - PR_GLOBAL_THREAD, - PR_UNJOINABLE_THREAD, - 0); + scope = PR_GLOBAL_THREAD; + + t = PR_CreateThread(PR_USER_THREAD, + File_Read, (void *)fparamp, + PR_PRIORITY_NORMAL, + scope, + PR_UNJOINABLE_THREAD, + 0); offset += len; if ((offset + len) > BUF_DATA_SIZE) break; @@ -421,9 +412,9 @@ File_Rdwr_Param *fparamp; /* Wait for reader threads to exit */ while (thread_count) { - PR_Wait(mon2, PR_INTERVAL_NO_TIMEOUT); + PR_Wait(mon, PR_INTERVAL_NO_TIMEOUT); } - PR_ExitMonitor(mon2); + PR_ExitMonitor(mon); if (memcmp(in_buf->data, out_buf->data, offset) != 0) { printf("File Test failed: file data corrupted\n"); @@ -759,7 +750,7 @@ HANDLE hfile; * Test file and directory NSPR APIs */ -void main(int argc, char **argv) +int main(int argc, char **argv) { #ifdef XP_UNIX int opt; @@ -784,7 +775,11 @@ void main(int argc, char **argv) SetupMacPrintfLog("testfile.log"); #endif - mon2 = PR_NewMonitor(); + mon = PR_NewMonitor(); + if (mon == NULL) { + printf("testfile: PR_NewMonitor failed\n"); + exit(2); + } if (FileTest() < 0) { printf("File Test failed\n"); @@ -798,5 +793,7 @@ void main(int argc, char **argv) } printf("Dir Test passed\n"); + PR_DestroyMonitor(mon); PR_Cleanup(); + return 0; } diff --git a/pr/tests/tpd.c b/pr/tests/tpd.c index 9afce87c..786948e4 100644 --- a/pr/tests/tpd.c +++ b/pr/tests/tpd.c @@ -21,6 +21,7 @@ ** Description: Exercising the thread private data bailywick. */ +#include "prmem.h" #include "prinit.h" #include "prlog.h" #include "prprf.h" @@ -42,18 +43,20 @@ static PRBool should = PR_TRUE; static PRBool did = PR_TRUE; static PRFileDesc *fout = NULL; -static void PrintProgress(void) +static void PrintProgress(PRIntn line) { + failed = failed || (should && !did); + failed = failed || (!should && did); if (debug > 0) { #if defined(WIN16) printf( - "Destructor should %s have been called and was%s\n", - ((should) ? "" : " NOT"), ((did) ? "" : " NOT")); + "@ line %d destructor should%s have been called and was%s\n", + line, ((should) ? "" : " NOT"), ((did) ? "" : " NOT")); #else PR_fprintf( - fout, "Destructor should %s have been called and was%s\n", - ((should) ? "" : " NOT"), ((did) ? "" : " NOT")); + fout, "@ line %d destructor should%s have been called and was%s\n", + line, ((should) ? "" : " NOT"), ((did) ? "" : " NOT")); #endif } } /* PrintProgress */ @@ -70,10 +73,15 @@ static void MyAssert(const char *expr, const char *file, PRIntn line) static void PR_CALLBACK Destructor(void *data) { + MY_ASSERT(NULL != data); if (should) did = PR_TRUE; else failed = PR_TRUE; - MY_ASSERT(NULL != data); - if (debug > 0) MyAssert((const char*)data, __FILE__, __LINE__); + /* + * We don't actually free the storage since it's actually allocated + * on the stack. Normally, this would not be the case and this is + * the opportunity to free whatever. + PR_Free(data); + */ } /* Destructor */ static void PR_CALLBACK Thread(void *null) @@ -91,24 +99,24 @@ static void PR_CALLBACK Thread(void *null) pd = PR_GetThreadPrivate(key[keys]); MY_ASSERT(NULL == pd); } - PrintProgress(); + PrintProgress(__LINE__); did = should = PR_FALSE; for (keys = 0; keys < 4; ++keys) { - rv = PR_SetThreadPrivate(keys, key_string[keys]); + rv = PR_SetThreadPrivate(key[keys], key_string[keys]); MY_ASSERT(PR_SUCCESS == rv); } - PrintProgress(); + PrintProgress(__LINE__); #if !defined(DEBUG) did = should = PR_FALSE; for (keys = 4; keys < 8; ++keys) { - rv = PR_SetThreadPrivate(keys, key_string[keys]); + rv = PR_SetThreadPrivate(key[keys], key_string[keys]); MY_ASSERT(PR_FAILURE == rv); } - PrintProgress(); + PrintProgress(__LINE__); #endif did = PR_FALSE; should = PR_TRUE; @@ -117,7 +125,7 @@ static void PR_CALLBACK Thread(void *null) rv = PR_SetThreadPrivate(key[keys], key_string[keys]); MY_ASSERT(PR_SUCCESS == rv); } - PrintProgress(); + PrintProgress(__LINE__); did = PR_FALSE; should = PR_TRUE; for (keys = 0; keys < 4; ++keys) @@ -125,7 +133,7 @@ static void PR_CALLBACK Thread(void *null) rv = PR_SetThreadPrivate(key[keys], NULL); MY_ASSERT(PR_SUCCESS == rv); } - PrintProgress(); + PrintProgress(__LINE__); did = should = PR_FALSE; for (keys = 0; keys < 4; ++keys) @@ -133,7 +141,7 @@ static void PR_CALLBACK Thread(void *null) rv = PR_SetThreadPrivate(key[keys], NULL); MY_ASSERT(PR_SUCCESS == rv); } - PrintProgress(); + PrintProgress(__LINE__); did = should = PR_FALSE; for (keys = 8; keys < 127; ++keys) @@ -141,7 +149,7 @@ static void PR_CALLBACK Thread(void *null) rv = PR_SetThreadPrivate(key[keys], "EXTENSION"); MY_ASSERT(PR_SUCCESS == rv); } - PrintProgress(); + PrintProgress(__LINE__); did = PR_FALSE; should = PR_TRUE; for (keys = 8; keys < 127; ++keys) @@ -149,7 +157,7 @@ static void PR_CALLBACK Thread(void *null) rv = PR_SetThreadPrivate(key[keys], NULL); MY_ASSERT(PR_SUCCESS == rv); } - PrintProgress(); + PrintProgress(__LINE__); did = should = PR_FALSE; for (keys = 8; keys < 127; ++keys) @@ -157,6 +165,17 @@ static void PR_CALLBACK Thread(void *null) rv = PR_SetThreadPrivate(key[keys], NULL); MY_ASSERT(PR_SUCCESS == rv); } + + /* put in keys and leave them there for thread exit */ + did = should = PR_FALSE; + for (keys = 0; keys < 4; ++keys) + { + rv = PR_SetThreadPrivate(key[keys], key_string[keys]); + MY_ASSERT(PR_SUCCESS == rv); + } + PrintProgress(__LINE__); + did = PR_FALSE; should = PR_TRUE; + } /* Thread */ static PRIntn PR_CALLBACK Tpd(PRIntn argc, char **argv) @@ -177,7 +196,7 @@ static PRIntn PR_CALLBACK Tpd(PRIntn argc, char **argv) rv = PR_NewThreadPrivateIndex(&key[keys], Destructor); MY_ASSERT(PR_SUCCESS == rv); } - PrintProgress(); + PrintProgress(__LINE__); did = should = PR_FALSE; for (keys = 0; keys < 8; ++keys) @@ -185,24 +204,24 @@ static PRIntn PR_CALLBACK Tpd(PRIntn argc, char **argv) pd = PR_GetThreadPrivate(key[keys]); MY_ASSERT(NULL == pd); } - PrintProgress(); + PrintProgress(__LINE__); did = should = PR_FALSE; for (keys = 0; keys < 4; ++keys) { - rv = PR_SetThreadPrivate(keys, key_string[keys]); + rv = PR_SetThreadPrivate(key[keys], key_string[keys]); MY_ASSERT(PR_SUCCESS == rv); } - PrintProgress(); + PrintProgress(__LINE__); #if !defined(DEBUG) did = should = PR_FALSE; for (keys = 4; keys < 8; ++keys) { - rv = PR_SetThreadPrivate(keys, key_string[keys]); + rv = PR_SetThreadPrivate(key[keys], key_string[keys]); MY_ASSERT(PR_FAILURE == rv); } - PrintProgress(); + PrintProgress(__LINE__); #endif did = PR_FALSE; should = PR_TRUE; @@ -211,7 +230,7 @@ static PRIntn PR_CALLBACK Tpd(PRIntn argc, char **argv) rv = PR_SetThreadPrivate(key[keys], key_string[keys]); MY_ASSERT(PR_SUCCESS == rv); } - PrintProgress(); + PrintProgress(__LINE__); did = PR_FALSE; should = PR_TRUE; for (keys = 0; keys < 4; ++keys) @@ -219,7 +238,7 @@ static PRIntn PR_CALLBACK Tpd(PRIntn argc, char **argv) rv = PR_SetThreadPrivate(key[keys], NULL); MY_ASSERT(PR_SUCCESS == rv); } - PrintProgress(); + PrintProgress(__LINE__); did = should = PR_FALSE; for (keys = 0; keys < 4; ++keys) @@ -227,7 +246,7 @@ static PRIntn PR_CALLBACK Tpd(PRIntn argc, char **argv) rv = PR_SetThreadPrivate(key[keys], NULL); MY_ASSERT(PR_SUCCESS == rv); } - PrintProgress(); + PrintProgress(__LINE__); did = should = PR_FALSE; for (keys = 8; keys < 127; ++keys) @@ -237,7 +256,7 @@ static PRIntn PR_CALLBACK Tpd(PRIntn argc, char **argv) rv = PR_SetThreadPrivate(key[keys], "EXTENSION"); MY_ASSERT(PR_SUCCESS == rv); } - PrintProgress(); + PrintProgress(__LINE__); did = PR_FALSE; should = PR_TRUE; for (keys = 8; keys < 127; ++keys) @@ -245,7 +264,7 @@ static PRIntn PR_CALLBACK Tpd(PRIntn argc, char **argv) rv = PR_SetThreadPrivate(key[keys], NULL); MY_ASSERT(PR_SUCCESS == rv); } - PrintProgress(); + PrintProgress(__LINE__); did = should = PR_FALSE; for (keys = 8; keys < 127; ++keys) @@ -260,6 +279,8 @@ static PRIntn PR_CALLBACK Tpd(PRIntn argc, char **argv) (void)PR_JoinThread(thread); + PrintProgress(__LINE__); + #if defined(WIN16) printf( "%s\n",((PR_TRUE == failed) ? "FAILED" : "PASSED")); diff --git a/pr/tests/udpsrv.c b/pr/tests/udpsrv.c index 4e9292d1..d45421d4 100644 --- a/pr/tests/udpsrv.c +++ b/pr/tests/udpsrv.c @@ -64,13 +64,6 @@ #include <string.h> #include <errno.h> -/* --- manifest constants --- */ -#ifdef XP_MAC -#define fprintf(a,b) printf(b) -#include "prlog.h" -#define printf PR_LogPrint -#endif - #ifdef XP_PC #define mode_t int #endif @@ -93,12 +86,13 @@ static PRIntn _debug_on = 0; static PRBool passed = PR_TRUE; static PRUint32 cltBytesRead = 0; static PRUint32 srvBytesRead = 0; +static PRFileDesc *output = NULL; /* --- static function declarations --- */ -#define DPRINTF(arg) if (_debug_on) printf(arg) +#define DPRINTF(arg) if (_debug_on) PR_fprintf(output, arg) + - /******************************************************************* ** ListNetAddr() -- Display the Net Address on stdout ** @@ -122,7 +116,7 @@ void ListNetAddr( char *msg, PRNetAddr *na ) DPRINTF( mbuf ); #endif } /* --- end ListNetAddr() --- */ - + /******************************************************************** ** UDP_Server() -- Test a UDP server application ** @@ -155,7 +149,9 @@ static void PR_CALLBACK UDP_Server( void *arg ) if ( svrSock == NULL ) { passed = PR_FALSE; - if (debug_mode) printf("udpsrv: UDP_Server(): PR_NewUDPSocket() returned NULL\n" ); + if (debug_mode) + PR_fprintf(output, + "udpsrv: UDP_Server(): PR_NewUDPSocket() returned NULL\n" ); return; } @@ -174,7 +170,7 @@ static void PR_CALLBACK UDP_Server( void *arg ) { if ( PR_GetError() == PR_ADDRESS_IN_USE_ERROR ) { - if (debug_mode) printf("udpsrv: UDP_Server(): \ + if (debug_mode) PR_fprintf(output, "udpsrv: UDP_Server(): \ PR_Bind(): reports: PR_ADDRESS_IN_USE_ERROR\n"); PR_Sleep( PR_MillisecondsToInterval( 2000 )); continue; @@ -182,7 +178,7 @@ static void PR_CALLBACK UDP_Server( void *arg ) else { passed = PR_FALSE; - if (debug_mode) printf( "udpsrv: UDP_Server(): \ + if (debug_mode) PR_fprintf(output, "udpsrv: UDP_Server(): \ PR_Bind(): failed: %ld with error: %ld\n", rv, PR_GetError() ); PR_Close( svrSock ); @@ -202,8 +198,10 @@ static void PR_CALLBACK UDP_Server( void *arg ) if ( rv == -1 ) { passed = PR_FALSE; - if (debug_mode) printf( "udpsrv: UDP_Server(): PR_RecvFrom(): failed with error: %ld\n", - PR_GetError() ); + if (debug_mode) + PR_fprintf(output, + "udpsrv: UDP_Server(): PR_RecvFrom(): failed with error: %ld\n", + PR_GetError() ); PR_Close( svrSock ); return; } @@ -223,8 +221,10 @@ static void PR_CALLBACK UDP_Server( void *arg ) if ( rv == -1 ) { passed = PR_FALSE; - if (debug_mode) printf( "udpsrv: UDP_Server(): PR_SendTo(): failed with error: %ld\n", - PR_GetError() ); + if (debug_mode) + PR_fprintf(output, + "udpsrv: UDP_Server(): PR_SendTo(): failed with error: %ld\n", + PR_GetError() ); PR_Close( svrSock ); return; } @@ -237,14 +237,16 @@ static void PR_CALLBACK UDP_Server( void *arg ) if ( rv != PR_SUCCESS ) { passed = PR_FALSE; - if (debug_mode) printf("udpsrv: UDP_Server(): PR_Close(): failed to close socket\n" ); + if (debug_mode) + PR_fprintf(output, + "udpsrv: UDP_Server(): PR_Close(): failed to close socket\n" ); return; } DPRINTF("udpsrv: UDP_Server(): Normal end\n" ); } /* --- end UDP_Server() --- */ - + static char cltBuf[UDP_BUF_SIZE]; static char cltBufin[UDP_BUF_SIZE]; /******************************************************************** @@ -284,7 +286,9 @@ static void PR_CALLBACK UDP_Client( void *arg ) if ( cltSock == NULL ) { passed = PR_FALSE; - if (debug_mode) printf("udpsrv: UDP_Client(): PR_NewUDPSocket() returned NULL\n" ); + if (debug_mode) + PR_fprintf(output, + "udpsrv: UDP_Client(): PR_NewUDPSocket() returned NULL\n" ); return; } @@ -307,14 +311,18 @@ static void PR_CALLBACK UDP_Client( void *arg ) { if ( PR_GetError() == PR_ADDRESS_IN_USE_ERROR ) { - if (debug_mode) printf("udpsrv: UDP_Client(): PR_Bind(): reports: PR_ADDRESS_IN_USE_ERROR\n"); + if (debug_mode) + PR_fprintf(output, + "udpsrv: UDP_Client(): PR_Bind(): reports: PR_ADDRESS_IN_USE_ERROR\n"); PR_Sleep( PR_MillisecondsToInterval( 2000 )); continue; } else { passed = PR_FALSE; - if (debug_mode) printf( "udpsrv: UDP_Client(): PR_Bind(): failed: %ld with error: %ld\n", + if (debug_mode) + PR_fprintf(output, + "udpsrv: UDP_Client(): PR_Bind(): failed: %ld with error: %ld\n", rv, PR_GetError() ); PR_Close( cltSock ); return; @@ -352,7 +360,7 @@ static void PR_CALLBACK UDP_Client( void *arg ) writeThisMany -= numBytes; { char mbuf[256]; - sprintf( mbuf, "udpsrv: UDP_Client(): write_this_many: %ld, numbytes: %ld\n", + sprintf( mbuf, "udpsrv: UDP_Client(): write_this_many: %d, numbytes: %d\n", writeThisMany, numBytes ); DPRINTF( mbuf ); } @@ -362,7 +370,9 @@ static void PR_CALLBACK UDP_Client( void *arg ) if ( rv == -1 ) { passed = PR_FALSE; - if (debug_mode) printf( "udpsrv: UDP_Client(): PR_SendTo(): failed with error: %ld\n", + if (debug_mode) + PR_fprintf(output, + "udpsrv: UDP_Client(): PR_SendTo(): failed with error: %ld\n", PR_GetError() ); PR_Close( cltSock ); return; @@ -376,7 +386,8 @@ static void PR_CALLBACK UDP_Client( void *arg ) if ( rv == -1 ) { passed = PR_FALSE; - if (debug_mode) printf( "udpsrv: UDP_Client(): PR_RecvFrom(): failed with error: %ld\n", + if (debug_mode) PR_fprintf(output, + "udpsrv: UDP_Client(): PR_RecvFrom(): failed with error: %ld\n", PR_GetError() ); PR_Close( cltSock ); return; @@ -393,12 +404,13 @@ static void PR_CALLBACK UDP_Client( void *arg ) if ( endOfInput && i == 0 && cltBufin[0] == 'E' ) continue; passed = PR_FALSE; - if (debug_mode) printf("udpsrv: UDP_Client(): return data mismatch\n" ); + if (debug_mode) PR_fprintf(output, + "udpsrv: UDP_Client(): return data mismatch\n" ); PR_Close( cltSock ); return; } } - if (debug_mode) printf("."); + if (debug_mode) PR_fprintf(output, "."); } /* --- Close the socket --- */ @@ -407,12 +419,13 @@ static void PR_CALLBACK UDP_Client( void *arg ) if ( rv != PR_SUCCESS ) { passed = PR_FALSE; - if (debug_mode) printf("udpsrv: UDP_Client(): PR_Close(): failed to close socket\n" ); + if (debug_mode) PR_fprintf(output, + "udpsrv: UDP_Client(): PR_Close(): failed to close socket\n" ); return; } DPRINTF("udpsrv: UDP_Client(): ending\n" ); } /* --- end UDP_Client() --- */ - + /******************************************************************** ** main() -- udpsrv ** @@ -461,6 +474,7 @@ int main(int argc, char **argv) PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0); PR_STDIO_INIT(); + output = PR_STDERR; #ifdef XP_MAC SetupMacPrintfLog("udpsrv.log"); @@ -481,7 +495,7 @@ int main(int argc, char **argv) 0 ); if ( srv == NULL ) { - if (debug_mode) printf( "udpsrv: Cannot create server thread\n" ); + if (debug_mode) PR_fprintf(output, "udpsrv: Cannot create server thread\n" ); passed = PR_FALSE; } @@ -504,7 +518,7 @@ int main(int argc, char **argv) 0 ); if ( clt == NULL ) { - if (debug_mode) printf( "udpsrv: Cannot create server thread\n" ); + if (debug_mode) PR_fprintf(output, "udpsrv: Cannot create server thread\n" ); passed = PR_FALSE; } @@ -518,7 +532,7 @@ int main(int argc, char **argv) /* ** Evaluate test results */ - if (debug_mode) printf( "\n\nudpsrv: main(): cltBytesRead(%ld), \ + if (debug_mode) PR_fprintf(output, "\n\nudpsrv: main(): cltBytesRead(%ld), \ srvBytesRead(%ld), expected(%ld)\n", cltBytesRead, srvBytesRead, UDP_AMOUNT_TO_WRITE ); if ( cltBytesRead != srvBytesRead || cltBytesRead != UDP_AMOUNT_TO_WRITE ) diff --git a/pr/tests/version.c b/pr/tests/version.c new file mode 100644 index 00000000..c5c3013d --- /dev/null +++ b/pr/tests/version.c @@ -0,0 +1,101 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "NPL"); you may not use this file except in + * compliance with the NPL. You may obtain a copy of the NPL at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the NPL is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL + * for the specific language governing rights and limitations under the + * NPL. + * + * The Initial Developer of this code under the NPL is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All Rights + * Reserved. + */ + +#include "prio.h" +#include "prprf.h" +#include "prlink.h" +#include "prvrsion.h" + +#include "plerror.h" +#include "plgetopt.h" + +PRIntn main(PRIntn argc, char **argv) +{ + PRIntn rv = 1; + PLOptStatus os; + PRIntn verbosity = 0; + PRLibrary *runtime = NULL; + const char *library_name = NULL; + const PRVersionDescription *version_info; + PLOptState *opt = PL_CreateOptState(argc, argv, "d"); + + PRFileDesc *err = PR_GetSpecialFD(PR_StandardError); + + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) + { + if (PL_OPT_BAD == os) continue; + switch (opt->option) + { + case 0: /* fully qualified library name */ + library_name = opt->value; + break; + case 'd': /* verbodity */ + verbosity += 1; + break; + default: + PR_fprintf(err, "Usage: version [-d] {fully qualified library name}\n"); + return 2; /* but not a lot else */ + } + } + PL_DestroyOptState(opt); + + if (NULL == library_name) + PR_fprintf(err, "Usage: version [-d] {fully qualified library name}\n"); + else + { + runtime = PR_LoadLibrary(library_name); + if (NULL == runtime) PL_FPrintError(err, "PR_LoadLibrary"); + else + { + versionEntryPointType versionPoint = (versionEntryPointType) + PR_FindSymbol(runtime, "libVersionPoint"); + if (NULL == versionPoint) PL_FPrintError(err, "PR_FindSymbol"); + else + { + char buffer[100]; + PRExplodedTime exploded; + version_info = versionPoint(); + (void)PR_fprintf(err, "Runtime library version information\n"); + PR_ExplodeTime( + version_info->buildTime, PR_GMTParameters, &exploded); + (void)PR_FormatTime( + buffer, sizeof(buffer), "%d %b %Y %H:%M:%S", &exploded); + (void)PR_fprintf(err, " Build time: %s GMT\n", buffer); + (void)PR_fprintf( + err, " Build time: %s\n", version_info->buildTimeString); + (void)PR_fprintf( + err, " %s V%u.%u.%u (%s%s%s)\n", + version_info->description, + version_info->vMajor, + version_info->vMinor, + version_info->vPatch, + (version_info->beta ? " beta " : ""), + (version_info->debug ? " debug " : ""), + (version_info->special ? " special" : "")); + (void)PR_fprintf(err, " filename: %s\n", version_info->filename); + (void)PR_fprintf(err, " security: %s\n", version_info->security); + (void)PR_fprintf(err, " copyright: %s\n", version_info->copyright); + (void)PR_fprintf(err, " comment: %s\n", version_info->comment); + rv = 0; + } + } + } + return rv; +} + +/* version.c */ |